]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #!/usr/bin/python |
2 | ||
3 | # Copyright (C) 2012. Jurko Gospodnetic | |
4 | # Distributed under the Boost Software License, Version 1.0. | |
5 | # (See accompanying file LICENSE_1_0.txt or copy at | |
6 | # http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | # Tests Boost Build's project-id handling. | |
9 | ||
10 | import BoostBuild | |
11 | import sys | |
12 | ||
13 | ||
14 | def test_assigning_project_ids(): | |
15 | t = BoostBuild.Tester(pass_toolset=False) | |
16 | t.write("jamroot.jam", """\ | |
17 | import assert ; | |
18 | import modules ; | |
19 | import notfile ; | |
20 | import project ; | |
21 | ||
22 | rule assert-project-id ( id ? : module-name ? ) | |
23 | { | |
24 | module-name ?= [ CALLER_MODULE ] ; | |
25 | assert.result $(id) : project.attribute $(module-name) id ; | |
26 | } | |
27 | ||
28 | # Project rule modifies the main project id. | |
29 | assert-project-id ; # Initial project id is empty | |
30 | project foo ; assert-project-id /foo ; | |
31 | project ; assert-project-id /foo ; | |
32 | project foo ; assert-project-id /foo ; | |
33 | project bar ; assert-project-id /bar ; | |
34 | project /foo ; assert-project-id /foo ; | |
35 | project "" ; assert-project-id /foo ; | |
36 | ||
37 | # Calling the use-project rule does not modify the project's main id. | |
38 | use-project id1 : a ; | |
39 | # We need to load the 'a' Jamfile module manually as the use-project rule will | |
40 | # only schedule the load to be done after the current module load finishes. | |
41 | a-module = [ project.load a ] ; | |
42 | assert-project-id : $(a-module) ; | |
43 | use-project id2 : a ; | |
44 | assert-project-id : $(a-module) ; | |
45 | modules.call-in $(a-module) : project baz ; | |
46 | assert-project-id /baz : $(a-module) ; | |
47 | use-project id3 : a ; | |
48 | assert-project-id /baz : $(a-module) ; | |
49 | ||
50 | # Make sure the project id still holds after all the scheduled use-project loads | |
51 | # complete. We do this by scheduling the assert for the Jam action scheduling | |
52 | # phase. | |
53 | notfile x : @assert-a-rule ; | |
54 | rule assert-a-rule ( target : : properties * ) | |
55 | { | |
56 | assert-project-id /baz : $(a-module) ; | |
57 | } | |
58 | """) | |
59 | t.write("a/jamfile.jam", """\ | |
60 | # Initial project id for this module is empty. | |
61 | assert-project-id ; | |
62 | """) | |
63 | t.run_build_system() | |
64 | t.cleanup() | |
65 | ||
66 | ||
67 | def test_using_project_ids_in_target_references(): | |
68 | t = BoostBuild.Tester() | |
69 | __write_appender(t, "appender.jam") | |
70 | t.write("jamroot.jam", """\ | |
71 | import type ; | |
72 | type.register AAA : _a ; | |
73 | type.register BBB : _b ; | |
74 | ||
75 | import appender ; | |
76 | appender.register aaa-to-bbb : AAA : BBB ; | |
77 | ||
78 | use-project id1 : a ; | |
79 | use-project /id2 : a ; | |
80 | ||
81 | bbb b1 : /id1//target ; | |
82 | bbb b2 : /id2//target ; | |
83 | bbb b3 : /id3//target ; | |
84 | bbb b4 : a//target ; | |
85 | bbb b5 : /project-a1//target ; | |
86 | bbb b6 : /project-a2//target ; | |
87 | bbb b7 : /project-a3//target ; | |
88 | ||
89 | use-project id3 : a ; | |
90 | """) | |
91 | t.write("a/source._a", "") | |
92 | t.write("a/jamfile.jam", """\ | |
93 | project project-a1 ; | |
94 | project /project-a2 ; | |
95 | import alias ; | |
96 | alias target : source._a ; | |
97 | project /project-a3 ; | |
98 | """) | |
99 | ||
100 | t.run_build_system() | |
101 | t.expect_addition("bin/$toolset/b%d._b" % x for x in range(1, 8)) | |
102 | t.expect_nothing_more() | |
103 | ||
104 | t.cleanup() | |
105 | ||
106 | ||
107 | def test_repeated_ids_for_different_projects(): | |
108 | t = BoostBuild.Tester() | |
109 | ||
110 | t.write("a/jamfile.jam", "") | |
111 | t.write("jamroot.jam", "project foo ; use-project foo : a ;") | |
112 | t.run_build_system(status=1) | |
113 | t.expect_output_lines("""\ | |
114 | error: Attempt to redeclare already registered project id '/foo'. | |
115 | error: Original project: | |
116 | error: Name: Jamfile<*> | |
117 | error: Module: Jamfile<*> | |
118 | error: Main id: /foo | |
119 | error: File: jamroot.jam | |
120 | error: Location: . | |
121 | error: New project: | |
122 | error: Module: Jamfile<*> | |
123 | error: File: a*jamfile.jam | |
124 | error: Location: a""") | |
125 | ||
126 | t.write("jamroot.jam", "use-project foo : a ; project foo ;") | |
127 | t.run_build_system(status=1) | |
128 | t.expect_output_lines("""\ | |
129 | error: Attempt to redeclare already registered project id '/foo'. | |
130 | error: Original project: | |
131 | error: Name: Jamfile<*> | |
132 | error: Module: Jamfile<*> | |
133 | error: Main id: /foo | |
134 | error: File: jamroot.jam | |
135 | error: Location: . | |
136 | error: New project: | |
137 | error: Module: Jamfile<*> | |
138 | error: File: a*jamfile.jam | |
139 | error: Location: a""") | |
140 | ||
141 | t.write("jamroot.jam", """\ | |
142 | import modules ; | |
143 | import project ; | |
144 | modules.call-in [ project.load a ] : project foo ; | |
145 | project foo ; | |
146 | """) | |
147 | t.run_build_system(status=1) | |
148 | t.expect_output_lines("""\ | |
149 | error: at jamroot.jam:4 | |
150 | error: Attempt to redeclare already registered project id '/foo'. | |
151 | error: Original project: | |
152 | error: Name: Jamfile<*> | |
153 | error: Module: Jamfile<*> | |
154 | error: Main id: /foo | |
155 | error: File: a*jamfile.jam | |
156 | error: Location: a | |
157 | error: New project: | |
158 | error: Module: Jamfile<*> | |
159 | error: File: jamroot.jam | |
160 | error: Location: .""") | |
161 | ||
162 | t.cleanup() | |
163 | ||
164 | ||
165 | def test_repeated_ids_for_same_project(): | |
166 | t = BoostBuild.Tester() | |
167 | ||
168 | t.write("jamroot.jam", "project foo ; project foo ;") | |
169 | t.run_build_system() | |
170 | ||
171 | t.write("jamroot.jam", "project foo ; use-project foo : . ;") | |
172 | t.run_build_system() | |
173 | ||
174 | t.write("jamroot.jam", "project foo ; use-project foo : ./. ;") | |
175 | t.run_build_system() | |
176 | ||
177 | t.write("jamroot.jam", """\ | |
178 | project foo ; | |
179 | use-project foo : . ; | |
180 | use-project foo : ./aaa/.. ; | |
181 | use-project foo : ./. ; | |
182 | """) | |
183 | t.run_build_system() | |
184 | ||
185 | # On Windows we have a case-insensitive file system and we can use | |
186 | # backslashes as path separators. | |
187 | # FIXME: Make a similar test pass on Cygwin. | |
188 | if sys.platform in ['win32']: | |
189 | t.write("a/fOo bAr/b/jamfile.jam", "") | |
190 | t.write("jamroot.jam", r""" | |
191 | use-project bar : "a/foo bar/b" ; | |
192 | use-project bar : "a/foO Bar/b" ; | |
193 | use-project bar : "a/foo BAR/b/" ; | |
194 | use-project bar : "a\\.\\FOO bar\\b\\" ; | |
195 | """) | |
196 | t.run_build_system() | |
197 | t.rm("a") | |
198 | ||
199 | t.write("bar/jamfile.jam", "") | |
200 | t.write("jamroot.jam", """\ | |
201 | use-project bar : bar ; | |
202 | use-project bar : bar/ ; | |
203 | use-project bar : bar// ; | |
204 | use-project bar : bar/// ; | |
205 | use-project bar : bar//// ; | |
206 | use-project bar : bar/. ; | |
207 | use-project bar : bar/./ ; | |
208 | use-project bar : bar/////./ ; | |
209 | use-project bar : bar/../bar/xxx/.. ; | |
210 | use-project bar : bar/..///bar/xxx///////.. ; | |
211 | use-project bar : bar/./../bar/xxx/.. ; | |
212 | use-project bar : bar/.////../bar/xxx/.. ; | |
213 | use-project bar : bar/././../bar/xxx/.. ; | |
214 | use-project bar : bar/././//////////../bar/xxx/.. ; | |
215 | use-project bar : bar/.///.////../bar/xxx/.. ; | |
216 | use-project bar : bar/./././xxx/.. ; | |
217 | use-project bar : bar/xxx////.. ; | |
218 | use-project bar : bar/xxx/.. ; | |
219 | use-project bar : bar///////xxx/.. ; | |
220 | """) | |
221 | t.run_build_system() | |
222 | t.rm("bar") | |
223 | ||
224 | # On Windows we have a case-insensitive file system and we can use | |
225 | # backslashes as path separators. | |
226 | # FIXME: Make a similar test pass on Cygwin. | |
227 | if sys.platform in ['win32']: | |
228 | t.write("baR/jamfile.jam", "") | |
229 | t.write("jamroot.jam", r""" | |
230 | use-project bar : bar ; | |
231 | use-project bar : BAR ; | |
232 | use-project bar : bAr ; | |
233 | use-project bar : bAr/ ; | |
234 | use-project bar : bAr\\ ; | |
235 | use-project bar : bAr\\\\ ; | |
236 | use-project bar : bAr\\\\///// ; | |
237 | use-project bar : bAr/. ; | |
238 | use-project bar : bAr/./././ ; | |
239 | use-project bar : bAr\\.\\.\\.\\ ; | |
240 | use-project bar : bAr\\./\\/.\\.\\ ; | |
241 | use-project bar : bAr/.\\././ ; | |
242 | use-project bar : Bar ; | |
243 | use-project bar : BaR ; | |
244 | use-project bar : BaR/./../bAr/xxx/.. ; | |
245 | use-project bar : BaR/./..\\bAr\\xxx/.. ; | |
246 | use-project bar : BaR/xxx/.. ; | |
247 | use-project bar : BaR///\\\\\\//xxx/.. ; | |
248 | use-project bar : Bar\\xxx/.. ; | |
249 | use-project bar : BAR/xXx/.. ; | |
250 | use-project bar : BAR/xXx\\\\/\\/\\//\\.. ; | |
251 | """) | |
252 | t.run_build_system() | |
253 | t.rm("baR") | |
254 | ||
255 | t.cleanup() | |
256 | ||
257 | ||
258 | def test_unresolved_project_references(): | |
259 | t = BoostBuild.Tester() | |
260 | ||
261 | __write_appender(t, "appender.jam") | |
262 | t.write("a/source._a", "") | |
263 | t.write("a/jamfile.jam", "import alias ; alias target : source._a ;") | |
264 | t.write("jamroot.jam", """\ | |
265 | import type ; | |
266 | type.register AAA : _a ; | |
267 | type.register BBB : _b ; | |
268 | ||
269 | import appender ; | |
270 | appender.register aaa-to-bbb : AAA : BBB ; | |
271 | ||
272 | use-project foo : a ; | |
273 | ||
274 | bbb b1 : a//target ; | |
275 | bbb b2 : /foo//target ; | |
276 | bbb b-invalid : invalid//target ; | |
277 | bbb b-root-invalid : /invalid//target ; | |
278 | bbb b-missing-root : foo//target ; | |
279 | bbb b-invalid-target : /foo//invalid ; | |
280 | """) | |
281 | ||
282 | t.run_build_system(["b1", "b2"]) | |
b32b8144 | 283 | t.expect_addition("bin/$toolset/debug*/b%d._b" % x for x in range(1, 3)) |
7c673cae FG |
284 | t.expect_nothing_more() |
285 | ||
286 | t.run_build_system(["b-invalid"], status=1) | |
287 | t.expect_output_lines("""\ | |
288 | error: Unable to find file or target named | |
289 | error: 'invalid//target' | |
290 | error: referred to from project at | |
291 | error: '.' | |
292 | error: could not resolve project reference 'invalid'""") | |
293 | ||
294 | t.run_build_system(["b-root-invalid"], status=1) | |
295 | t.expect_output_lines("""\ | |
296 | error: Unable to find file or target named | |
297 | error: '/invalid//target' | |
298 | error: referred to from project at | |
299 | error: '.' | |
300 | error: could not resolve project reference '/invalid'""") | |
301 | ||
302 | t.run_build_system(["b-missing-root"], status=1) | |
303 | t.expect_output_lines("""\ | |
304 | error: Unable to find file or target named | |
305 | error: 'foo//target' | |
306 | error: referred to from project at | |
307 | error: '.' | |
308 | error: could not resolve project reference 'foo' - possibly missing a """ | |
309 | "leading slash ('/') character.") | |
310 | ||
311 | t.run_build_system(["b-invalid-target"], status=1) | |
312 | t.expect_output_lines("""\ | |
313 | error: Unable to find file or target named | |
314 | error: '/foo//invalid' | |
315 | error: referred to from project at | |
316 | error: '.'""") | |
317 | t.expect_output_lines("*could not resolve project reference*", False) | |
318 | ||
319 | t.cleanup() | |
320 | ||
321 | ||
322 | def __write_appender(t, name): | |
323 | t.write(name, | |
324 | r"""# Copyright 2012 Jurko Gospodnetic | |
325 | # Distributed under the Boost Software License, Version 1.0. | |
326 | # (See accompanying file LICENSE_1_0.txt or copy at | |
327 | # http://www.boost.org/LICENSE_1_0.txt) | |
328 | ||
329 | # Support for registering test generators that construct their targets by | |
330 | # simply appending their given input data, e.g. list of sources & targets. | |
331 | ||
332 | import "class" : new ; | |
333 | import generators ; | |
334 | import modules ; | |
335 | import sequence ; | |
336 | ||
337 | rule register ( id composing ? : source-types + : target-types + ) | |
338 | { | |
339 | local caller-module = [ CALLER_MODULE ] ; | |
340 | id = $(caller-module).$(id) ; | |
341 | local g = [ new generator $(id) $(composing) : $(source-types) : | |
342 | $(target-types) ] ; | |
343 | $(g).set-rule-name $(__name__).appender ; | |
344 | generators.register $(g) ; | |
345 | return $(id) ; | |
346 | } | |
347 | ||
348 | if [ modules.peek : NT ] | |
349 | { | |
350 | X = ")" ; | |
351 | ECHO_CMD = (echo. ; | |
352 | } | |
353 | else | |
354 | { | |
355 | X = \" ; | |
356 | ECHO_CMD = "echo $(X)" ; | |
357 | } | |
358 | ||
359 | local appender-runs ; | |
360 | ||
361 | # We set up separate actions for building each target in order to avoid having | |
362 | # to iterate over them in action (i.e. shell) code. We have to be extra careful | |
363 | # though to achieve the exact same effect as if doing all the work in just one | |
364 | # action. Otherwise Boost Jam might, under some circumstances, run only some of | |
365 | # our actions. To achieve this we register a series of actions for all the | |
366 | # targets (since they all have the same target list - either all or none of them | |
367 | # get run independent of which target actually needs to get built), each | |
368 | # building only a single target. Since all our actions use the same targets, we | |
369 | # can not use 'on-target' parameters to pass data to a specific action so we | |
370 | # pass them using the second 'sources' parameter which our actions then know how | |
371 | # to interpret correctly. This works well since Boost Jam does not automatically | |
372 | # add dependency relations between specified action targets & sources and so the | |
373 | # second argument, even though most often used to pass in a list of sources, can | |
374 | # actually be used for passing in any type of information. | |
375 | rule appender ( targets + : sources + : properties * ) | |
376 | { | |
377 | appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ; | |
378 | local target-index = 0 ; | |
379 | local target-count = [ sequence.length $(targets) ] ; | |
380 | local original-targets ; | |
381 | for t in $(targets) | |
382 | { | |
383 | target-index = [ CALC $(target-index) + 1 ] ; | |
384 | local appender-run = $(appender-runs) ; | |
385 | if $(targets[2])-defined | |
386 | { | |
387 | appender-run += [$(target-index)/$(target-count)] ; | |
388 | } | |
389 | append $(targets) : $(appender-run:J=" ") $(t) $(sources) ; | |
390 | } | |
391 | } | |
392 | ||
393 | actions append | |
394 | { | |
395 | $(ECHO_CMD)-------------------------------------------------$(X) | |
396 | $(ECHO_CMD)Appender run: $(>[1])$(X) | |
397 | $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])" | |
398 | $(ECHO_CMD)Target group: $(<:J=' ')$(X) | |
399 | $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])" | |
400 | $(ECHO_CMD) Target: '$(>[2])'$(X) | |
401 | $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])" | |
402 | $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X) | |
403 | $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])" | |
404 | $(ECHO_CMD)=================================================$(X) | |
405 | $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])" | |
406 | } | |
407 | """) | |
408 | ||
409 | ||
410 | test_assigning_project_ids() | |
411 | test_using_project_ids_in_target_references() | |
412 | test_repeated_ids_for_same_project() | |
413 | test_repeated_ids_for_different_projects() | |
414 | test_unresolved_project_references() |