1#!/usr/bin/python 2 3# Copyright 2012 Jurko Gospodnetic 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 6 7# Tests for a bug causing Boost Build's scanner targets to be rebuilt. 8# unnecessarily in the following scenario: 9# * We want to build target X requiring target A. 10# * We have a multi-file action generating targets A & B. 11# * Out action generates target B with a more recent timestamp than target A. 12# * Target A includes target B. 13# * Target A has a registered include scanner. 14# Now even if our targets A & B have already been built and are up-to-date 15# (e.g. in a state left by a previous successful build run), our scanner target 16# tasked with scanning target A will be marked for updating, thus causing any 17# targets depending on it to be updated/rebuilt as well. 18 19import BoostBuild 20 21t = BoostBuild.Tester(use_test_config=False) 22 23t.write("foo.jam", r""" 24import common ; 25import generators ; 26import modules ; 27import type ; 28import types/cpp ; 29 30type.register FOO : foo ; 31type.register BAR : bar ; 32generators.register-standard foo.foo : FOO : CPP BAR ; 33 34local rule sleep-cmd ( delay ) 35{ 36 if [ modules.peek : NT ] 37 { 38 return ping 127.0.0.1 -n $(delay) -w 1000 >NUL ; 39 } 40 else 41 { 42 return sleep $(delay) ; 43 } 44} 45 46.touch = [ common.file-creation-command ] ; 47.sleep = [ sleep-cmd 2 ] ; 48 49rule foo ( cpp bar : foo : properties * ) 50{ 51 # We add the INCLUDE relationship between our generated CPP & BAR targets 52 # explicitly instead of relying on Boost Jam's internal implementation 53 # detail - automatically adding such relationships between all files 54 # generated by the same action. This way our test will continue to function 55 # correctly even if the related Boost Jam implementation detail changes. 56 # Note that adding this relationship by adding an #include directive in our 57 # generated CPP file is not good enough as such a relationship would get 58 # added only after the scanner target's relationships have already been 59 # established and they (as affected by our initial INCLUDE relationship) are 60 # the original reason for this test failing. 61 INCLUDES $(cpp) : $(bar) ; 62} 63 64actions foo 65{ 66 $(.touch) "$(<[1])" 67 $(.sleep) 68 $(.touch) "$(<[2])" 69} 70""") 71 72t.write( 73 'foo.py', 74""" 75import os 76 77from b2.build import type as type_, generators 78from b2.tools import common 79from b2.manager import get_manager 80 81MANAGER = get_manager() 82ENGINE = MANAGER.engine() 83 84type_.register('FOO', ['foo']) 85type_.register('BAR', ['bar']) 86generators.register_standard('foo.foo', ['FOO'], ['CPP', 'BAR']) 87 88def sleep_cmd(delay): 89 if os.name == 'nt': 90 return 'ping 127.0.0.1 -n {} -w 1000 >NUL'.format(delay) 91 return 'sleep {}'.format(delay) 92 93def foo(targets, sources, properties): 94 cpp, bar = targets 95 foo = sources[0] 96 # We add the INCLUDE relationship between our generated CPP & BAR targets 97 # explicitly instead of relying on Boost Jam's internal implementation 98 # detail - automatically adding such relationships between all files 99 # generated by the same action. This way our test will continue to function 100 # correctly even if the related Boost Jam implementation detail changes. 101 # Note that adding this relationship by adding an #include directive in our 102 # generated CPP file is not good enough as such a relationship would get 103 # added only after the scanner target's relationships have already been 104 # established and they (as affected by our initial INCLUDE relationship) are 105 # the original reason for this test failing. 106 bjam.call('INCLUDES', cpp, bar) 107 108ENGINE.register_action( 109 'foo.foo', 110 ''' 111 {touch} "$(<[1])" 112 {sleep} 113 {touch} "$(<[2])" 114 '''.format(touch=common.file_creation_command(), sleep=sleep_cmd(2)) 115) 116""" 117) 118 119t.write("x.foo", "") 120t.write("jamroot.jam", """\ 121import foo ; 122lib x : x.foo : <link>static ; 123""") 124 125 126# Get everything built once. 127t.run_build_system() 128 129# Simply rerunning the build without touching any of its source target files 130# should not cause any files to be affected. 131t.run_build_system() 132t.expect_nothing_more() 133