From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/boost/tools/build/test/generators_test.py | 433 ++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 src/boost/tools/build/test/generators_test.py (limited to 'src/boost/tools/build/test/generators_test.py') diff --git a/src/boost/tools/build/test/generators_test.py b/src/boost/tools/build/test/generators_test.py new file mode 100644 index 000000000..f612a25eb --- /dev/null +++ b/src/boost/tools/build/test/generators_test.py @@ -0,0 +1,433 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2002, 2003, 2004, 2005 Vladimir Prus +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import re + + +def test_basic(): + t = BoostBuild.Tester() + __write_appender(t, "appender.jam") + t.write("a.cpp", "") + t.write("b.cxx", "") + t.write("c.tui", "") + t.write("d.wd", "") + t.write("e.cpp", "") + t.write("x.l", "") + t.write("y.x_pro", "") + t.write("z.cpp", "") + t.write("lib/c.cpp", "int bar() { return 0; }\n") + t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;") + t.write("jamroot.jam", +r"""import appender ; + +import "class" : new ; +import generators ; +import type ; + + +################################################################################ +# +# We use our own custom EXE, LIB & OBJ target generators as using the regular +# ones would force us to have to deal with different compiler/linker specific +# 'features' that really have nothing to do with this test. For example, IBM XL +# C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero +# exit code and thus fails our build when run with a source file using an +# unknown suffix like '.marked_cpp'. +# +################################################################################ + +type.register MY_EXE : my_exe ; +type.register MY_LIB : my_lib ; +type.register MY_OBJ : my_obj ; + +appender.register compile-c : C : MY_OBJ ; +appender.register compile-cpp : CPP : MY_OBJ ; +appender.register link-lib composing : MY_OBJ : MY_LIB ; +appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ; + + +################################################################################ +# +# LEX --> C +# +################################################################################ + +type.register LEX : l ; + +appender.register lex-to-c : LEX : C ; + + +################################################################################ +# +# /--> tUI_H --\ +# tUI --< >--> CPP +# \------------/ +# +################################################################################ + +type.register tUI : tui ; +type.register tUI_H : tui_h ; + +appender.register ui-to-cpp : tUI tUI_H : CPP ; +appender.register ui-to-h : tUI : tUI_H ; + + +################################################################################ +# +# /--> X1 --\ +# X_PRO --< >--> CPP +# \--> X2 --/ +# +################################################################################ + +type.register X1 : x1 ; +type.register X2 : x2 ; +type.register X_PRO : x_pro ; + +appender.register x1-x2-to-cpp : X1 X2 : CPP ; +appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ; + + +################################################################################ +# +# When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from +# anything else, e.g. directly from CPP. +# +################################################################################ + +type.register CPP_MARKED : marked_cpp : CPP ; +type.register POSITIONS : positions ; +type.register NM.TARGET.CPP : target_cpp : CPP ; +type.register NM_EXE : : MY_EXE ; + +appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ; +appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ; + +class "nm::target::cpp-obj-generator" : generator +{ + rule __init__ ( id ) + { + generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ; + generator.set-rule-name appender.appender ; + } + + rule requirements ( ) + { + return NM_EXE ; + } + + rule run ( project name ? : properties * : source : multiple ? ) + { + if [ $(source).type ] = CPP + { + local converted = [ generators.construct $(project) : NM.TARGET.CPP + : $(properties) : $(source) ] ; + if $(converted) + { + return [ generators.construct $(project) : MY_OBJ : + $(properties) : $(converted[2]) ] ; + } + } + } +} +generators.register [ new "nm::target::cpp-obj-generator" target-obj ] ; +generators.override target-obj : all ; + + +################################################################################ +# +# A more complex test case scenario with the following generators: +# 1. WHL --> CPP, WHL_LR0, H, H(%_symbols) +# 2. DLP --> CPP +# 3. WD --> WHL(%_parser) DLP(%_lexer) +# 4. A custom generator of higher priority than generators 1. & 2. that helps +# disambiguate between them when generating CPP files from WHL and DLP +# sources. +# +################################################################################ + +type.register WHL : whl ; +type.register DLP : dlp ; +type.register WHL_LR0 : lr0 ; +type.register WD : wd ; + +local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H + H(%_symbols) ] ; +local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ; +appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ; + +class wd-to-cpp : generator +{ + rule __init__ ( id : sources * : targets * ) + { + generator.__init__ $(id) : $(sources) : $(targets) ; + } + + rule run ( project name ? : property-set : source ) + { + local new-sources = $(source) ; + if ! [ $(source).type ] in WHL DLP + { + local r1 = [ generators.construct $(project) $(name) : WHL : + $(property-set) : $(source) ] ; + local r2 = [ generators.construct $(project) $(name) : DLP : + $(property-set) : $(source) ] ; + new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ; + } + + local result ; + for local i in $(new-sources) + { + local t = [ generators.construct $(project) $(name) : CPP : + $(property-set) : $(i) ] ; + result += $(t[2-]) ; + } + return $(result) ; + } +} +generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ; +generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ; +generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ; + + +################################################################################ +# +# Declare build targets. +# +################################################################################ + +# This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp. +my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ; +my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ; + +# This should cause two CPP --> MY_OBJ constructions for z.cpp. +my-obj obj_1 : z.cpp ; +my-obj obj_2 : z.cpp ; + +nm-exe e : e.cpp ; +""") + + t.run_build_system() + t.expect_addition("bin/" * BoostBuild.List("a.my_exe " + "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp " + "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h " + "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp " + "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe " + "f.my_exe obj_1.my_obj obj_2.my_obj")) + t.expect_addition("lib/bin/" * BoostBuild.List("c.my_obj " + "auxilliary.my_lib")) + t.expect_nothing_more() + + folder = "bin" + t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'") + t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'") + t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'") + + lines = t.stdout().splitlines() + source_lines = [x for x in lines if re.match("^ Sources: '", x)] + if not __match_count_is(source_lines, "'z.cpp'", 2): + BoostBuild.annotation("failure", "z.cpp must be compiled exactly " + "twice.") + t.fail_test(1) + if not __match_count_is(source_lines, "'a.cpp'", 1): + BoostBuild.annotation("failure", "a.cpp must be compiled exactly " + "once.") + t.fail_test(1) + t.cleanup() + + +def test_generated_target_names(): + """ + Test generator generated target names. Unless given explicitly, target + names should be determined based on their specified source names. All + sources for generating a target need to have matching names in order for + Boost Build to be able to implicitly determine the target's name. + + We use the following target generation structure with differently named + BBX targets: + /---> BB1 ---\ + AAA --<----> BB2 ---->--> CCC --(composing)--> DDD + \---> BB3 ---/ + + The extra generator at the end is needed because generating a top-level + CCC target directly would requires us to explicitly specify a name for it. + The extra generator needs to be composing in order not to explicitly + request a specific name for its CCC source target based on its own target + name. + + We also check for a regression where only the first two sources were + checked to see if their names match. Note that we need to try out all file + renaming combinations as we do not know what ordering Boost Build is going + to use when passing in those files as generator sources. + + """ + jamfile_template = """\ +import type ; +type.register AAA : _a ; +type.register BB1 : _b1 ; +type.register BB2 : _b2 ; +type.register BB3 : _b3 ; +type.register CCC : _c ; +type.register DDD : _d ; + +import appender ; +appender.register aaa-to-bbX : AAA : BB1%s BB2%s BB3%s ; +appender.register bbX-to-ccc : BB1 BB2 BB3 : CCC ; +appender.register ccc-to-ddd composing : CCC : DDD ; + +ddd _xxx : _xxx._a ; +""" + + t = BoostBuild.Tester() + __write_appender(t, "appender.jam") + t.write("_xxx._a", "") + + def test_one(t, rename1, rename2, rename3, status): + def f(rename): + if rename: return "(%_x)" + return "" + + jamfile = jamfile_template % (f(rename1), f(rename2), f(rename3)) + t.write("jamroot.jam", jamfile, wait=False) + + # Remove any preexisting targets left over from a previous test run + # so we do not have to be careful about tracking which files have been + # newly added and which preexisting ones have only been modified. + t.rm("bin") + + t.run_build_system(status=status) + + if status: + t.expect_output_lines("*.bbX-to-ccc: source targets have " + "different names: cannot determine target name") + else: + def suffix(rename): + if rename: return "_x" + return "" + name = "bin/_xxx" + e = t.expect_addition + e("%s%s._b1" % (name, suffix(rename1))) + e("%s%s._b2" % (name, suffix(rename2))) + e("%s%s._b3" % (name, suffix(rename3))) + e("%s%s._c" % (name, suffix(rename1 and rename2 and rename3))) + e("%s._d" % name) + t.expect_nothing_more() + + test_one(t, False, False, False, status=0) + test_one(t, True , False, False, status=1) + test_one(t, False, True , False, status=1) + test_one(t, False, False, True , status=1) + test_one(t, True , True , False, status=1) + test_one(t, True , False, True , status=1) + test_one(t, False, True , True , status=1) + test_one(t, True , True , True , status=0) + t.cleanup() + + +def __match_count_is(lines, pattern, expected): + count = 0 + for x in lines: + if re.search(pattern, x): + count += 1 + if count > expected: + return False + return count == expected + + +def __write_appender(t, name): + t.write(name, +r"""# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Support for registering test generators that construct their targets by +# simply appending their given input data, e.g. list of sources & targets. + +import "class" : new ; +import generators ; +import modules ; +import sequence ; + +rule register ( id composing ? : source-types + : target-types + ) +{ + local caller-module = [ CALLER_MODULE ] ; + id = $(caller-module).$(id) ; + local g = [ new generator $(id) $(composing) : $(source-types) : + $(target-types) ] ; + $(g).set-rule-name $(__name__).appender ; + generators.register $(g) ; + return $(id) ; +} + +if [ modules.peek : NT ] +{ + X = ")" ; + ECHO_CMD = (echo. ; +} +else +{ + X = \" ; + ECHO_CMD = "echo $(X)" ; +} + +local appender-runs ; + +# We set up separate actions for building each target in order to avoid having +# to iterate over them in action (i.e. shell) code. We have to be extra careful +# though to achieve the exact same effect as if doing all the work in just one +# action. Otherwise Boost Jam might, under some circumstances, run only some of +# our actions. To achieve this we register a series of actions for all the +# targets (since they all have the same target list - either all or none of them +# get run independent of which target actually needs to get built), each +# building only a single target. Since all our actions use the same targets, we +# can not use 'on-target' parameters to pass data to a specific action so we +# pass them using the second 'sources' parameter which our actions then know how +# to interpret correctly. This works well since Boost Jam does not automatically +# add dependency relations between specified action targets & sources and so the +# second argument, even though most often used to pass in a list of sources, can +# actually be used for passing in any type of information. +rule appender ( targets + : sources + : properties * ) +{ + appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ; + local target-index = 0 ; + local target-count = [ sequence.length $(targets) ] ; + local original-targets ; + for t in $(targets) + { + target-index = [ CALC $(target-index) + 1 ] ; + local appender-run = $(appender-runs) ; + if $(targets[2])-defined + { + appender-run += "[$(target-index)/$(target-count)]" ; + } + append $(targets) : $(appender-run:J=" ") $(t) $(sources) ; + } +} + +actions append +{ + $(ECHO_CMD)-------------------------------------------------$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])" + $(ECHO_CMD)Target group: $(<:J=' ')$(X) + $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])" + $(ECHO_CMD) Target: '$(>[2])'$(X) + $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])" + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X) + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])" + $(ECHO_CMD)=================================================$(X) + $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])" +} +""") + + +test_basic() +test_generated_target_names() -- cgit v1.2.3