summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/build/test/scanner_causing_rebuilds.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/tools/build/test/scanner_causing_rebuilds.py')
-rwxr-xr-xsrc/boost/tools/build/test/scanner_causing_rebuilds.py132
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()