diff options
Diffstat (limited to 'src/boost/tools/build/test/scanner_causing_rebuilds.py')
-rwxr-xr-x | src/boost/tools/build/test/scanner_causing_rebuilds.py | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/boost/tools/build/test/scanner_causing_rebuilds.py b/src/boost/tools/build/test/scanner_causing_rebuilds.py new file mode 100755 index 000000000..d0b55ee16 --- /dev/null +++ b/src/boost/tools/build/test/scanner_causing_rebuilds.py @@ -0,0 +1,132 @@ +#!/usr/bin/python + +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) + +# Tests for a bug causing Boost Build's scanner targets to be rebuilt. +# unnecessarily in the following scenario: +# * We want to build target X requiring target A. +# * We have a multi-file action generating targets A & B. +# * Out action generates target B with a more recent timestamp than target A. +# * Target A includes target B. +# * Target A has a registered include scanner. +# Now even if our targets A & B have already been built and are up-to-date +# (e.g. in a state left by a previous successful build run), our scanner target +# tasked with scanning target A will be marked for updating, thus causing any +# targets depending on it to be updated/rebuilt as well. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("foo.jam", r""" +import common ; +import generators ; +import modules ; +import type ; +import types/cpp ; + +type.register FOO : foo ; +type.register BAR : bar ; +generators.register-standard foo.foo : FOO : CPP BAR ; + +local rule sleep-cmd ( delay ) +{ + if [ modules.peek : NT ] + { + return ping 127.0.0.1 -n $(delay) -w 1000 >NUL ; + } + else + { + return sleep $(delay) ; + } +} + +.touch = [ common.file-creation-command ] ; +.sleep = [ sleep-cmd 2 ] ; + +rule foo ( cpp bar : foo : properties * ) +{ + # We add the INCLUDE relationship between our generated CPP & BAR targets + # explicitly instead of relying on Boost Jam's internal implementation + # detail - automatically adding such relationships between all files + # generated by the same action. This way our test will continue to function + # correctly even if the related Boost Jam implementation detail changes. + # Note that adding this relationship by adding an #include directive in our + # generated CPP file is not good enough as such a relationship would get + # added only after the scanner target's relationships have already been + # established and they (as affected by our initial INCLUDE relationship) are + # the original reason for this test failing. + INCLUDES $(cpp) : $(bar) ; +} + +actions foo +{ + $(.touch) "$(<[1])" + $(.sleep) + $(.touch) "$(<[2])" +} +""") + +t.write( + 'foo.py', +""" +import os + +from b2.build import type as type_, generators +from b2.tools import common +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +type_.register('FOO', ['foo']) +type_.register('BAR', ['bar']) +generators.register_standard('foo.foo', ['FOO'], ['CPP', 'BAR']) + +def sleep_cmd(delay): + if os.name == 'nt': + return 'ping 127.0.0.1 -n {} -w 1000 >NUL'.format(delay) + return 'sleep {}'.format(delay) + +def foo(targets, sources, properties): + cpp, bar = targets + foo = sources[0] + # We add the INCLUDE relationship between our generated CPP & BAR targets + # explicitly instead of relying on Boost Jam's internal implementation + # detail - automatically adding such relationships between all files + # generated by the same action. This way our test will continue to function + # correctly even if the related Boost Jam implementation detail changes. + # Note that adding this relationship by adding an #include directive in our + # generated CPP file is not good enough as such a relationship would get + # added only after the scanner target's relationships have already been + # established and they (as affected by our initial INCLUDE relationship) are + # the original reason for this test failing. + bjam.call('INCLUDES', cpp, bar) + +ENGINE.register_action( + 'foo.foo', + ''' + {touch} "$(<[1])" + {sleep} + {touch} "$(<[2])" + '''.format(touch=common.file_creation_command(), sleep=sleep_cmd(2)) +) +""" +) + +t.write("x.foo", "") +t.write("jamroot.jam", """\ +import foo ; +lib x : x.foo : <link>static ; +""") + + +# Get everything built once. +t.run_build_system() + +# Simply rerunning the build without touching any of its source target files +# should not cause any files to be affected. +t.run_build_system() +t.expect_nothing_more() |