# file : tests/recipe/buildscript/testscript # license : MIT; see accompanying LICENSE file posix = ($cxx.target.class != 'windows') +mkdir build +cat <=build/bootstrap.build project = test amalgamation = subprojects = using config using test EOI +cat <=build/root.build EOI : update : { : success : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} EOI $* 2>'cp file{bar} -> file{foo}'; cat <<'bar'; # While at it, make sure there is no rebuild. # $* 2>/'info: dir{./} is up to date'; $* clean 2>- } : error : : Test that the target file is removed on error and is created on subsequent : successful update. : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ diag concat $< t = $path($>) p = $path($<) cp $p $t cat $(p).baz >>$t }} EOI $* 2>>~%EOE% != 0; concat file{bar} %cat: unable to print '.+bar.baz': .+% buildfile:10:3: error: builtin cat exited with code 1 %.+ EOE test -f foo != 0; echo 'baz' >=bar.baz; $* 2>'concat file{bar}'; cat <<>EOO; bar baz EOO $* clean 2>- } : mutual-redirects : { echo 'bar' >=bar; cat <=buildfile; foo: bar % [diag=cp] {{ echo 'copying' 2>&1 cp $path($<) $path($>) }} EOI $* 2>>~%EOE% != 0; cp file{bar} -> file{foo} buildfile:4:3: error: stdout and stderr redirected to each other %.+ EOE $* clean 2>- } : computed-var : { cat <=buildfile; a = a b = b foo: {{ x = true echo "$($x ? a : b)" >$path($>) }} EOI $* 2>>EOE != 0 buildfile:6:10: error: expansion of computed variable is only allowed in depdb preamble info: consider using 'depdb' builtin to track its value changes EOE } : untracked-var : { cat <=buildfile; a = a b = b foo: {{ x = true y = $($x ? a : b) depdb env BOGUS echo $y >$path($>) }} EOI $* 2>>~%EOE% != 0; buildfile:6:8: error: use of untracked variable 'a' info: use the 'depdb' builtin to manually track it %.+ EOE $* clean 2>- } : export : if $posix { cat <=bar; #!/bin/sh echo "$message" EOI cat <=buildfile; exe{foo}: bar {{ cp $path($<) $path($>) }} % test {{ diag test $> export message=text1 $> >>>?'text1' env message=text2 -- $> >>>?'text2' }} EOI $* test 2>>EOE; cp file{bar} -> exe{foo} test exe{foo} EOE $* clean 2>- } : diag : { cat <=buildfile; foo: {{ v1 = foo echo bar | set v2 diag echo "$v1 $v2" -> $> echo "$v1 $v2" >$path($>) }} EOI $* 2>'echo foo bar -> file{foo}'; cat <<'foo bar'; $* clean 2>- } : depdb : { : track-var-auto : { echo 'bar' >=bar; cat <=buildfile; s = $process.run(cat bar) foo: {{ echo "$s" >$path($>) }} EOI $* 2>'echo file{foo}'; cat <<'bar'; $* 2>/'info: dir{./} is up to date'; echo 'baz' >=bar; $* 2>'echo file{foo}'; cat <<'baz'; $* clean 2>- } : track-var-manual : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; a = $process.run(cat baz) foo: bar {{ x = true y = $($x ? a : b) depdb hash "$a" diag compose $> cp $path($<) $path($>) echo $y >>$path($>) }} EOI $* 2>'compose file{foo}'; cat <<>EOO; bar baz EOO $* 2>/'info: dir{./} is up to date'; # Make sure that on filesystems with a low file timestamps resolution # (for example HFS+) the file is considered as changed. # sleep 1; echo 'BAR' >=bar; $* 2>'compose file{foo}'; cat <<>EOO; BAR baz EOO $* 2>/'info: dir{./} is up to date'; echo 'BAZ' >=baz; $* 2>'compose file{foo}'; cat <<>EOO; BAR BAZ EOO $* 2>/'info: dir{./} is up to date'; $* clean 2>- } : preamble : { : valid : { echo 'bar' >=bar; cat <=buildfile; s = $process.run(cat bar) foo: {{ depdb clear s1 = 'abc' s2 = 'xyz' if echo "$s" >>>? 'bar' v = "$s1" else echo "$s2" | set v end depdb string "$v" echo "$v" >$path($>) }} EOI $* 2>'echo file{foo}'; cat <<'abc'; $* 2>/'info: dir{./} is up to date'; echo 'baz' >=bar; $* 2>'echo file{foo}'; cat <<'xyz'; $* clean 2>- } : invalid : { cat <=buildfile; foo: {{ v = 'abc' echo "$v" >$path($>) depdb string "$v" }} EOI $* 2>>~%EOE% != 0; buildfile:4:3: error: disallowed command in depdb preamble info: only variable assignments are allowed in depdb preamble buildfile:5:3: info: depdb preamble ends here %.+ EOE $* clean 2>- } : temp-dir : { cat <=buildfile; foo: {{ touch $~/f | set dummy if test -f $~/f v = "yes" else v = "no" end depdb string "$v" diag echo $> test -f $~/f echo "$v" >$path($>) }} EOI $* 2>'echo file{foo}'; $* clean 2>- } } : string : { echo 'bar' >=bar; cat <=buildfile; s = $process.run(cat bar) foo: {{ depdb clear depdb string "$s" echo "$s" >$path($>) }} EOI $* 2>'echo file{foo}'; cat <<'bar'; $* 2>/'info: dir{./} is up to date'; echo 'baz' >=bar; $* 2>'echo file{foo}'; cat <<'baz'; $* clean 2>- } : hash : { echo 'bar' >=bar; cat <=buildfile; s = $process.run(cat bar) foo: {{ depdb clear depdb hash "$s" echo "$s" >$path($>) }} EOI $* 2>'echo file{foo}'; cat <<'bar'; $* 2>/'info: dir{./} is up to date'; echo 'baz' >=bar; $* 2>'echo file{foo}'; cat <<'baz'; $* clean 2>- } : env : { : invalid : { cat <=buildfile; foo: {{ s = $getenv(FOO) depdb clear depdb env FOO=bar echo "$s" >$path($>) }} EOI $* 2>>/EOE != 0; buildfile:6:3: error: invalid 'depdb env' argument: invalid variable name 'FOO=bar': contains '=' info: while updating file{foo} info: while updating dir{./} info: failed to update dir{./} EOE $* clean 2>- } : valid : { cat <=buildfile; foo: {{ s = $getenv(FOO) depdb clear depdb env FOO echo "$s" >$path($>) }} EOI export FOO=foo; $* 2>'echo file{foo}'; cat <<'foo'; $* 2>/'info: dir{./} is up to date'; export FOO=bar; $* 2>'echo file{foo}'; cat <<'bar'; export -u FOO; $* 2>'echo file{foo}'; cat <<''; $* clean 2>- } } : dyndep : { : normal : { cat <=bar.h; bar EOI cat <=buildfile; define h: file h{*}: extension = h ./: h{foo baz} h{foo}: {{ # Note that strictly speaking we should return $out_base/baz.h # on the second invocation (since it now exists). But our dyndep # machinery skips the entry which it has already seen, so this # works for now. # depdb dyndep "-I$out_base" --what=header --default-type=h -- \ echo "$out_base/foo.h: $src_base/bar.h baz.h" diag gen $> cat $path($<) >$path($>) }} h{baz}: {{ diag gen $> echo baz >$path($>) }} EOI $* 2>>EOE; gen h{baz} gen h{foo} EOE cat foo.h >>EOO; bar baz EOO $* clean 2>- } : byproduct : { cat <=bar.h; bar EOI cat <=buildfile; define h: file h{*}: extension = h h{foo}: h{baz} {{ o = $path($>) t = $path($>).t depdb dyndep --byproduct --what=header --default-type=h --file $t diag gen $> cat $src_base/bar.h $out_base/baz.h >$o echo "$out_base/foo.h: $src_base/bar.h $out_base/baz.h" >$t }} h{baz}: {{ diag gen $> echo baz >$path($>) }} EOI $* 2>>EOE; gen h{baz} gen h{foo} EOE cat foo.h >>EOO; bar baz EOO $* clean 2>- } } } } : clean : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} % [diag=clean] clean {{ t = $path($>) rm $t $(t).d }} EOI $* 2>-; # Rely on the cleanup machinery to verify that the build output files are # removed. # $* clean 2>'clean file{foo}' } : test : { : success : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} % [diag=test] test {{ cat <$path($>) >?$path($<) }} EOI $* test 2>>EOE; cp file{bar} -> file{foo} test file{foo} EOE $* clean 2>- } : depdb : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} % [diag=test] test {{ depdb clear cat <$path($>) >?$path($<) }} EOI $* test 2>>EOE != 0 buildfile:7:3: error: 'depdb' builtin cannot be used to perform test EOE } : runner : if $posix { echo 'bar' >=bar; cat <=run; #!/bin/sh if test "$1" = "--trace"; then shift echo "$*" fi "$@" EOI chmod u+x run; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} % [diag=test] test {{ if ($test.runner.path != [null]) $test.runner.path $test.runner.options cat <$path($>) else cat <$path($>) end }} EOI $* test 2>>EOE; cp file{bar} -> file{foo} test file{foo} bar EOE $* test config.test.runner="./run --trace" 2>>EOE; test file{foo} cat bar EOE $* clean 2>- } } : diff-label : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ echo 'baz' >? $path($<) }} EOI $* 2>>/~%EOE% != 0; %.+ %--- .+/bar% +++ stdout %.+ EOE $* clean 2>- } : canned-cmdline : { cat <=buildfile; ./: {{ x = echo >| y = [cmdline] echo >| diag update $> $x foo $y bar ([cmdline] $x) baz }} EOI $* >> EOO 2>>/EOE bar baz EOO update dir{./} >| foo EOE } : timeout : if $posix { : update : { : expired : { echo 'bar' >=bar; cat <=buildfile; foo: bar % [diag=update] {{ cp $path($<) $path($>) timeout 1 ^sleep 5 }} EOI $* 2>>~%EOE% != 0; update file{bar} -> file{foo} buildfile:6:3: error: process ^sleep terminated: execution timeout expired info: command line: sleep 5 info: while updating file{foo} %.+ EOE $* clean 2>- } : successful-timeout : { echo 'bar' >=bar; cat <=buildfile; foo: bar % [diag=update] {{ cp $path($<) $path($>) timeout --success 1 ^sleep 5 }} EOI $* 2>>EOE; update file{bar} -> file{foo} EOE $* clean 2>- } } : test : { : expired : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ cp $path($<) $path($>) }} % [diag=test] test {{ ^sleep 5 }} EOI $* test config.test.timeout=1 2>>~%EOE% != 0; cp file{bar} -> file{foo} test file{foo} buildfile:7:3: error: process ^sleep terminated: execution timeout expired info: command line: sleep 5 info: while testing file{foo} %.+ EOE $* test config.test.timeout=/1 2>>~%EOE% != 0; test file{foo} buildfile:7:3: error: process ^sleep terminated: execution timeout expired info: command line: sleep 5 info: while testing file{foo} %.+ EOE $* clean 2>- } : not-expired : { echo 'bar' >=bar; cat <=buildfile; foo: bar % [diag=cp] {{ ^sleep 4 cp $path($<) $path($>) }} % [diag=test] test {{ ^sleep 1 }} EOI $* test config.test.timeout=3 2>>EOE; cp file{bar} -> file{foo} test file{foo} EOE $* clean 2>- } } } # @@ TODO: test $1 when implemented. # : rule : { cat <=buildfile; alias{far}: alias{bar} alias{bar}: alias{~'/f(.+)/'}: alias{~'/b\1/'} {{ diag frob $< -> $> }} EOI $* 2>>EOE frob alias{bar} -> alias{far} EOE } : loop : { : while : { : basics : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ p = $path($>) while test -f $p != 0 cp $path($<) $p end }} EOI $* 2>'cp file{bar} -> file{foo}'; cat <<'bar'; $* clean 2>- } : exit : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) while test -f $p != 0 touch $p exit cp $path($<) $p end }} EOI $* 2>'gen file{foo}'; cat <<:''; $* clean 2>- } : error : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) while test -f $p != 0 touch $p exit 'fed up' cp $path($<) $p end }} EOI $* 2>>~%EOE% != 0; gen file{foo} buildfile:8:5: error: fed up %.{3} EOE $* clean 2>- } : depdb : { : inside : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ p = $path($>) while test -f $p != 0 depdb hash $p cp $path($<) $p end }} EOI $* 2>>EOE != 0 buildfile:5:5: error: 'depdb' call inside flow control construct EOE } : after-commands : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ p = $path($>) while test -f $p != 0 cp $path($<) $p end depdb hash $p }} EOI $* 2>>~%EOE% != 0; buildfile:5:5: error: disallowed command in depdb preamble info: only variable assignments are allowed in depdb preamble buildfile:8:3: info: depdb preamble ends here %.{3} EOE $* clean 2>- } : after-vars : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ p = $path($<) h = while test -f $p != 0 h += $p end depdb hash $p cat $p >$path($>) }} EOI $* 2>'cat file{bar} -> file{foo}'; $* clean 2>- } } } : for : { : form-1 : : for x: ... : { : basics : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar baz {{ p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* 2>'cat file{bar} -> file{foo}'; cat <<>EOO; bar baz EOO $* clean 2>- } : pair : { mkdir -p src/build; echo 'bar' >=src/bar; echo 'baz' >=src/baz; echo 'project =' >=src/build/bootstrap.build; cat <=src/buildfile; foo: file{bar}@./ file{baz}@./ {{ p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* src/@out/ 2>>/EOE; mkdir fsdir{out/} cat src/file{bar} -> out/file{foo} EOE cat <<>EOO; bar baz EOO $* 'clean:' src/@out/ 2>- } : special-var : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for ~: $< cat $path($f) >>$p end }} EOI $* 2>>EOE != 0 buildfile:6:7: error: attempt to set '~' special variable EOE } : exit : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for f: $< cat $path($f) >>$p exit end }} EOI $* 2>'cat file{bar} -> file{foo}'; cat <<>EOO; bar EOO $* clean 2>- } : error : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for f: $< cat $path($f) >>$p exit 'fed up' end }} EOI $* 2>>~%EOE% != 0; cat file{bar} -> file{foo} buildfile:8:5: error: fed up %.{3} EOE $* clean 2>- } : depdb : { : inside : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ for f: $< depdb hash $f end p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* 2>>EOE != 0 buildfile:4:5: error: 'depdb' call inside flow control construct EOE } : after-commands : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ for f: $< echo $path($f) >- end depdb hash a }} EOI $* 2>>~%EOE% != 0; buildfile:4:5: error: disallowed command in depdb preamble info: only variable assignments are allowed in depdb preamble buildfile:7:3: info: depdb preamble ends here %.{3} EOE $* clean 2>- } : after-vars : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ h = for f: $< h += $path($f) end depdb hash $h p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* 2>'cat file{bar} -> file{foo}'; $* clean 2>- } } } : form-2 : : ... | for x : { : basics : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar baz {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for -w f cat $f >>$p end }} EOI $* 2>'gen file{foo}'; cat <<>EOO; bar baz EOO $* clean 2>- } : special-var : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for ~ cat $f >>$p end }} EOI $* 2>>~%EOE% != 0; gen file{foo} buildfile:8:3: error: attempt to set '~' special variable %.{3} EOE $* clean 2>- } : misuse : { : after-var { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for x: cat $f >>$p end }} EOI $* 2>>~%EOE% != 0; gen file{foo} buildfile:8:3: error: for: ':' after variable name %.+ EOE $* clean 2>- } : after-attrs { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for x [path]: cat $f >>$p end }} EOI $* 2>>~%EOE% != 0; gen file{foo} :1:7: error: whitespace required after attributes :1:1: info: use the '\[' escape sequence if this is a wildcard pattern buildfile:8:3: info: while parsing attributes '[path]:' %.+ EOE $* clean 2>- } } : exit : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for -w f cat $f >>$p exit end }} EOI $* 2>'gen file{foo}'; cat <<>EOO; bar EOO $* clean 2>- } : error : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ diag gen ($>) p = $path($>) rm -f $p echo $path($<) | for -w f cat $f >>$p exit 'fed up' end }} EOI $* 2>>~%EOE% != 0; gen file{foo} buildfile:10:5: error: fed up %.{3} EOE $* clean 2>- } : depdb : { : inside : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ echo $path($<) | for -w f depdb hash $f end p = $path($>) rm -f $p echo $path($<) | for -w f cat $f >>$p end }} EOI $* 2>>EOE != 0 buildfile:4:5: error: 'depdb' call inside flow control construct EOE } : after-commands : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ echo $path($<) | for -w f echo $f >- end depdb hash $p }} EOI $* 2>>~%EOE% != 0; buildfile:4:5: error: disallowed command in depdb preamble info: only variable assignments are allowed in depdb preamble buildfile:7:3: info: depdb preamble ends here %.{3} EOE $* clean 2>- } : after-vars : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ h = echo $path($<) | for -w f h += $f end depdb hash $h diag gen ($>) p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* 2>'gen file{foo}'; $* clean 2>- } } } : form-3 : : for x <... : { : basics : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar baz {{ diag gen ($>) p = $path($>) rm -f $p for -w f <<"EOF" $path($<) EOF cat $f >>$p end for <<"EOF" -w f $path($<) EOF cat $f >>$p end }} EOI $* 2>'gen file{foo}'; cat <<>EOO; bar baz bar baz EOO $* clean 2>- } : quoting : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar baz {{ n = 'gen' diag "($n)" ($>) p = $path($>) rm -f $p o = -w for "$o" f <<"EOF" $path($<) EOF cat $f >>$p end o = -n for "($o)" f <<"EOF" $path($<) EOF echo $f >>$p end }} EOI $* 2>'gen file{foo}'; cat <<>~%EOO%; bar baz %.+bar .+baz% EOO $* clean 2>- } : special-var : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for ~ <<<$path($<) cat $f >>$p end }} EOI $* 2>>EOE != 0 buildfile:6:6: error: attempt to set '~' special variable EOE } : exit : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for f <<<$path($<) cat $f >>$p exit end }} EOI $* 2>'cat file{bar} -> file{foo}'; cat <<>EOO; bar EOO $* clean 2>- } : error : { echo 'bar' >=bar; echo 'baz' >=baz; cat <=buildfile; foo: bar {{ p = $path($>) rm -f $p for f <<<$path($<) cat $f >>$p exit 'fed up' end }} EOI $* 2>>~%EOE% != 0; cat file{bar} -> file{foo} buildfile:8:5: error: fed up %.{3} EOE $* clean 2>- } : depdb : { : inside : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ for -w f <<<$path($<) depdb hash $f end p = $path($>) rm -f $p echo $path($<) | for -w f cat $f >>$p end }} EOI $* 2>>EOE != 0 buildfile:4:5: error: 'depdb' call inside flow control construct EOE } : after-commands : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ for -w f <<<$path($<) echo $f >- end depdb hash a }} EOI $* 2>>~%EOE% != 0; buildfile:4:5: error: disallowed command in depdb preamble info: only variable assignments are allowed in depdb preamble buildfile:7:3: info: depdb preamble ends here %.{3} EOE $* clean 2>- } : after-vars : { echo 'bar' >=bar; cat <=buildfile; foo: bar {{ h = for -w f <<<$path($<) h += $f end depdb hash $h diag gen ($>) p = $path($>) rm -f $p for f: $< cat $path($f) >>$p end }} EOI $* 2>'gen file{foo}'; $* clean 2>- } } } } }