]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/test/generators_test.py
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / test / generators_test.py
CommitLineData
7c673cae
FG
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
10import BoostBuild
11import re
12
13
14def test_basic():
15 t = BoostBuild.Tester(pass_d0=False)
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",
28r"""import appender ;
29
30import "class" : new ;
31import generators ;
32import 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
46type.register MY_EXE : my_exe ;
47type.register MY_LIB : my_lib ;
48type.register MY_OBJ : my_obj ;
49
50appender.register compile-c : C : MY_OBJ ;
51appender.register compile-cpp : CPP : MY_OBJ ;
52appender.register link-lib composing : MY_OBJ : MY_LIB ;
53appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ;
54
55
56################################################################################
57#
58# LEX --> C
59#
60################################################################################
61
62type.register LEX : l ;
63
64appender.register lex-to-c : LEX : C ;
65
66
67################################################################################
68#
69# /--> tUI_H --\
70# tUI --< >--> CPP
71# \------------/
72#
73################################################################################
74
75type.register tUI : tui ;
76type.register tUI_H : tui_h ;
77
78appender.register ui-to-cpp : tUI tUI_H : CPP ;
79appender.register ui-to-h : tUI : tUI_H ;
80
81
82################################################################################
83#
84# /--> X1 --\
85# X_PRO --< >--> CPP
86# \--> X2 --/
87#
88################################################################################
89
90type.register X1 : x1 ;
91type.register X2 : x2 ;
92type.register X_PRO : x_pro ;
93
94appender.register x1-x2-to-cpp : X1 X2 : CPP ;
95appender.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
105type.register CPP_MARKED : marked_cpp : CPP ;
106type.register POSITIONS : positions ;
107type.register NM.TARGET.CPP : target_cpp : CPP ;
108type.register NM_EXE : : MY_EXE ;
109
110appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ;
111appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ;
112
113class 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}
140generators.register [ new nm::target::cpp-obj-generator target-obj ] ;
141generators.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
156type.register WHL : whl ;
157type.register DLP : dlp ;
158type.register WHL_LR0 : lr0 ;
159type.register WD : wd ;
160
161local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H
162 H(%_symbols) ] ;
163local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ;
164appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ;
165
166class 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}
195generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ;
196generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ;
197generators.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.
207my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ;
208my-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.
211my-obj obj_1 : z.cpp ;
212my-obj obj_2 : z.cpp ;
213
214nm-exe e : e.cpp ;
215""")
216
217 t.run_build_system()
b32b8144 218 t.expect_addition("bin/$toolset/debug*/" * BoostBuild.List("a.my_exe "
7c673cae
FG
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"))
b32b8144 224 t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List("c.my_obj "
7c673cae
FG
225 "auxilliary.my_lib"))
226 t.expect_nothing_more()
227
b32b8144 228 folder = "bin/$toolset/debug*"
7c673cae
FG
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
246def 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 = """\
272import type ;
273type.register AAA : _a ;
274type.register BB1 : _b1 ;
275type.register BB2 : _b2 ;
276type.register BB3 : _b3 ;
277type.register CCC : _c ;
278type.register DDD : _d ;
279
280import appender ;
281appender.register aaa-to-bbX : AAA : BB1%s BB2%s BB3%s ;
282appender.register bbX-to-ccc : BB1 BB2 BB3 : CCC ;
283appender.register ccc-to-ddd composing : CCC : DDD ;
284
285ddd _xxx : _xxx._a ;
286"""
287
288 t = BoostBuild.Tester(pass_d0=False)
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 ""
b32b8144 314 name = "bin/$toolset/debug*/_xxx"
7c673cae
FG
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
334def __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
344def __write_appender(t, name):
345 t.write(name,
346r"""# 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
354import "class" : new ;
355import generators ;
356import modules ;
357import sequence ;
358
359rule 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
370if [ modules.peek : NT ]
371{
372 X = ")" ;
373 ECHO_CMD = (echo. ;
374}
375else
376{
377 X = \" ;
378 ECHO_CMD = "echo $(X)" ;
379}
380
381local 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.
397rule 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
415actions 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
432test_basic()
433test_generated_target_names()