mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
411 lines
13 KiB
Plaintext
Executable File
411 lines
13 KiB
Plaintext
Executable File
# (C) Copyright David Abrahams 2002. Permission to copy, use, modify, sell and
|
|
# distribute this software is granted provided this copyright notice appears in
|
|
# all copies. This software is provided "as is" without express or implied
|
|
# warranty, and with no claim as to its suitability for any purpose.
|
|
if ! $(.testing.jam-included)
|
|
{
|
|
.testing.jam-included = "}" ; # The brace makes emacs indentation happy
|
|
|
|
|
|
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.
|
|
#
|
|
# type should be a target type (e.g. OBJ, DLL, LIB, EXE)
|
|
#
|
|
# RETURNS the name(s) of the generated test target(s).
|
|
rule boost-test ( sources + : target-type : requirements * : test-name ? : default-build * )
|
|
{
|
|
if ! $(gIN_LIB_INCLUDE) # No need to execute this code twice
|
|
{
|
|
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) <sysinclude>$(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) )
|
|
{
|
|
dump-test ;
|
|
}
|
|
}
|
|
|
|
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) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
# Helper for boost-test above. Uses dynamic scoping to access
|
|
# boost-test's locals.
|
|
local rule dump-test ( )
|
|
{
|
|
local srcs = [ on $(result) get-var-value source-files ] ;
|
|
|
|
# locate each source file
|
|
local source-files ;
|
|
for local s in $(srcs)
|
|
{
|
|
# find out where to look for the file
|
|
local paths = [ on $(s) get-var-value LOCATE SEARCH ] ;
|
|
|
|
s = $(s:G=) ; # strip grist
|
|
|
|
# build all the potential full paths of the file
|
|
local full-paths = $(s:R=$(paths)) ;
|
|
|
|
# look there
|
|
local files = [ GLOB $(full-paths:D) : $(s:D=) ] ;
|
|
|
|
if $(files)
|
|
{
|
|
# make relative to the project root instead of "."
|
|
local file = $(files[1]:R=$(SUBDIR_TOKENS:J=/) ;
|
|
|
|
# try to undo absolute paths
|
|
source-files += [ relative-path $(file) ] ;
|
|
}
|
|
}
|
|
|
|
# Extract values of the <test-info> feature
|
|
local dump-test-info = [ get-values <test-info> : $(requirements) ] ;
|
|
|
|
# Format them into a single string of quoted strings
|
|
dump-test-info = \"$(dump-test-info:J=\"\ \")\" ;
|
|
|
|
ECHO boost-test($(target-type)) \"$(test-name)\"
|
|
[$(dump-test-info)]
|
|
":" \"$(source-files)\"
|
|
;
|
|
|
|
}
|
|
|
|
|
|
#######
|
|
|
|
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 + )
|
|
{
|
|
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 + )
|
|
{
|
|
**passed** $(test-file) ;
|
|
DEPENDS $(test-file) : $(dependency) ;
|
|
}
|
|
|
|
rule declare-build-succeed-test ( test-type : dependency-type )
|
|
{
|
|
gGENERATOR_FUNCTION($(test-type)) = build-test succeeded-test-file ;
|
|
gDEPENDENCY_TYPE($(test-type)) = $(dependency-type) ;
|
|
SUF$(test-type) = $(BOOST_TEST_SUFFIX) ;
|
|
}
|
|
|
|
# A utility rule which declares test-type to be a target type which
|
|
# depends on the /failed/ construction of a target of type
|
|
# dependency-type.
|
|
rule declare-build-fail-test ( test-type : dependency-type )
|
|
{
|
|
gGENERATOR_FUNCTION($(test-type)) = build-test failed-test-file ;
|
|
gDEPENDENCY_TYPE($(test-type)) = $(dependency-type) ;
|
|
SUF$(test-type) = $(BOOST_TEST_SUFFIX) ;
|
|
}
|
|
|
|
# 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
|
|
# declare-build-fail-test, above.
|
|
rule build-test ( test-file-generator test-file + : sources + : requirements * )
|
|
{
|
|
# Get the target type of the current target out of the build properties
|
|
local target-type = [ get-values <target-type> : $(gBUILD_PROPERTIES) ] ;
|
|
|
|
# Get the type of target to attempt to build; the outcome of this
|
|
# attempt determines the result of the test.
|
|
local dependency-type = $(gDEPENDENCY_TYPE($(target-type))) ;
|
|
|
|
# Get the actual name of the target to attempt to build
|
|
local dependency = $(test-file[1]:S=$(SUF$(dependency-type))) ;
|
|
|
|
# record the source file names so we can put them in the .test
|
|
# file.
|
|
source-files on $(test-file) = $(sources) ;
|
|
|
|
# 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 = [
|
|
$(gGENERATOR_FUNCTION($(dependency-type))) $(dependency) : $(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
|
|
MakeLocate $(test-file) : $(LOCATE_TARGET) ;
|
|
Clean clean : $(test-file) ;
|
|
|
|
# Generate the test file
|
|
$(test-file-generator) $(test-file) : $(dependency) ;
|
|
}
|
|
|
|
### Rules for testing whether a file compiles ###
|
|
|
|
# Establish the rule which generates targets of type "OBJ". Should really go
|
|
# into basic build system, but wasn't needed 'till now.
|
|
gGENERATOR_FUNCTION(OBJ) = Object ;
|
|
declare-build-fail-test COMPILE_FAIL : OBJ ;
|
|
declare-build-succeed-test COMPILE : OBJ ;
|
|
|
|
# Test that the given source-file(s) compile
|
|
rule compile ( sources + : requirements * : test-name ? )
|
|
{
|
|
return [ boost-test $(sources) : COMPILE : $(requirements) : $(test-name) ] ;
|
|
}
|
|
|
|
# Test that the given source-file(s) fail to compile
|
|
rule compile-fail ( sources + : requirements * : test-name ? )
|
|
{
|
|
return [ boost-test $(sources) : COMPILE_FAIL : $(requirements) : $(test-name) ] ;
|
|
}
|
|
|
|
|
|
### Rules for testing whether a program runs ###
|
|
|
|
gGENERATOR_FUNCTION(RUN_TEST) = run-test ;
|
|
SUFRUN_TEST = .run ;
|
|
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) ;
|
|
# Move important data from the test target to the executable
|
|
gRUN_LD_LIBRARY_PATH($(executable)) = $(gRUN_LD_LIBRARY_PATH($(parent))) ;
|
|
gRUN_PATH($(executable)) = $(gRUN_PATH($(parent))) ;
|
|
|
|
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
|
|
local LOCATE_TARGET = [ FDirName [ split-path $(LOCATE_TARGET) ] ] ;
|
|
MakeLocate $(target) : $(LOCATE_TARGET) ;
|
|
|
|
DEPENDS $(target) : $(executable) $(gRUN_TEST_INPUT_FILES) ;
|
|
INPUT_FILES on $(target) = $(gRUN_TEST_INPUT_FILES) ;
|
|
ARGS on $(target) = $(gRUN_TEST_ARGS) ;
|
|
capture-run-output $(target) : $(executable) ;
|
|
}
|
|
|
|
# The rule is just used for argument checking
|
|
rule capture-run-output ( target : executable + )
|
|
{
|
|
gTEST_OUTPUT_FILE($(target)) = $(target:S=.output) ;
|
|
INCLUDES $(target) : $(target:S=.output) ;
|
|
MakeLocate $(test-file:S=.output) : $(LOCATE_TARGET) ;
|
|
Clean clean $(test-file:S=.output) ;
|
|
capture-run-output1 $(target) : $(executable) ;
|
|
}
|
|
|
|
if $(NT)
|
|
{
|
|
ENV_PATH = %PATH% ;
|
|
CATENATE = type ;
|
|
}
|
|
else
|
|
{
|
|
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 ? : default-build * )
|
|
{
|
|
local gRUN_TEST_ARGS = $(args) ;
|
|
local gRUN_TEST_INPUT_FILES = $(input-files) ;
|
|
SEARCH on $(input-files) = $(LOCATE_SOURCE) ;
|
|
return [ boost-test $(sources) : RUN : $(requirements) : $(name) : $(default-build) ] ;
|
|
}
|
|
|
|
rule run-fail ( sources + : args * : input-files * : requirements * : name ? )
|
|
{
|
|
local gRUN_TEST_ARGS = $(2) ;
|
|
local gRUN_TEST_INPUT_FILES = $(3) ;
|
|
SEARCH on $(3) = $(LOCATE_SOURCE) ;
|
|
return [ boost-test $(<) : RUN_FAIL : $(4) : $(name) ] ;
|
|
}
|
|
|
|
### Rules for testing whether a program links
|
|
|
|
declare-build-fail-test LINK_FAIL : EXE ;
|
|
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...
|
|
{
|
|
NOTFILE $(<) ;
|
|
type-DEPENDS $(<) : $(>) ;
|
|
}
|
|
|
|
} # include guard
|
|
|