1# Status: ported
2# Base revision: 64432.
3# Copyright 2005-2010 Vladimir Prus.
4# Distributed under the Boost Software License, Version 1.0. (See
5# accompanying file LICENSE_1_0.txt or copy at
6# http://www.boost.org/LICENSE_1_0.txt)
7
8# Defines main target 'cast', used to change type for target. For example, in Qt
9# library one wants two kinds of CPP files -- those that just compiled and those
10# that are passed via the MOC tool.
11#
12# This is done with:
13#
14#    exe main : main.cpp [ cast _ moccable-cpp : widget.cpp ] ;
15#
16# Boost.Build will assign target type CPP to both main.cpp and widget.cpp. Then,
17# the cast rule will change target type of widget.cpp to MOCCABLE-CPP, and Qt
18# support will run the MOC tool as part of the build process.
19#
20# At the moment, the 'cast' rule only works for non-derived (source) targets.
21#
22# TODO: The following comment is unclear or incorrect. Clean it up.
23# > Another solution would be to add a separate main target 'moc-them' that
24# > would moc all the passed sources, no matter what their type is, but I prefer
25# > cast, as defining a new target type + generator for that type is somewhat
26# > simpler than defining a main target rule.
27
28from b2.build import targets, virtual_target, property_set, type as type_
29
30from b2.manager import get_manager
31from b2.util import bjam_signature, is_iterable_typed
32
33
34class CastTargetClass(targets.TypedTarget):
35
36    def construct(self, name, source_targets, ps):
37        assert isinstance(name, basestring)
38        assert is_iterable_typed(source_targets, virtual_target.VirtualTarget)
39        assert isinstance(ps, property_set.PropertySet)
40
41        result = []
42        for s in source_targets:
43            if not isinstance(s, virtual_target.FileTarget):
44                get_manager().errors()("Source to the 'cast' metatager is not a file")
45
46            if s.action():
47                get_manager().errors()("Only non-derived targets allowed as sources for 'cast'.")
48
49
50            r = s.clone_with_different_type(self.type())
51            result.append(get_manager().virtual_targets().register(r))
52
53        return property_set.empty(), result
54
55
56@bjam_signature((["name", "type"], ["sources", "*"], ["requirements", "*"],
57                 ["default_build", "*"], ["usage_requirements", "*"]))
58def cast(name, type, sources, requirements, default_build, usage_requirements):
59
60    from b2.manager import get_manager
61    t = get_manager().targets()
62
63    project = get_manager().projects().current()
64
65    real_type = type_.type_from_rule_name(type)
66    if not real_type:
67        real_type = type
68    return t.main_target_alternative(
69        CastTargetClass(name, project, real_type,
70                        t.main_target_sources(sources, name),
71                        t.main_target_requirements(requirements, project),
72                        t.main_target_default_build(default_build, project),
73                        t.main_target_usage_requirements(usage_requirements, project)))
74
75
76get_manager().projects().add_rule("cast", cast)
77