From f05bacab618fa77295df90419a37bcc0ed6e469d Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 20 Dec 2002 22:44:18 +0000 Subject: [PATCH] sane-testing merged [SVN r16674] --- testing.jam | 381 +++++++++++++++++++++++-------------------------- v1/testing.jam | 381 +++++++++++++++++++++++-------------------------- 2 files changed, 364 insertions(+), 398 deletions(-) diff --git a/testing.jam b/testing.jam index de04410b8..3269805c7 100755 --- a/testing.jam +++ b/testing.jam @@ -6,23 +6,13 @@ if ! $(.testing.jam-included) { .testing.jam-included = "}" ; # The brace makes emacs indentation happy -####################################################################################### -# Tests generate a number of files reflecting their status in the subvariant-directory -# -# .test - a marker so that Jam knows when it needs to be -# rebuilt. It will contain the paths from this -# directory to the source files used for the test -# -# .success - present only if the test last succeeded. -# Contains the string "succeeded" -# -# .failure - present only if the test last failed. Contains the string -# "failed". -# -# .output - contains the output of the test if it was a run test. -####################################################################################### - +local rule get-var-value ( name + ) +{ +# ECHO $(name) ; + # ECHO $($(name)) ; + return $($(name)) ; +} # Declares a test target. If name is not supplied, it is taken from the name of # the first source file, sans extension and directory path. @@ -32,161 +22,108 @@ if ! $(.testing.jam-included) # RETURNS the name(s) of the generated test target(s). rule boost-test ( sources + : target-type : requirements * : test-name ? ) { - local result ; + if ! $(gIN_LIB_INCLUDE) # No need to execute this code twice { - # manufacture a test name if none supplied explicitly - test-name ?= $(sources[1]:D=:S=) ; + local result ; + { + # manufacture a test name if none supplied explicitly + test-name ?= $(sources[1]:D=:S=) ; + + # Make sure that targets don't become part of "all" + local gSUPPRESS_FAKE_TARGETS = true ; + + result = [ + declare-local-target $(test-name) + : $(sources) + : $(requirements) $(BOOST_ROOT) + : # default build + : $(target-type) + ] ; + + if $(result) in $(.all-boost-tests) + { + EXIT boost-test \"$(result)\" declared twice ; + .all-boost-tests += $(result) ; + } + + if ( --dump-tests in $(ARGV) ) + { + local srcs = [ on $(result) get-var-value source-files ] ; + local source-files ; + for local s in $(srcs) + { + source-files += [ + SEARCH_FOR_TARGET $(s:G=) + : [ on $(s) get-var-value LOCATE SEARCH ] + ] ; + } - # Make sure that targets don't become part of "all" - local gSUPPRESS_FAKE_TARGETS = true ; + ECHO "(boost-test" \"$(test-name)\" ":" \"$(source-files)\" ")" ; + } + + } - local dependencies = [ select-gristed $(sources) ] ; - local source-files = [ select-ungristed $(sources) ] ; - result = [ - declare-local-target $(test-name) - : $(source-files) $(dependencies) # sources - : $(requirements) $(BOOST_ROOT) # requirements - : # default build - : $(target-type) - ] ; + Clean clean : $(result) ; + + # make NOTFILE targets of the same base name as the sources which can + # be used to build a single test. + type-DEPENDS $(sources:B:S=) : $(result) ; + + # The NOTFILE target called "test" builds all tests + type-DEPENDS test : $(result) ; + + # Make sure the test result doesn't hang around if the test fails + RMOLD $(result) ; + + return $(result) ; } - - Clean clean : $(result) ; - - # make NOTFILE targets of the same base name as the sources which can - # be used to build a single test. - type-DEPENDS $(sources:B:S=) : $(result) ; - - # The NOTFILE target called "test" builds all tests - type-DEPENDS test : $(result) ; - - return $(result) ; } ####### BOOST_TEST_SUFFIX ?= .test ; +# Set a variable which says how to dump a file to stdout +if $(NT) +{ + CATENATE = type ; +} +else +{ + CATENATE = cat ; +} + +actions **passed** bind source-files +{ + echo $(source-files) > $(<) +} + +actions (failed-as-expected) +{ + echo failed as expected > $(<) +} + # a utility rule which causes test-file to be built successfully only if # dependency fails to build. Used for expected-failure tests. rule failed-test-file ( test-file : dependency + ) { - catenate-output-on-failure $(test-file) : $(dependency[1]) ; - DEPENDS $(test-file) : $(dependency) ; - NOCARE $(dependency) ; - TEMPORARY $(dependency) ; + local grist = [ MATCH ^<(.*)> : $(dependency:G) ] ; + local marker = $(dependency:G=$(grist)*fail) ; + (failed-as-expected) $(marker) ; FAIL_EXPECTED $(dependency) ; + MakeLocate $(marker) : $(LOCATE_TARGET) ; + RMOLD $(marker) ; + DEPENDS $(marker) : $(dependency) ; + + succeeded-test-file $(test-file) : $(marker) ; } # a utility rule which causes test-file to be built successfully only if # dependency builds. Used for expected-success tests. rule succeeded-test-file ( test-file : dependency + ) { - catenate-output-on-failure $(test-file) : $(dependency[1]) ; + **passed** $(test-file) ; DEPENDS $(test-file) : $(dependency) ; - NOCARE $(dependency) ; - TEMPORARY $(dependency) ; -} - -rule catenate-output-on-failure ( test-file : dependency ) -{ - if $(gTEST_OUTPUT_FILE($(dependency))) - { - output-file on $(test-file) = $(gTEST_OUTPUT_FILE($(dependency))) ; - } -} - -if $(NT) -{ - CATENATE1 = "if exist \"" ; - CATENATE2 = "\" ( ECHO *** output file follows *** -type \"" ; - CATENATE3 = "\" -ECHO *** end of output file *** )" ; - - actions failed-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if EXIST "$(>)". ( - if EXIST "$(<:S=.success)". del /f/q "$(<:S=.success)". - echo "failed" > "$(<:S=.failure)" - - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo * - echo ***************** failed above test: $(<:B:S=) ******************** - echo * - ) ELSE ( - if EXIST "$(<:S=.failure)". del /f/q "$(<:S=.failure)". - echo succeeded > "$(<:S=.success)" - ) - } - - actions succeeded-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if EXIST "$(>)". ( - if EXIST "$(<:S=.failure)". del /f/q "$(<:S=.failure)". - echo succeeded > "$(<:S=.success)" - ) ELSE ( - if EXIST "$(<:S=.success)". del /f/q "$(<:S=.success)". - echo failed > "$(<:S=.failure)" - - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo * - echo ***************** failed above test: $(<:B:S=) ******************** - echo * - ) - } -} -else -{ - CATENATE = "cat " ; - CATENATE1 = "if [ -f \"" ; - CATENATE2 = "\" ] ; then - echo *** output file follows *** - cat \"" ; - CATENATE3 = "\" ; echo *** end of output file *** - fi" ; - - actions failed-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if [ -f "$(>)" ] ; then - if [ -f "$(<:S=.success)" ] ; then - $(RM) "$(<:S=.success)" - fi - echo "failed" > $(<:S=.failure) - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo "*" - echo "***************** failed above test: $(<:B:S=) ********************" - echo "*" - else - if [ -f "$(<:S=.failure)" ] ; then - $(RM) "$(<:S=.failure)" - fi - echo "succeeded" > "$(<:S=.success)" - fi - } - - actions succeeded-test-file bind output-file source-files - { - echo "$(source-files)" > "$(<:S=.test)" - if [ -f "$(>)" ] ; then - if [ -f "$(<:S=.failure)" ] ; then - $(RM) "$(<:S=.failure)" - fi - echo "succeeded" > "$(<:S=.success)" - else - if [ -f "$(<:S=.success)" ] ; then - $(RM) "$(<:S=.success)" - fi - echo "failed" > "$(<:S=.failure)" - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo "*" - echo "***************** failed above test: $(<:B:S=) ********************" - echo "*" - fi - } } rule declare-build-succeed-test ( test-type : dependency-type ) @@ -206,13 +143,6 @@ rule declare-build-fail-test ( test-type : dependency-type ) SUF$(test-type) = $(BOOST_TEST_SUFFIX) ; } -# A temporary measure in case people don't rebuild their Jam -# executables. Define the builtin RMOLD if it's missing. -if ! ( RMOLD in [ RULENAMES ] ) -{ - rule RMOLD { } -} - # When the appropriate generator function is bound to the # test-file-generator argument, this is a target generator function # for target types declared with declare-build-succeed-test and @@ -233,9 +163,9 @@ rule build-test ( test-file-generator test-file + : sources + : requirements * ) # file. source-files on $(test-file) = $(sources) ; - # Make sure that the dependency is erased, so as not to give a - # false indication of success. - RMOLD $(dependency) ; + # Make sure that the test-file is erased upon failure, so as not + # to give a false indication of success. + RMOLD $(test-file) ; # Call dependency-type's generator function to attempt the build local ignored = [ @@ -244,18 +174,17 @@ rule build-test ( test-file-generator test-file + : sources + : requirements * ) # Generator functions don't handle this job for us; perhaps they should. set-target-variables $(dependency) ; + if $(test-file:S) != $(BOOST_TEST_SUFFIX) + { + EXIT unexpected test file suffix. Filename: $(test-file) ; + } + # The test files go with the other subvariant targets - local test-files = $(test-file:S=.test) $(test-file:S=.success) $(test-file:S=.failure) ; - MakeLocate $(test-files) : $(LOCATE_TARGET) ; - Clean clean : $(test-files) ; + MakeLocate $(test-file) : $(LOCATE_TARGET) ; + Clean clean : $(test-file) ; # Generate the test file $(test-file-generator) $(test-file) : $(dependency) ; - - if $(RUN_ALL_TESTS) - { - ALWAYS $(test-file) ; - } } ### Rules for testing whether a file compiles ### @@ -283,8 +212,10 @@ rule compile-fail ( sources + : requirements * : test-name ? ) gGENERATOR_FUNCTION(RUN_TEST) = run-test ; SUFRUN_TEST = .run ; -rule run-test ( target : sources + : requirements * ) +rule run-test ( run-target : sources + : requirements * ) { + local top-target = $(target) ; + local target = $(run-target) ; local executable = $(target:S=$(SUFEXE)) ; local parent = $(target:S=.test) ; @@ -292,8 +223,29 @@ rule run-test ( target : sources + : requirements * ) gRUN_LD_LIBRARY_PATH($(executable)) = $(gRUN_LD_LIBRARY_PATH($(parent))) ; gRUN_PATH($(executable)) = $(gRUN_PATH($(parent))) ; - executable-file $(executable) : $(sources) : $(requirements) ; set-target-variables $(executable) ; + local depends = $(gTARGET_DEPS($(top-target))) ; + local libs dlls ; + { + # Protect target variables against modification while lib dependencies + # are built. They will be made empty here, and restored when this scope exits + local $(gTARGET_VARIABLES) ; + + # extract the simple properties from dependent-properties + local simple-properties = $(gBUILD_PROPERTIES) ; + segregate-free-properties simple-properties ; + + # generate library build instructions + local BUILD = $(BUILD) ; + BUILD ?= $(gTARGET_DEFAULT_BUILD($(target))) ; + libs = [ link-libraries [ get-values <$(STATIC_TYPES)> : $(depends) ] + : $(toolset) $(variant) : $(simple-properties) ] ; + dlls = [ link-libraries [ get-values <$(SHARED_TYPES)> : $(depends) ] + : $(toolset) $(variant) : $(simple-properties) ] ; + } + depend-on-libraries $(executable) : $(libs) ; + depend-on-dlls $(executable) : $(dlls) ; + executable-file $(executable) : $(sources) : $(requirements) ; # The .test file goes with the other subvariant targets # normalization is a hack to get the slashes going the right way on Windoze @@ -311,47 +263,72 @@ rule capture-run-output ( target : executable + ) { gTEST_OUTPUT_FILE($(target)) = $(target:S=.output) ; INCLUDES $(target) : $(target:S=.output) ; - MakeLocate $(test-file:S=.failure) : $(LOCATE_TARGET) ; MakeLocate $(test-file:S=.output) : $(LOCATE_TARGET) ; Clean clean $(test-file:S=.output) ; capture-run-output1 $(target) : $(executable) ; } -rule capture-run-output1 ( target : executable ) +if $(NT) { - output-file on $(target) = $(target:S=.output) ; - local targets = $(target) $(target:S=.output) ; - - RUN_PATH on $(targets) = [ join $(gRUN_PATH($(executable))) : $(SPLITPATH) ] ; - if $(UNIX) - { - RUN_LD_LIBRARY_PATH on $(targets) = [ join $(gRUN_LD_LIBRARY_PATH($(executable))) : $(SPLITPATH) ] ; - } -} - - - -if $(UNIX) -{ - actions capture-run-output1 bind INPUT_FILES output-file - { - $(SHELL_SET)PATH=$(RUN_PATH:J=:):$PATH - $(SHELL_EXPORT)PATH - $(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH):$LD_LIBRARY_PATH - $(SHELL_EXPORT)LD_LIBRARY_PATH - $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<[1]) - } + ENV_PATH = %PATH% ; + CATENATE = type ; } else { - actions capture-run-output1 bind INPUT_FILES output-file - { - $(SHELL_SET)PATH=$(RUN_PATH:J=;);%PATH% - $(SHELL_EXPORT)PATH - $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<[1]) - } + ENV_PATH = $PATH ; + ENV_LD_LIBRARY_PATH = $LD_LIBRARY_PATH ; + CATENATE = cat ; } +rule capture-run-output1 ( target : executable ) +{ + output-file on $(target) = $(target:S=.output) ; + + # Make sure no confusing output about setting or exporting PATH or + # LD_LIBRARY_PATH is seen unless it is actually used. + local p = $(gRUN_PATH($(executable))) ; + if $(p) + { + RUN_PATH on $(target) = $(p) $(ENV_PATH) ; + PATH_VAR on $(target) = PATH ; + } + else + { + RUN_PATH on $(target) = ; + PATH_VAR on $(target) = ; + } + + p = $(gRUN_LD_LIBRARY_PATH($(executable))) ; + if $(NT) + { + RUN_LD_LIBRARY_PATH on $(target) = ; + LD_LIBRARY_PATH_VAR on $(target) = ; + } + else if $(p) + { + RUN_LD_LIBRARY_PATH on $(target) = $(p) $(ENV_LD_LIBRARY_PATH) ; + LD_LIBRARY_PATH_VAR on $(target) = LD_LIBRARY_PATH ; + } + execute-test $(target) : $(executable) ; +} + +RUN_OUTPUT_HEADER = "echo ====== BEGIN OUTPUT ====== &&" ; +RUN_OUTPUT_FOOTER = " && echo ====== END OUTPUT ======" ; +if --verbose-test in $(ARGV) +{ + VERBOSE_CAT = "&& "$(RUN_OUTPUT_HEADER)" "$(CATENATE)" " ; +} + +actions execute-test bind INPUT_FILES output-file +{ + $(SHELL_SET)PATH=$(RUN_PATH:J=$(SPLITPATH)) + $(SHELL_EXPORT)$(PATH_VAR) + $(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH:J=$(SPLITPATH)) + $(SHELL_EXPORT)$(LD_LIBRARY_PATH_VAR) + $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<) $(VERBOSE_CAT)$(<)$(RUN_OUTPUT_FOOTER) || ( $(RUN_OUTPUT_HEADER) $(CATENATE) $(output-file) $(RUN_OUTPUT_FOOTER) && exit 1 ) +} + + declare-build-fail-test RUN_FAIL : RUN_TEST ; declare-build-succeed-test RUN : RUN_TEST ; rule run ( sources + : args * : input-files * : requirements * : name ? ) @@ -378,6 +355,12 @@ rule link-fail ( sources + : requirements * : name ? ) return [ boost-test $(<) : LINK_FAIL : $(2) : $(name) ] ; } +declare-build-succeed-test LINK : EXE ; +rule link ( sources + : requirements * : name ? ) +{ + return [ boost-test $(<) : LINK : $(2) : $(name) ] ; +} + ### Rules for grouping tests into suites: rule test-suite # pseudotarget-name : test-targets... diff --git a/v1/testing.jam b/v1/testing.jam index de04410b8..3269805c7 100755 --- a/v1/testing.jam +++ b/v1/testing.jam @@ -6,23 +6,13 @@ if ! $(.testing.jam-included) { .testing.jam-included = "}" ; # The brace makes emacs indentation happy -####################################################################################### -# Tests generate a number of files reflecting their status in the subvariant-directory -# -# .test - a marker so that Jam knows when it needs to be -# rebuilt. It will contain the paths from this -# directory to the source files used for the test -# -# .success - present only if the test last succeeded. -# Contains the string "succeeded" -# -# .failure - present only if the test last failed. Contains the string -# "failed". -# -# .output - contains the output of the test if it was a run test. -####################################################################################### - +local rule get-var-value ( name + ) +{ +# ECHO $(name) ; + # ECHO $($(name)) ; + return $($(name)) ; +} # Declares a test target. If name is not supplied, it is taken from the name of # the first source file, sans extension and directory path. @@ -32,161 +22,108 @@ if ! $(.testing.jam-included) # RETURNS the name(s) of the generated test target(s). rule boost-test ( sources + : target-type : requirements * : test-name ? ) { - local result ; + if ! $(gIN_LIB_INCLUDE) # No need to execute this code twice { - # manufacture a test name if none supplied explicitly - test-name ?= $(sources[1]:D=:S=) ; + local result ; + { + # manufacture a test name if none supplied explicitly + test-name ?= $(sources[1]:D=:S=) ; + + # Make sure that targets don't become part of "all" + local gSUPPRESS_FAKE_TARGETS = true ; + + result = [ + declare-local-target $(test-name) + : $(sources) + : $(requirements) $(BOOST_ROOT) + : # default build + : $(target-type) + ] ; + + if $(result) in $(.all-boost-tests) + { + EXIT boost-test \"$(result)\" declared twice ; + .all-boost-tests += $(result) ; + } + + if ( --dump-tests in $(ARGV) ) + { + local srcs = [ on $(result) get-var-value source-files ] ; + local source-files ; + for local s in $(srcs) + { + source-files += [ + SEARCH_FOR_TARGET $(s:G=) + : [ on $(s) get-var-value LOCATE SEARCH ] + ] ; + } - # Make sure that targets don't become part of "all" - local gSUPPRESS_FAKE_TARGETS = true ; + ECHO "(boost-test" \"$(test-name)\" ":" \"$(source-files)\" ")" ; + } + + } - local dependencies = [ select-gristed $(sources) ] ; - local source-files = [ select-ungristed $(sources) ] ; - result = [ - declare-local-target $(test-name) - : $(source-files) $(dependencies) # sources - : $(requirements) $(BOOST_ROOT) # requirements - : # default build - : $(target-type) - ] ; + Clean clean : $(result) ; + + # make NOTFILE targets of the same base name as the sources which can + # be used to build a single test. + type-DEPENDS $(sources:B:S=) : $(result) ; + + # The NOTFILE target called "test" builds all tests + type-DEPENDS test : $(result) ; + + # Make sure the test result doesn't hang around if the test fails + RMOLD $(result) ; + + return $(result) ; } - - Clean clean : $(result) ; - - # make NOTFILE targets of the same base name as the sources which can - # be used to build a single test. - type-DEPENDS $(sources:B:S=) : $(result) ; - - # The NOTFILE target called "test" builds all tests - type-DEPENDS test : $(result) ; - - return $(result) ; } ####### BOOST_TEST_SUFFIX ?= .test ; +# Set a variable which says how to dump a file to stdout +if $(NT) +{ + CATENATE = type ; +} +else +{ + CATENATE = cat ; +} + +actions **passed** bind source-files +{ + echo $(source-files) > $(<) +} + +actions (failed-as-expected) +{ + echo failed as expected > $(<) +} + # a utility rule which causes test-file to be built successfully only if # dependency fails to build. Used for expected-failure tests. rule failed-test-file ( test-file : dependency + ) { - catenate-output-on-failure $(test-file) : $(dependency[1]) ; - DEPENDS $(test-file) : $(dependency) ; - NOCARE $(dependency) ; - TEMPORARY $(dependency) ; + local grist = [ MATCH ^<(.*)> : $(dependency:G) ] ; + local marker = $(dependency:G=$(grist)*fail) ; + (failed-as-expected) $(marker) ; FAIL_EXPECTED $(dependency) ; + MakeLocate $(marker) : $(LOCATE_TARGET) ; + RMOLD $(marker) ; + DEPENDS $(marker) : $(dependency) ; + + succeeded-test-file $(test-file) : $(marker) ; } # a utility rule which causes test-file to be built successfully only if # dependency builds. Used for expected-success tests. rule succeeded-test-file ( test-file : dependency + ) { - catenate-output-on-failure $(test-file) : $(dependency[1]) ; + **passed** $(test-file) ; DEPENDS $(test-file) : $(dependency) ; - NOCARE $(dependency) ; - TEMPORARY $(dependency) ; -} - -rule catenate-output-on-failure ( test-file : dependency ) -{ - if $(gTEST_OUTPUT_FILE($(dependency))) - { - output-file on $(test-file) = $(gTEST_OUTPUT_FILE($(dependency))) ; - } -} - -if $(NT) -{ - CATENATE1 = "if exist \"" ; - CATENATE2 = "\" ( ECHO *** output file follows *** -type \"" ; - CATENATE3 = "\" -ECHO *** end of output file *** )" ; - - actions failed-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if EXIST "$(>)". ( - if EXIST "$(<:S=.success)". del /f/q "$(<:S=.success)". - echo "failed" > "$(<:S=.failure)" - - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo * - echo ***************** failed above test: $(<:B:S=) ******************** - echo * - ) ELSE ( - if EXIST "$(<:S=.failure)". del /f/q "$(<:S=.failure)". - echo succeeded > "$(<:S=.success)" - ) - } - - actions succeeded-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if EXIST "$(>)". ( - if EXIST "$(<:S=.failure)". del /f/q "$(<:S=.failure)". - echo succeeded > "$(<:S=.success)" - ) ELSE ( - if EXIST "$(<:S=.success)". del /f/q "$(<:S=.success)". - echo failed > "$(<:S=.failure)" - - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo * - echo ***************** failed above test: $(<:B:S=) ******************** - echo * - ) - } -} -else -{ - CATENATE = "cat " ; - CATENATE1 = "if [ -f \"" ; - CATENATE2 = "\" ] ; then - echo *** output file follows *** - cat \"" ; - CATENATE3 = "\" ; echo *** end of output file *** - fi" ; - - actions failed-test-file bind output-file source-files - { - echo "$(source-files)" > $(<:S=.test) - if [ -f "$(>)" ] ; then - if [ -f "$(<:S=.success)" ] ; then - $(RM) "$(<:S=.success)" - fi - echo "failed" > $(<:S=.failure) - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo "*" - echo "***************** failed above test: $(<:B:S=) ********************" - echo "*" - else - if [ -f "$(<:S=.failure)" ] ; then - $(RM) "$(<:S=.failure)" - fi - echo "succeeded" > "$(<:S=.success)" - fi - } - - actions succeeded-test-file bind output-file source-files - { - echo "$(source-files)" > "$(<:S=.test)" - if [ -f "$(>)" ] ; then - if [ -f "$(<:S=.failure)" ] ; then - $(RM) "$(<:S=.failure)" - fi - echo "succeeded" > "$(<:S=.success)" - else - if [ -f "$(<:S=.success)" ] ; then - $(RM) "$(<:S=.success)" - fi - echo "failed" > "$(<:S=.failure)" - $(CATENATE1)$(output-file)$(CATENATE2)$(output-file)$(CATENATE3) - echo "*" - echo "***************** failed above test: $(<:B:S=) ********************" - echo "*" - fi - } } rule declare-build-succeed-test ( test-type : dependency-type ) @@ -206,13 +143,6 @@ rule declare-build-fail-test ( test-type : dependency-type ) SUF$(test-type) = $(BOOST_TEST_SUFFIX) ; } -# A temporary measure in case people don't rebuild their Jam -# executables. Define the builtin RMOLD if it's missing. -if ! ( RMOLD in [ RULENAMES ] ) -{ - rule RMOLD { } -} - # When the appropriate generator function is bound to the # test-file-generator argument, this is a target generator function # for target types declared with declare-build-succeed-test and @@ -233,9 +163,9 @@ rule build-test ( test-file-generator test-file + : sources + : requirements * ) # file. source-files on $(test-file) = $(sources) ; - # Make sure that the dependency is erased, so as not to give a - # false indication of success. - RMOLD $(dependency) ; + # Make sure that the test-file is erased upon failure, so as not + # to give a false indication of success. + RMOLD $(test-file) ; # Call dependency-type's generator function to attempt the build local ignored = [ @@ -244,18 +174,17 @@ rule build-test ( test-file-generator test-file + : sources + : requirements * ) # Generator functions don't handle this job for us; perhaps they should. set-target-variables $(dependency) ; + if $(test-file:S) != $(BOOST_TEST_SUFFIX) + { + EXIT unexpected test file suffix. Filename: $(test-file) ; + } + # The test files go with the other subvariant targets - local test-files = $(test-file:S=.test) $(test-file:S=.success) $(test-file:S=.failure) ; - MakeLocate $(test-files) : $(LOCATE_TARGET) ; - Clean clean : $(test-files) ; + MakeLocate $(test-file) : $(LOCATE_TARGET) ; + Clean clean : $(test-file) ; # Generate the test file $(test-file-generator) $(test-file) : $(dependency) ; - - if $(RUN_ALL_TESTS) - { - ALWAYS $(test-file) ; - } } ### Rules for testing whether a file compiles ### @@ -283,8 +212,10 @@ rule compile-fail ( sources + : requirements * : test-name ? ) gGENERATOR_FUNCTION(RUN_TEST) = run-test ; SUFRUN_TEST = .run ; -rule run-test ( target : sources + : requirements * ) +rule run-test ( run-target : sources + : requirements * ) { + local top-target = $(target) ; + local target = $(run-target) ; local executable = $(target:S=$(SUFEXE)) ; local parent = $(target:S=.test) ; @@ -292,8 +223,29 @@ rule run-test ( target : sources + : requirements * ) gRUN_LD_LIBRARY_PATH($(executable)) = $(gRUN_LD_LIBRARY_PATH($(parent))) ; gRUN_PATH($(executable)) = $(gRUN_PATH($(parent))) ; - executable-file $(executable) : $(sources) : $(requirements) ; set-target-variables $(executable) ; + local depends = $(gTARGET_DEPS($(top-target))) ; + local libs dlls ; + { + # Protect target variables against modification while lib dependencies + # are built. They will be made empty here, and restored when this scope exits + local $(gTARGET_VARIABLES) ; + + # extract the simple properties from dependent-properties + local simple-properties = $(gBUILD_PROPERTIES) ; + segregate-free-properties simple-properties ; + + # generate library build instructions + local BUILD = $(BUILD) ; + BUILD ?= $(gTARGET_DEFAULT_BUILD($(target))) ; + libs = [ link-libraries [ get-values <$(STATIC_TYPES)> : $(depends) ] + : $(toolset) $(variant) : $(simple-properties) ] ; + dlls = [ link-libraries [ get-values <$(SHARED_TYPES)> : $(depends) ] + : $(toolset) $(variant) : $(simple-properties) ] ; + } + depend-on-libraries $(executable) : $(libs) ; + depend-on-dlls $(executable) : $(dlls) ; + executable-file $(executable) : $(sources) : $(requirements) ; # The .test file goes with the other subvariant targets # normalization is a hack to get the slashes going the right way on Windoze @@ -311,47 +263,72 @@ rule capture-run-output ( target : executable + ) { gTEST_OUTPUT_FILE($(target)) = $(target:S=.output) ; INCLUDES $(target) : $(target:S=.output) ; - MakeLocate $(test-file:S=.failure) : $(LOCATE_TARGET) ; MakeLocate $(test-file:S=.output) : $(LOCATE_TARGET) ; Clean clean $(test-file:S=.output) ; capture-run-output1 $(target) : $(executable) ; } -rule capture-run-output1 ( target : executable ) +if $(NT) { - output-file on $(target) = $(target:S=.output) ; - local targets = $(target) $(target:S=.output) ; - - RUN_PATH on $(targets) = [ join $(gRUN_PATH($(executable))) : $(SPLITPATH) ] ; - if $(UNIX) - { - RUN_LD_LIBRARY_PATH on $(targets) = [ join $(gRUN_LD_LIBRARY_PATH($(executable))) : $(SPLITPATH) ] ; - } -} - - - -if $(UNIX) -{ - actions capture-run-output1 bind INPUT_FILES output-file - { - $(SHELL_SET)PATH=$(RUN_PATH:J=:):$PATH - $(SHELL_EXPORT)PATH - $(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH):$LD_LIBRARY_PATH - $(SHELL_EXPORT)LD_LIBRARY_PATH - $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<[1]) - } + ENV_PATH = %PATH% ; + CATENATE = type ; } else { - actions capture-run-output1 bind INPUT_FILES output-file - { - $(SHELL_SET)PATH=$(RUN_PATH:J=;);%PATH% - $(SHELL_EXPORT)PATH - $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<[1]) - } + ENV_PATH = $PATH ; + ENV_LD_LIBRARY_PATH = $LD_LIBRARY_PATH ; + CATENATE = cat ; } +rule capture-run-output1 ( target : executable ) +{ + output-file on $(target) = $(target:S=.output) ; + + # Make sure no confusing output about setting or exporting PATH or + # LD_LIBRARY_PATH is seen unless it is actually used. + local p = $(gRUN_PATH($(executable))) ; + if $(p) + { + RUN_PATH on $(target) = $(p) $(ENV_PATH) ; + PATH_VAR on $(target) = PATH ; + } + else + { + RUN_PATH on $(target) = ; + PATH_VAR on $(target) = ; + } + + p = $(gRUN_LD_LIBRARY_PATH($(executable))) ; + if $(NT) + { + RUN_LD_LIBRARY_PATH on $(target) = ; + LD_LIBRARY_PATH_VAR on $(target) = ; + } + else if $(p) + { + RUN_LD_LIBRARY_PATH on $(target) = $(p) $(ENV_LD_LIBRARY_PATH) ; + LD_LIBRARY_PATH_VAR on $(target) = LD_LIBRARY_PATH ; + } + execute-test $(target) : $(executable) ; +} + +RUN_OUTPUT_HEADER = "echo ====== BEGIN OUTPUT ====== &&" ; +RUN_OUTPUT_FOOTER = " && echo ====== END OUTPUT ======" ; +if --verbose-test in $(ARGV) +{ + VERBOSE_CAT = "&& "$(RUN_OUTPUT_HEADER)" "$(CATENATE)" " ; +} + +actions execute-test bind INPUT_FILES output-file +{ + $(SHELL_SET)PATH=$(RUN_PATH:J=$(SPLITPATH)) + $(SHELL_EXPORT)$(PATH_VAR) + $(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH:J=$(SPLITPATH)) + $(SHELL_EXPORT)$(LD_LIBRARY_PATH_VAR) + $(>) $(ARGS) $(INPUT_FILES) > $(output-file) 2>&1 && $(CP) $(output-file) $(<) $(VERBOSE_CAT)$(<)$(RUN_OUTPUT_FOOTER) || ( $(RUN_OUTPUT_HEADER) $(CATENATE) $(output-file) $(RUN_OUTPUT_FOOTER) && exit 1 ) +} + + declare-build-fail-test RUN_FAIL : RUN_TEST ; declare-build-succeed-test RUN : RUN_TEST ; rule run ( sources + : args * : input-files * : requirements * : name ? ) @@ -378,6 +355,12 @@ rule link-fail ( sources + : requirements * : name ? ) return [ boost-test $(<) : LINK_FAIL : $(2) : $(name) ] ; } +declare-build-succeed-test LINK : EXE ; +rule link ( sources + : requirements * : name ? ) +{ + return [ boost-test $(<) : LINK : $(2) : $(name) ] ; +} + ### Rules for grouping tests into suites: rule test-suite # pseudotarget-name : test-targets...