]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | # Status: being ported by Steven Watanabe |
2 | # Base revision: 47077 | |
3 | # | |
4 | # Copyright (C) Andre Hentz 2003. Permission to copy, use, modify, sell and | |
5 | # distribute this software is granted provided this copyright notice appears in | |
6 | # all copies. This software is provided "as is" without express or implied | |
7 | # warranty, and with no claim as to its suitability for any purpose. | |
8 | # | |
9 | # Copyright (c) 2006 Rene Rivera. | |
10 | # | |
11 | # Copyright (c) 2008 Steven Watanabe | |
12 | # | |
13 | # Use, modification and distribution is subject to the Boost Software | |
1e59de90 TL |
14 | # License Version 1.0. (See accompanying file LICENSE.txt or |
15 | # https://www.bfgroup.xyz/b2/LICENSE.txt) | |
7c673cae FG |
16 | |
17 | ##import type ; | |
18 | ##import generators ; | |
19 | ##import feature ; | |
20 | ##import errors ; | |
21 | ##import scanner ; | |
22 | ##import toolset : flags ; | |
23 | ||
24 | import os.path | |
25 | import re | |
26 | ||
27 | import bjam | |
28 | ||
29 | from b2.build import type, toolset, generators, scanner, feature | |
30 | from b2.exceptions import AlreadyDefined | |
31 | from b2.tools import builtin | |
32 | from b2.util import regex | |
33 | from b2.build.toolset import flags | |
34 | from b2.manager import get_manager | |
35 | from b2.util import utility | |
36 | ||
37 | __debug = None | |
38 | ||
39 | def debug(): | |
40 | global __debug | |
41 | if __debug is None: | |
42 | __debug = "--debug-configuration" in bjam.variable("ARGV") | |
43 | return __debug | |
44 | ||
45 | type.register('RC', ['rc']) | |
46 | ||
47 | def init(): | |
48 | pass | |
49 | ||
50 | def configure (command = None, condition = None, options = None): | |
51 | """ | |
52 | Configures a new resource compilation command specific to a condition, | |
53 | usually a toolset selection condition. The possible options are: | |
54 | ||
55 | * <rc-type>(rc|windres) - Indicates the type of options the command | |
56 | accepts. | |
57 | ||
58 | Even though the arguments are all optional, only when a command, condition, | |
59 | and at minimum the rc-type option are given will the command be configured. | |
60 | This is so that callers don't have to check auto-configuration values | |
61 | before calling this. And still get the functionality of build failures when | |
62 | the resource compiler can't be found. | |
63 | """ | |
64 | rc_type = feature.get_values('<rc-type>', options) | |
65 | if rc_type: | |
66 | assert(len(rc_type) == 1) | |
67 | rc_type = rc_type[0] | |
68 | ||
69 | if command and condition and rc_type: | |
70 | flags('rc.compile.resource', '.RC', condition, command) | |
71 | flags('rc.compile.resource', '.RC_TYPE', condition, [rc_type.lower()]) | |
72 | flags('rc.compile.resource', 'DEFINES', [], ['<define>']) | |
73 | flags('rc.compile.resource', 'INCLUDES', [], ['<include>']) | |
74 | if debug(): | |
75 | print 'notice: using rc compiler ::', condition, '::', command | |
76 | ||
77 | engine = get_manager().engine() | |
78 | ||
79 | class RCAction: | |
80 | """Class representing bjam action defined from Python. | |
81 | The function must register the action to execute.""" | |
82 | ||
83 | def __init__(self, action_name, function): | |
84 | self.action_name = action_name | |
85 | self.function = function | |
86 | ||
87 | def __call__(self, targets, sources, property_set): | |
88 | if self.function: | |
89 | self.function(targets, sources, property_set) | |
90 | ||
91 | # FIXME: What is the proper way to dispatch actions? | |
92 | def rc_register_action(action_name, function = None): | |
93 | global engine | |
94 | if action_name in engine.actions: | |
95 | raise AlreadyDefined("Bjam action %s is already defined" % action_name) | |
96 | engine.actions[action_name] = RCAction(action_name, function) | |
97 | ||
98 | def rc_compile_resource(targets, sources, properties): | |
99 | rc_type = bjam.call('get-target-variable', targets, '.RC_TYPE') | |
100 | rc_type = rc_type[0] if rc_type else '' | |
101 | global engine | |
102 | engine.set_update_action('rc.compile.resource.' + rc_type, targets, sources, properties) | |
103 | ||
104 | rc_register_action('rc.compile.resource', rc_compile_resource) | |
105 | ||
106 | ||
107 | engine.register_action( | |
108 | 'rc.compile.resource.rc', | |
109 | '"$(.RC)" -l 0x409 "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -fo "$(<)" "$(>)"') | |
110 | ||
111 | engine.register_action( | |
112 | 'rc.compile.resource.windres', | |
113 | '"$(.RC)" "-U$(UNDEFS)" "-D$(DEFINES)" -I"$(>:D)" -I"$(<:D)" -I"$(INCLUDES)" -o "$(<)" -i "$(>)"') | |
114 | ||
115 | # FIXME: this was originally declared quietly | |
116 | engine.register_action( | |
117 | 'compile.resource.null', | |
118 | 'as /dev/null -o "$(<)"') | |
119 | ||
120 | # Since it's a common practice to write | |
121 | # exe hello : hello.cpp hello.rc | |
122 | # we change the name of object created from RC file, to | |
123 | # avoid conflict with hello.cpp. | |
124 | # The reason we generate OBJ and not RES, is that gcc does not | |
125 | # seem to like RES files, but works OK with OBJ. | |
126 | # See http://article.gmane.org/gmane.comp.lib.boost.build/5643/ | |
127 | # | |
128 | # Using 'register-c-compiler' adds the build directory to INCLUDES | |
129 | # FIXME: switch to generators | |
130 | builtin.register_c_compiler('rc.compile.resource', ['RC'], ['OBJ(%_res)'], []) | |
131 | ||
132 | __angle_include_re = "#include[ ]*<([^<]+)>" | |
133 | ||
134 | # Register scanner for resources | |
135 | class ResScanner(scanner.Scanner): | |
136 | ||
137 | def __init__(self, includes): | |
138 | scanner.__init__ ; | |
139 | self.includes = includes | |
140 | ||
141 | def pattern(self): | |
142 | return "(([^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)" +\ | |
143 | "[ ]+([^ \"]+|\"[^\"]+\"))|(#include[ ]*(<[^<]+>|\"[^\"]+\")))" ; | |
144 | ||
145 | def process(self, target, matches, binding): | |
146 | binding = binding[0] | |
147 | angle = regex.transform(matches, "#include[ ]*<([^<]+)>") | |
148 | quoted = regex.transform(matches, "#include[ ]*\"([^\"]+)\"") | |
149 | res = regex.transform(matches, | |
150 | "[^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)" +\ | |
151 | "[ ]+(([^ \"]+)|\"([^\"]+)\")", [3, 4]) | |
152 | ||
153 | # Icons and other includes may referenced as | |
154 | # | |
155 | # IDR_MAINFRAME ICON "res\\icon.ico" | |
156 | # | |
157 | # so we have to replace double backslashes to single ones. | |
158 | res = [ re.sub(r'\\\\', '/', match) for match in res if match is not None ] | |
159 | ||
160 | # CONSIDER: the new scoping rule seem to defeat "on target" variables. | |
161 | g = bjam.call('get-target-variable', target, 'HDRGRIST')[0] | |
162 | b = os.path.normpath(os.path.dirname(binding)) | |
163 | ||
164 | # Attach binding of including file to included targets. | |
165 | # When target is directly created from virtual target | |
166 | # this extra information is unnecessary. But in other | |
167 | # cases, it allows to distinguish between two headers of the | |
168 | # same name included from different places. | |
169 | # We don't need this extra information for angle includes, | |
170 | # since they should not depend on including file (we can't | |
171 | # get literal "." in include path). | |
172 | g2 = g + "#" + b | |
173 | ||
174 | g = "<" + g + ">" | |
175 | g2 = "<" + g2 + ">" | |
176 | angle = [g + x for x in angle] | |
177 | quoted = [g2 + x for x in quoted] | |
178 | res = [g2 + x for x in res] | |
179 | ||
180 | all = angle + quoted | |
181 | ||
182 | bjam.call('mark-included', target, all) | |
183 | ||
184 | engine = get_manager().engine() | |
185 | ||
186 | engine.add_dependency(target, res) | |
187 | bjam.call('NOCARE', all + res) | |
188 | engine.set_target_variable(angle, 'SEARCH', [utility.get_value(inc) for inc in self.includes]) | |
189 | engine.set_target_variable(quoted, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes]) | |
190 | engine.set_target_variable(res, 'SEARCH', [b + utility.get_value(inc) for inc in self.includes]) | |
191 | ||
192 | # Just propagate current scanner to includes, in a hope | |
193 | # that includes do not change scanners. | |
194 | get_manager().scanners().propagate(self, angle + quoted) | |
195 | ||
196 | scanner.register(ResScanner, 'include') | |
197 | type.set_scanner('RC', ResScanner) |