]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/test/generators_test.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / tools / build / test / generators_test.py
1 #!/usr/bin/python
2
3 # Copyright 2002, 2003 Dave Abrahams
4 # Copyright 2002, 2003, 2004, 2005 Vladimir Prus
5 # Copyright 2012 Jurko Gospodnetic
6 # Distributed under the Boost Software License, Version 1.0.
7 # (See accompanying file LICENSE_1_0.txt or copy at
8 # http://www.boost.org/LICENSE_1_0.txt)
9
10 import BoostBuild
11 import re
12
13
14 def test_basic():
15 t = BoostBuild.Tester()
16 __write_appender(t, "appender.jam")
17 t.write("a.cpp", "")
18 t.write("b.cxx", "")
19 t.write("c.tui", "")
20 t.write("d.wd", "")
21 t.write("e.cpp", "")
22 t.write("x.l", "")
23 t.write("y.x_pro", "")
24 t.write("z.cpp", "")
25 t.write("lib/c.cpp", "int bar() { return 0; }\n")
26 t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;")
27 t.write("jamroot.jam",
28 r"""import appender ;
29
30 import "class" : new ;
31 import generators ;
32 import type ;
33
34
35 ################################################################################
36 #
37 # We use our own custom EXE, LIB & OBJ target generators as using the regular
38 # ones would force us to have to deal with different compiler/linker specific
39 # 'features' that really have nothing to do with this test. For example, IBM XL
40 # C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero
41 # exit code and thus fails our build when run with a source file using an
42 # unknown suffix like '.marked_cpp'.
43 #
44 ################################################################################
45
46 type.register MY_EXE : my_exe ;
47 type.register MY_LIB : my_lib ;
48 type.register MY_OBJ : my_obj ;
49
50 appender.register compile-c : C : MY_OBJ ;
51 appender.register compile-cpp : CPP : MY_OBJ ;
52 appender.register link-lib composing : MY_OBJ : MY_LIB ;
53 appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ;
54
55
56 ################################################################################
57 #
58 # LEX --> C
59 #
60 ################################################################################
61
62 type.register LEX : l ;
63
64 appender.register lex-to-c : LEX : C ;
65
66
67 ################################################################################
68 #
69 # /--> tUI_H --\
70 # tUI --< >--> CPP
71 # \------------/
72 #
73 ################################################################################
74
75 type.register tUI : tui ;
76 type.register tUI_H : tui_h ;
77
78 appender.register ui-to-cpp : tUI tUI_H : CPP ;
79 appender.register ui-to-h : tUI : tUI_H ;
80
81
82 ################################################################################
83 #
84 # /--> X1 --\
85 # X_PRO --< >--> CPP
86 # \--> X2 --/
87 #
88 ################################################################################
89
90 type.register X1 : x1 ;
91 type.register X2 : x2 ;
92 type.register X_PRO : x_pro ;
93
94 appender.register x1-x2-to-cpp : X1 X2 : CPP ;
95 appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ;
96
97
98 ################################################################################
99 #
100 # When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from
101 # anything else, e.g. directly from CPP.
102 #
103 ################################################################################
104
105 type.register CPP_MARKED : marked_cpp : CPP ;
106 type.register POSITIONS : positions ;
107 type.register NM.TARGET.CPP : target_cpp : CPP ;
108 type.register NM_EXE : : MY_EXE ;
109
110 appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ;
111 appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ;
112
113 class "nm::target::cpp-obj-generator" : generator
114 {
115 rule __init__ ( id )
116 {
117 generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ;
118 generator.set-rule-name appender.appender ;
119 }
120
121 rule requirements ( )
122 {
123 return <main-target-type>NM_EXE ;
124 }
125
126 rule run ( project name ? : properties * : source : multiple ? )
127 {
128 if [ $(source).type ] = CPP
129 {
130 local converted = [ generators.construct $(project) : NM.TARGET.CPP
131 : $(properties) : $(source) ] ;
132 if $(converted)
133 {
134 return [ generators.construct $(project) : MY_OBJ :
135 $(properties) : $(converted[2]) ] ;
136 }
137 }
138 }
139 }
140 generators.register [ new "nm::target::cpp-obj-generator" target-obj ] ;
141 generators.override target-obj : all ;
142
143
144 ################################################################################
145 #
146 # A more complex test case scenario with the following generators:
147 # 1. WHL --> CPP, WHL_LR0, H, H(%_symbols)
148 # 2. DLP --> CPP
149 # 3. WD --> WHL(%_parser) DLP(%_lexer)
150 # 4. A custom generator of higher priority than generators 1. & 2. that helps
151 # disambiguate between them when generating CPP files from WHL and DLP
152 # sources.
153 #
154 ################################################################################
155
156 type.register WHL : whl ;
157 type.register DLP : dlp ;
158 type.register WHL_LR0 : lr0 ;
159 type.register WD : wd ;
160
161 local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H
162 H(%_symbols) ] ;
163 local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ;
164 appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ;
165
166 class wd-to-cpp : generator
167 {
168 rule __init__ ( id : sources * : targets * )
169 {
170 generator.__init__ $(id) : $(sources) : $(targets) ;
171 }
172
173 rule run ( project name ? : property-set : source )
174 {
175 local new-sources = $(source) ;
176 if ! [ $(source).type ] in WHL DLP
177 {
178 local r1 = [ generators.construct $(project) $(name) : WHL :
179 $(property-set) : $(source) ] ;
180 local r2 = [ generators.construct $(project) $(name) : DLP :
181 $(property-set) : $(source) ] ;
182 new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ;
183 }
184
185 local result ;
186 for local i in $(new-sources)
187 {
188 local t = [ generators.construct $(project) $(name) : CPP :
189 $(property-set) : $(i) ] ;
190 result += $(t[2-]) ;
191 }
192 return $(result) ;
193 }
194 }
195 generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ;
196 generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ;
197 generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ;
198
199
200 ################################################################################
201 #
202 # Declare build targets.
203 #
204 ################################################################################
205
206 # This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp.
207 my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ;
208 my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ;
209
210 # This should cause two CPP --> MY_OBJ constructions for z.cpp.
211 my-obj obj_1 : z.cpp ;
212 my-obj obj_2 : z.cpp ;
213
214 nm-exe e : e.cpp ;
215 """)
216
217 t.run_build_system()
218 t.expect_addition("bin/" * BoostBuild.List("a.my_exe "
219 "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp "
220 "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h "
221 "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp "
222 "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe "
223 "f.my_exe obj_1.my_obj obj_2.my_obj"))
224 t.expect_addition("lib/bin/" * BoostBuild.List("c.my_obj "
225 "auxilliary.my_lib"))
226 t.expect_nothing_more()
227
228 folder = "bin"
229 t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'")
230 t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'")
231 t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'")
232
233 lines = t.stdout().splitlines()
234 source_lines = [x for x in lines if re.match("^ Sources: '", x)]
235 if not __match_count_is(source_lines, "'z.cpp'", 2):
236 BoostBuild.annotation("failure", "z.cpp must be compiled exactly "
237 "twice.")
238 t.fail_test(1)
239 if not __match_count_is(source_lines, "'a.cpp'", 1):
240 BoostBuild.annotation("failure", "a.cpp must be compiled exactly "
241 "once.")
242 t.fail_test(1)
243 t.cleanup()
244
245
246 def test_generated_target_names():
247 """
248 Test generator generated target names. Unless given explicitly, target
249 names should be determined based on their specified source names. All
250 sources for generating a target need to have matching names in order for
251 Boost Build to be able to implicitly determine the target's name.
252
253 We use the following target generation structure with differently named
254 BBX targets:
255 /---> BB1 ---\
256 AAA --<----> BB2 ---->--> CCC --(composing)--> DDD
257 \---> BB3 ---/
258
259 The extra generator at the end is needed because generating a top-level
260 CCC target directly would requires us to explicitly specify a name for it.
261 The extra generator needs to be composing in order not to explicitly
262 request a specific name for its CCC source target based on its own target
263 name.
264
265 We also check for a regression where only the first two sources were
266 checked to see if their names match. Note that we need to try out all file
267 renaming combinations as we do not know what ordering Boost Build is going
268 to use when passing in those files as generator sources.
269
270 """
271 jamfile_template = """\
272 import type ;
273 type.register AAA : _a ;
274 type.register BB1 : _b1 ;
275 type.register BB2 : _b2 ;
276 type.register BB3 : _b3 ;
277 type.register CCC : _c ;
278 type.register DDD : _d ;
279
280 import appender ;
281 appender.register aaa-to-bbX : AAA : BB1%s BB2%s BB3%s ;
282 appender.register bbX-to-ccc : BB1 BB2 BB3 : CCC ;
283 appender.register ccc-to-ddd composing : CCC : DDD ;
284
285 ddd _xxx : _xxx._a ;
286 """
287
288 t = BoostBuild.Tester()
289 __write_appender(t, "appender.jam")
290 t.write("_xxx._a", "")
291
292 def test_one(t, rename1, rename2, rename3, status):
293 def f(rename):
294 if rename: return "(%_x)"
295 return ""
296
297 jamfile = jamfile_template % (f(rename1), f(rename2), f(rename3))
298 t.write("jamroot.jam", jamfile, wait=False)
299
300 # Remove any preexisting targets left over from a previous test run
301 # so we do not have to be careful about tracking which files have been
302 # newly added and which preexisting ones have only been modified.
303 t.rm("bin")
304
305 t.run_build_system(status=status)
306
307 if status:
308 t.expect_output_lines("*.bbX-to-ccc: source targets have "
309 "different names: cannot determine target name")
310 else:
311 def suffix(rename):
312 if rename: return "_x"
313 return ""
314 name = "bin/_xxx"
315 e = t.expect_addition
316 e("%s%s._b1" % (name, suffix(rename1)))
317 e("%s%s._b2" % (name, suffix(rename2)))
318 e("%s%s._b3" % (name, suffix(rename3)))
319 e("%s%s._c" % (name, suffix(rename1 and rename2 and rename3)))
320 e("%s._d" % name)
321 t.expect_nothing_more()
322
323 test_one(t, False, False, False, status=0)
324 test_one(t, True , False, False, status=1)
325 test_one(t, False, True , False, status=1)
326 test_one(t, False, False, True , status=1)
327 test_one(t, True , True , False, status=1)
328 test_one(t, True , False, True , status=1)
329 test_one(t, False, True , True , status=1)
330 test_one(t, True , True , True , status=0)
331 t.cleanup()
332
333
334 def __match_count_is(lines, pattern, expected):
335 count = 0
336 for x in lines:
337 if re.search(pattern, x):
338 count += 1
339 if count > expected:
340 return False
341 return count == expected
342
343
344 def __write_appender(t, name):
345 t.write(name,
346 r"""# Copyright 2012 Jurko Gospodnetic
347 # Distributed under the Boost Software License, Version 1.0.
348 # (See accompanying file LICENSE_1_0.txt or copy at
349 # http://www.boost.org/LICENSE_1_0.txt)
350
351 # Support for registering test generators that construct their targets by
352 # simply appending their given input data, e.g. list of sources & targets.
353
354 import "class" : new ;
355 import generators ;
356 import modules ;
357 import sequence ;
358
359 rule register ( id composing ? : source-types + : target-types + )
360 {
361 local caller-module = [ CALLER_MODULE ] ;
362 id = $(caller-module).$(id) ;
363 local g = [ new generator $(id) $(composing) : $(source-types) :
364 $(target-types) ] ;
365 $(g).set-rule-name $(__name__).appender ;
366 generators.register $(g) ;
367 return $(id) ;
368 }
369
370 if [ modules.peek : NT ]
371 {
372 X = ")" ;
373 ECHO_CMD = (echo. ;
374 }
375 else
376 {
377 X = \" ;
378 ECHO_CMD = "echo $(X)" ;
379 }
380
381 local appender-runs ;
382
383 # We set up separate actions for building each target in order to avoid having
384 # to iterate over them in action (i.e. shell) code. We have to be extra careful
385 # though to achieve the exact same effect as if doing all the work in just one
386 # action. Otherwise Boost Jam might, under some circumstances, run only some of
387 # our actions. To achieve this we register a series of actions for all the
388 # targets (since they all have the same target list - either all or none of them
389 # get run independent of which target actually needs to get built), each
390 # building only a single target. Since all our actions use the same targets, we
391 # can not use 'on-target' parameters to pass data to a specific action so we
392 # pass them using the second 'sources' parameter which our actions then know how
393 # to interpret correctly. This works well since Boost Jam does not automatically
394 # add dependency relations between specified action targets & sources and so the
395 # second argument, even though most often used to pass in a list of sources, can
396 # actually be used for passing in any type of information.
397 rule appender ( targets + : sources + : properties * )
398 {
399 appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ;
400 local target-index = 0 ;
401 local target-count = [ sequence.length $(targets) ] ;
402 local original-targets ;
403 for t in $(targets)
404 {
405 target-index = [ CALC $(target-index) + 1 ] ;
406 local appender-run = $(appender-runs) ;
407 if $(targets[2])-defined
408 {
409 appender-run += "[$(target-index)/$(target-count)]" ;
410 }
411 append $(targets) : $(appender-run:J=" ") $(t) $(sources) ;
412 }
413 }
414
415 actions append
416 {
417 $(ECHO_CMD)-------------------------------------------------$(X)
418 $(ECHO_CMD)Appender run: $(>[1])$(X)
419 $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])"
420 $(ECHO_CMD)Target group: $(<:J=' ')$(X)
421 $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])"
422 $(ECHO_CMD) Target: '$(>[2])'$(X)
423 $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])"
424 $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)
425 $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])"
426 $(ECHO_CMD)=================================================$(X)
427 $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])"
428 }
429 """)
430
431
432 test_basic()
433 test_generated_target_names()