Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/v1/testing.jam @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

  • Property svn:executable set to *
File size: 17.9 KB
Line 
1#  (C) Copyright David Abrahams 2002.
2# Distributed under the Boost Software License, Version 1.0.
3# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
4
5if ! $(.testing.jam-included)
6{
7.testing.jam-included = "}" ; # The brace makes emacs indentation happy
8
9# Decide which toolsets should be treated like an ordinary (unix) GCC installation
10gcc-compilers = [ MATCH ^(gcc.*)$ : $(TOOLS) ] ;
11mingw-compilers = [ MATCH ^(mingw.*)$ ^(gcc-nocygwin.*) : $(TOOLS) ] ;
12gcc-compilers = [ difference $(gcc-compilers) : $(mingw-compilers) ] ;
13
14local rule get-var-value ( name + )
15{
16    return $($(name)) ;
17}
18
19local rule get-library-name ( path_or_tokens + )
20{
21    local path = $(path_or_tokens) ;
22    if ! $(path[1]) { path = [ split-path $(path) ] ; }
23    path = /$(path:J=/) ;
24
25    local match1 = [ MATCH /libs/(.*)/(test|example) : $(path) ] ;
26    local match2 = [ MATCH /libs/(.*)$ : $(path) ] ;
27    local match3 = [ MATCH (/status$) : $(path) ] ;
28
29    if $(match1) { return $(match1[0]) ; }
30    else if $(match2) { return $(match2[0]) ; }
31    else if $(match3) { return "" ; }
32    else if --dump-tests in $(ARGV)
33    {
34        EXIT Cannot extract library name from path $(path) ;
35    }
36}
37
38# Declares a test target. If name is not supplied, it is taken from the name of
39# the first source file, sans extension and directory path.
40#
41# type should be a target type (e.g. OBJ, DLL, LIB, EXE)
42#
43# RETURNS the name(s) of the generated test target(s).
44rule boost-test ( sources + : target-type : requirements * : test-name ? : default-build * )
45{
46    if ! $(gIN_LIB_INCLUDE) # No need to execute this code twice
47    {
48        local result ;
49        {
50            # manufacture a test name if none supplied explicitly
51            test-name ?= $(sources[1]:D=:S=) ;
52           
53            local library = "" ;
54            if $(SUBDIR_TOKENS) { library = [ get-library-name $(SUBDIR_TOKENS) ] ; }
55           
56            # Make sure that targets don't become part of "all"
57            local gSUPPRESS_FAKE_TARGETS = true ;
58           
59            result = [
60              declare-local-target $(test-name)
61                : $(sources)
62                  : $(requirements) <sysinclude>$(BOOST_ROOT)
63                    : $(default-build)
64                      : $(target-type)
65            ] ;
66           
67            if $(result) && $(result) in $(.all-boost-tests)
68            {
69                EXIT boost-test \"$(result)\" declared twice ;
70                .all-boost-tests += $(result) ;
71            }
72           
73            if --dump-tests in $(ARGV) && $(result)
74            {
75                dump-test $(library) : $(result) : $(requirements) ;
76            }
77        }
78       
79        Clean clean : $(result) ;
80       
81        # make NOTFILE targets of the same base name as the sources which can
82        # be used to build a single test.
83        type-DEPENDS $(sources:B:S=) : $(result) ;
84       
85        # The NOTFILE target called "test" builds all tests
86        type-DEPENDS test : $(result) ;
87       
88        # Make sure the test result doesn't hang around if the test fails
89        RMOLD $(result) ;
90       
91        return $(result) ;
92    }
93}
94
95
96
97
98# Helper for boost-test above.  Uses dynamic scoping to access
99# boost-test's locals.
100local rule dump-test ( library ? : targets + : requirements * )
101{
102    local srcs = [ on $(targets) get-var-value source-files ] ;
103   
104    # Pick any source file names off the associated main target as well.
105    srcs += [ unique [ on $(gTARGET_SUBVARIANT($(targets))) get-var-value source-files ] ] ;
106   
107    local pwd = [ PWD ] ;
108   
109    # locate each source file
110    local source-files ;
111    for local s in $(srcs)
112    {
113        # find out where to look for the file
114        local paths = [ on $(s) get-var-value LOCATE SEARCH ] ;
115       
116        s = $(s:G=) ; # strip grist
117       
118        # build all the potential full paths of the file
119        local full-paths = $(s:R=$(paths)) ;
120       
121        # look there
122        local files = [ GLOB $(full-paths:D) : $(s:D=) ] ;
123       
124        if $(files)
125        {
126            # make relative to the project root instead of "."
127            local file = $(files[1]:R=$(pwd)) ;
128           
129            # try to undo absolute paths
130            source-files += [ relative-path  $(file) ] ;
131        }
132    }
133
134    # Extract values of the <test-info> feature
135    local dump-test-info = [ get-values <test-info> : $(requirements) ] ;
136   
137    # Format them into a single string of quoted strings
138    dump-test-info = \"$(dump-test-info:J=\"\ \")\" ;
139   
140    local test-id  ; # unique among all tests
141   
142    if $(library)
143        {
144        test-id = $(library)/$(test-name) ;
145        }
146    else
147        {
148        test-id = $(test-name) ;
149        }
150
151    ECHO boost-test($(target-type)) \"$(test-id)\"
152      [$(dump-test-info)]
153        ":" \"$(source-files)\"
154          ;
155   
156    if --dump-test-targets in $(ARGV)
157    {
158        ECHO boost-test(TARGET)
159            \"$(test-id)\" [$(dump-test-info)] ":"
160            \"$(targets)\"
161            ;
162    }
163}
164
165
166#######
167
168BOOST_TEST_SUFFIX ?= .test ;
169
170# Set a variable which says how to dump a file to stdout
171if $(NT)
172{
173    CATENATE = type ;
174}
175else
176{
177    CATENATE = cat ;
178}
179
180actions **passed** bind source-files
181{
182    echo $(source-files) > $(<)
183}
184
185actions (failed-as-expected)
186{
187    echo failed as expected > $(<)
188}
189
190# a utility rule which causes test-file to be built successfully only if
191# dependency fails to build. Used for expected-failure tests.
192rule failed-test-file ( test-file : dependency + )
193{
194    local grist = [ MATCH ^<(.*)> : $(dependency:G) ] ;
195    local marker = $(dependency:G=$(grist)*fail) ;
196    (failed-as-expected) $(marker) ;
197    FAIL_EXPECTED $(dependency) ;
198    MakeLocate $(marker) : $(LOCATE_TARGET) ;
199    RMOLD $(marker) ;
200    DEPENDS $(marker) : $(dependency) ;
201   
202    succeeded-test-file $(test-file) : $(marker) ;
203}
204
205# a utility rule which causes test-file to be built successfully only if
206# dependency builds. Used for expected-success tests.
207rule succeeded-test-file ( test-file : dependency + )
208{
209    **passed** $(test-file) ;
210    DEPENDS $(test-file) : $(dependency) ;
211}
212
213rule declare-build-succeed-test ( test-type : dependency-type )
214{
215    gGENERATOR_FUNCTION($(test-type)) = build-test succeeded-test-file ;
216    gDEPENDENCY_TYPE($(test-type)) = $(dependency-type) ;
217    SUF$(test-type) = $(BOOST_TEST_SUFFIX) ;
218}
219
220# A utility rule which declares test-type to be a target type which
221# depends on the /failed/ construction of a target of type
222# dependency-type.
223rule declare-build-fail-test ( test-type : dependency-type )
224{
225    gGENERATOR_FUNCTION($(test-type)) = build-test failed-test-file ;
226    gDEPENDENCY_TYPE($(test-type)) = $(dependency-type) ;
227    SUF$(test-type) = $(BOOST_TEST_SUFFIX) ;
228}
229
230# When the appropriate generator function is bound to the
231# test-file-generator argument, this is a target generator function
232# for target types declared with declare-build-succeed-test and
233# declare-build-fail-test, above.
234rule build-test ( test-file-generator test-file + : sources * : requirements * )
235{
236    # Get the target type of the current target out of the build properties
237    local target-type = [ get-values <target-type> : $(gBUILD_PROPERTIES) ] ;
238
239    # Get the type of target to attempt to build; the outcome of this
240    # attempt determines the result of the test.
241    local dependency-type = $(gDEPENDENCY_TYPE($(target-type))) ;
242   
243    # Get the actual name of the target to attempt to build
244    local dependency = $(test-file[1]:S=$(SUF$(dependency-type))) ;
245
246    # record the source file names so we can put them in the .test
247    # file.
248    source-files on $(test-file) = $(sources) ;
249   
250    # Make sure that the test-file is erased upon failure, so as not
251    # to give a false indication of success.
252    RMOLD $(test-file) ;
253   
254    # Call dependency-type's generator function to attempt the build
255    $(gGENERATOR_FUNCTION($(dependency-type))) $(dependency) : $(sources) : $(requirements) ;
256
257    # Generator functions don't handle this job for us; perhaps they should.
258    set-target-variables $(dependency) ;
259   
260    if $(test-file:S) != $(BOOST_TEST_SUFFIX)
261    {
262        EXIT unexpected test file suffix. Filename: $(test-file) ;
263    }
264   
265    # The test files go with the other subvariant targets
266    MakeLocate $(test-file) : $(LOCATE_TARGET) ;
267    Clean clean : $(test-file) ;
268   
269    # Generate the test file
270    $(test-file-generator) $(test-file) : $(dependency) ;
271}
272
273### Rules for testing whether a file compiles ###
274
275# Establish the rule which generates targets of type "OBJ". Should really go
276# into basic build system, but wasn't needed 'till now.
277gGENERATOR_FUNCTION(OBJ) = Object ;
278declare-build-fail-test COMPILE_FAIL : OBJ ;
279declare-build-succeed-test COMPILE : OBJ ;
280
281# Test that the given source-file(s) compile
282rule compile ( sources + : requirements * : test-name ? )
283{
284    return [ boost-test $(sources) : COMPILE : $(requirements) : $(test-name) ] ;
285}
286
287# Test that the given source-file(s) fail to compile
288rule compile-fail ( sources + : requirements * : test-name ? )
289{
290    return [ boost-test $(sources) : COMPILE_FAIL : $(requirements) : $(test-name) ] ;
291}
292
293
294### Rules for testing whether a program runs ###
295
296gGENERATOR_FUNCTION(TEST_EXE) = run-test EXE  ;
297SUFTEST_EXE = .run ;
298
299rule test-executable(EXE) ( target-to-test )
300{
301    return $(target-to-test) ;
302}
303
304rule nt-paths-to-cygwin ( paths * )
305{
306    local result ;
307    for local p in $(paths)
308    {
309        # if already rooted...
310        if [ MATCH ^([A-Za-z]:[/\\]) : $(p) ]
311        {
312            p = [ split-path $(p) ] ;
313            p = [ join-path /cygdrive [ MATCH ^(.).* : $(p[1]) ] $(p[2-]) ] ;
314        }
315        result += $(p:T) ;
316    }
317    return $(result) ;
318}
319
320rule run-test ( type-to-test run-target : sources * )
321{
322    local parent = $(run-target:S=.test) ;
323    local targets-to-test ;
324    local main-target = $(gTARGET_SUBVARIANT($(parent))) ;
325   
326    # If no sources, assume someone else already built the targets,
327    # and they are the library dependencies of the test target that
328    # match the type-to-test.  This should perhaps be _all_
329    # dependencies, but hopefully we'll throw this code out soon!
330    if ! $(sources)
331    {
332        for local t in [ on $(parent) return $(library-dependencies) ]
333        {
334            if $(gTARGET_TYPE($(t))) = $(type-to-test)
335            {
336                targets-to-test += $(t) ;
337            }
338        }
339    }
340    else
341    {
342        targets-to-test = $(run-target:S=$(SUF$(type-to-test))) ;
343       
344        set-target-variables $(targets-to-test) ;
345       
346        generate-dependencies $(main-target) : $(targets-to-test) ;
347       
348        declare-basic-target $(targets-to-test) : $(sources) : : : $(type-to-test) ;
349        $(gGENERATOR_FUNCTION($(type-to-test))) $(targets-to-test) : $(sources) ;
350    }
351   
352    # The .test file goes with the other subvariant targets
353    # normalization is a hack to get the slashes going the right way on Windoze
354    local LOCATE_TARGET = [ FDirName [ split-path $(LOCATE_TARGET) ] ] ;
355    MakeLocate $(run-target) : $(LOCATE_TARGET) ;
356   
357    local executable = [ test-executable($(type-to-test)) $(targets-to-test) ] ;
358    local x-input-files = [ expand-source-names $(gRUN_TEST_INPUT_FILES) ] ;
359    local x-input-deps = ;
360    for local x-input-file in $(x-input-files)
361    {
362        local input-file-type = [ ungrist $(x-input-file:G:L) ] ;
363        local input-file-type-id = $(gTARGET_TYPE_ID($(input-file-type))) ;
364        local input-file-typed = $(x-input-file:G=$(input-file-type-id)) ;
365       
366        if $(input-file-typed)
367        {
368            dependent-include $(input-file-typed) ;
369       
370            local input-file-path = [ target-path-of $(input-file-typed) ] ;
371            local input-file-target = [ target-id-of $(input-file-path) ] ;
372           
373            local [ protect-subproject ] ;
374            enter-subproject [ directory-of $(input-file-path) ] ;
375           
376            local p = $(gBUILD_PROPERTIES) ;
377            segregate-free-properties p ;
378            local input-file-subvariant = [
379                find-compatible-subvariant $(input-file-target)
380                    : $(gCURRENT_TOOLSET) $(variant)
381                    : $(p) ] ;
382            local input-file-dep = [
383                subvariant-target $(input-file-target)
384                    : $(input-file-subvariant)
385                    : $(gCURRENT_TOOLSET) $(variant) ] ;
386            x-input-deps += $(input-file-dep) ;
387        }
388        else
389        {
390            x-input-deps += $(x-input-file) ;
391        }
392    }
393    DEPENDS $(run-target) : $(executable) $(targets-to-test) $(x-input-deps) ;
394    INPUT_FILES on $(run-target) = $(x-input-deps) ;
395    ARGS on $(run-target) = $(gRUN_TEST_ARGS) ;
396    ARGS2 on $(run-target) = $(gRUN_TEST_ARGS2) ;
397   
398    #
399    # Prepare path setup
400    #
401    local path-sources = $(parent) $(executable) ;  # where do we get paths from?
402    local $(.run-path-shell-vars) ;                 # declare local path variables
403   
404    # initialize path variables from the path-sources
405    for local v in $(.run-path-vars)
406    {
407        local shell-var = $(.shell-var($(v))) ;
408        $(shell-var) = [ unique $($(shell-var)) $(gRUN_$(v)($(path-sources))) ] ;
409    }
410   
411    local nt-cygwin ;
412    if $(NT) && $(gCURRENT_TOOLSET) in $(gcc-compilers)
413    {
414        nt-cygwin = true ;
415    }
416
417    # build up a fragment of shell command
418    local path-setup ;
419    for local shell-var in $(.run-path-shell-vars)
420    {
421        if $($(shell-var))
422        {
423            local dirs = $($(shell-var)) ;
424            local splitpath = $(SPLITPATH) ;
425           
426            # PATH gets translated automatically; the rest must be
427            # cygwin-native when running with Cygwin GCC under NT
428            if $(nt-cygwin) && $(shell-var) != PATH
429            {
430                dirs = [ nt-paths-to-cygwin $(dirs) ] ;
431                splitpath = ":" ;
432            }
433           
434            if $(.run-path-shell-var-value($(shell-var)))
435            {
436                dirs += $(.env-prefix)$(shell-var)$(.env-suffix) ;
437            }
438           
439            path-setup += $(SHELL_SET)$(shell-var)=$(dirs:J=$(splitpath)) ;
440            path-setup += $(SHELL_EXPORT)$(shell-var) ;
441        }
442    }
443   
444    local debugger = [ MATCH ^--debugger=(.*) : $(ARGV) ] ;
445    debugger = $(debugger)" " ;
446    local newline = "
447" ;
448    PATH_SETUP on $(run-target) = $(path-setup:J=$(newline):E=)$(newline)$(debugger:E=) ;
449    local verbose-test = 1 ;
450    if --verbose-test in $(ARGV)
451    {
452        verbose-test = 0 ;
453    }
454   
455    VERBOSE_TEST on $(run-target) = $(verbose-test) ;
456    if $(NT)
457    {
458        STATUS on $(run-target) = %status% ;
459        SET_STATUS on $(run-target) = "set status=%ERRORLEVEL%" ;
460        RUN_OUTPUT_NL on $(run-target) = "echo." ;
461        STATUS_0 on $(run-target) = "%status% EQU 0 (" ;
462        STATUS_NOT_0 on $(run-target) = "%status% NEQ 0 (" ;
463        VERBOSE on $(run-target) = "%verbose% EQU 0 (" ;
464        ENDIF on $(run-target) = ")" ;
465    }
466    else
467    {
468        STATUS on $(run-target) = "$status" ;
469        SET_STATUS on $(run-target) = "status=$?" ;
470        RUN_OUTPUT_NL on $(run-target) = "echo" ;
471        STATUS_0 on $(run-target) = "test $status -eq 0 ; then" ;
472        STATUS_NOT_0 on $(run-target) = "test $status -ne 0 ; then" ;
473        VERBOSE on $(run-target) = "test $verbose -eq 0 ; then" ;
474        ENDIF on $(run-target) = "fi" ;
475    }
476   
477    capture-run-output $(run-target) : $(executable) : $(debugger) ;
478
479    if ! ( --preserve-test-targets in $(ARGV) ) && ! [ MATCH ^--debugger=(.*) : $(ARGV) ]
480    {
481        RmTemps $(run-target) : $(targets-to-test) ;
482    }
483}
484
485# The rule is just used for argument checking
486rule capture-run-output ( target : executable + : debugger ? )
487{
488    gTEST_OUTPUT_FILE($(target)) = $(target:S=.output) ;
489    INCLUDES $(target) : $(target:S=.output) ;
490    MakeLocate $(test-file:S=.output) : $(LOCATE_TARGET) ;
491    Clean clean : $(test-file:S=.output) ;
492    output-file on $(target) = $(target:S=.output) ;
493    if $(debugger)
494    {
495        debug-test $(target) : $(executable) ;
496    }
497    else
498    {
499        execute-test $(target) : $(executable) ;
500    }
501
502    if --run-all-tests in $(ARGV)
503    {
504        ALWAYS $(target) ;
505    }
506}
507
508if $(NT)
509{
510    CATENATE = type ;
511}
512else
513{
514    CATENATE = cat ;
515}
516
517actions debug-test bind INPUT_FILES
518{
519    $(PATH_SETUP)$(>) $(ARGS) "$(INPUT_FILES)" $(ARGS2)
520}
521
522actions execute-test bind INPUT_FILES output-file
523{
524    $(PATH_SETUP)$(>) $(ARGS) "$(INPUT_FILES)" $(ARGS2) > $(output-file) 2>&1
525    $(SET_STATUS)
526    $(RUN_OUTPUT_NL) >> $(output-file)
527    echo EXIT STATUS: $(STATUS) >> $(output-file)
528    if $(STATUS_0)
529        $(CP) $(output-file) $(<)
530    $(ENDIF)
531    $(SHELL_SET)verbose=$(VERBOSE_TEST)
532    if $(STATUS_NOT_0)
533        $(SHELL_SET)verbose=0
534    $(ENDIF)
535    if $(VERBOSE)
536        echo ====== BEGIN OUTPUT ======
537        $(CATENATE) $(output-file)
538        echo ====== END OUTPUT ======
539    $(ENDIF)
540    exit $(STATUS)
541}
542
543
544declare-build-fail-test RUN_FAIL : TEST_EXE ;
545declare-build-succeed-test RUN : TEST_EXE ;
546rule run ( sources + : args * : input-files * : requirements * : name ? : default-build * : args2 * )
547{
548    local gRUN_TEST_ARGS = $(args) ;
549    local gRUN_TEST_ARGS2 = $(args2) ;
550    local gRUN_TEST_INPUT_FILES = $(input-files) ;
551    SEARCH on $(input-files) = $(SEARCH_SOURCE) ;
552    return [ boost-test $(sources) : RUN : $(requirements) : $(name) : $(default-build) ] ;
553}
554
555rule run-fail ( sources + : args * : input-files * : requirements * : name ? )
556{
557    local gRUN_TEST_ARGS = $(2) ;
558    local gRUN_TEST_INPUT_FILES = $(3) ;
559    SEARCH on $(3) = $(SEARCH_SOURCE) ;
560    return [ boost-test $(<) : RUN_FAIL : $(4) : $(name) ] ;
561}
562
563### Rules for testing whether a program links
564
565declare-build-fail-test LINK_FAIL : EXE ;
566rule link-fail ( sources + : requirements * : name ? )
567{
568    return [ boost-test $(<) : LINK_FAIL : $(2) : $(name) ] ;
569}
570
571declare-build-succeed-test LINK : EXE ;
572rule link ( sources + : requirements * : name ? )
573{
574    return [ boost-test $(<) : LINK : $(2) : $(name) ] ;
575}
576
577### Rules for grouping tests into suites:
578
579rule test-suite # pseudotarget-name : test-targets...
580{
581    NOTFILE $(<) ;
582    type-DEPENDS $(<) : $(>) ;
583}
584
585} # include guard
586
Note: See TracBrowser for help on using the repository browser.