From 13d30f14bebbb4d79eb2d96fd37ed9c96c3754a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurko=20Gospodneti=C4=87?= Date: Fri, 5 Sep 2008 00:26:43 +0000 Subject: [PATCH] Added a test for and fixed a Boost Build generator selection bug caused by caching viable source target types for different target types and generators and not maintaining those caches when their content gets invalidated by defining a new generator. Currently quick-fixed by clearing most of the cached values when registering a new generator. Later on this could be made more detailed by clearing only the actually invalidated cache values or updating them or even only marking them to be lazily updated when needed next. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem detected & and a reproducible example constructed by Juraj Ivančić. Debugged by Vladimir Prus. Patched and packaged by Jurko Gospodnetić. [SVN r48590] --- v2/build/generators.jam | 57 ++++++++++++++++++++++++++++++ v2/test/generator_selection.py | 64 ++++++++++++++++++++++++++++++++++ v2/test/test_all.py | 3 +- 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100755 v2/test/generator_selection.py diff --git a/v2/build/generators.jam b/v2/build/generators.jam index 5500f4398..a87dab34e 100644 --- a/v2/build/generators.jam +++ b/v2/build/generators.jam @@ -58,6 +58,43 @@ if "--debug-generators" in [ modules.peek : ARGV ] } +# Clears cached viable source target type information except for target types +# and generators with all source types listed as viable. Should be called when +# something invalidates those cached values by possibly causing some new source +# types to become viable. +# +local rule invalidate-extendable-viable-source-target-type-cache ( ) +{ + local generators-with-cached-source-types = $(.vstg-cached-generators) ; + .vstg-cached-generators = ; + for local gen in $(generators-with-cached-source-types) + { + if $(.vstg.$(gen)) = * + { + .vstg-cached-generators += $(gen) ; + } + else + { + .vstg.$(gen) = ; + } + } + + local types-with-cached-source-types = $(.vst-cached-types) ; + .vst-cached-types = ; + for local type in $(types-with-cached-source-types) + { + if $(.vst.$(type)) = * + { + .vst-cached-types += $(gen) ; + } + else + { + .vst.$(type) = ; + } + } +} + + # Outputs a debug message if generators debugging is on. Each element of # 'message' is checked to see if it is a class instance. If so, instead of the # value, the result of 'str' call is output. @@ -643,6 +680,24 @@ rule register ( g ) base = $(base:B) ; } .generators-for-toolset.$(base) += $(g) ; + + + # After adding a new generator that can construct new target types, we need + # to clear the related cached viable source target type information for + # constructing a specific target type or using a specific generator. Cached + # viable source target type lists affected by this are those containing any + # of the target types constructed by the new generator or any of their base + # target types. + # + # A more advanced alternative to clearing that cached viable source target + # type information would be to expand it with additional source types or + # even better - mark it as needing to be expanded on next use. + # + # For now we just clear all the cached viable source target type information + # that does not simply state 'all types' and may implement a more detailed + # algorithm later on if it becomes needed. + + invalidate-extendable-viable-source-target-type-cache ; } @@ -783,6 +838,7 @@ rule viable-source-types ( target-type ) local key = .vst.$(target-type) ; if ! $($(key)) { + .vst-cached-types += $(target-type) ; local v = [ viable-source-types-real $(target-type) ] ; if ! $(v) { @@ -844,6 +900,7 @@ local rule viable-source-types-for-generator ( generator ) local key = .vstg.$(generator) ; if ! $($(key)) { + .vstg-cached-generators += $(generator) ; local v = [ viable-source-types-for-generator-real $(generator) ] ; if ! $(v) { diff --git a/v2/test/generator_selection.py b/v2/test/generator_selection.py new file mode 100755 index 000000000..192683ca7 --- /dev/null +++ b/v2/test/generator_selection.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +# Copyright 2008 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests that generators get selected correctly. + +import BoostBuild + + +################################################################################ +# +# test_generator_added_after_already_building_a_target_of_its_target_type() +# ------------------------------------------------------------------------- +# +################################################################################ + +def test_generator_added_after_already_building_a_target_of_its_target_type(): + """Regression test for a Boost Build bug causing it to not use a generator + if it got added after already building a targer of its target type. + """ + + t = BoostBuild.Tester() + + t.write("dummy.cpp", "void f() {}\n") + + t.write("jamroot.jam", """ +# Building this dummy target must not cause a later defined CPP target type +# generator not to be recognized as viable. +obj dummy : dummy.cpp ; +alias the-other-obj : Other//other-obj ; +""") + + t.write("Other/source.extension", "A dummy source file.") + + t.write("Other/mygen.jam", """ +import generators ; +import type ; +type.register MY_TYPE : extension ; +generators.register-standard mygen.generate-a-cpp-file : MY_TYPE : CPP ; +rule generate-a-cpp-file { ECHO Generating a CPP file... ; } +actions generate-a-cpp-file { echo void g() {} > "$(<)" } +""") + + t.write("Other/jamfile.jam", """ +import mygen ; +obj other-obj : source.extension ; +""") + + t.run_build_system() + t.expect_output_line("Generating a CPP file...") + + t.cleanup() + + +################################################################################ +# +# main() +# ------ +# +################################################################################ + +test_generator_added_after_already_building_a_target_of_its_target_type() diff --git a/v2/test/test_all.py b/v2/test/test_all.py index 73f14a566..98b7fcbe5 100644 --- a/v2/test/test_all.py +++ b/v2/test/test_all.py @@ -171,7 +171,8 @@ tests = [ "rebuilds", "sort_rule", "ordered_include", "test_result_dumping", - "inherited_dependency" + "inherited_dependency", + "generator_selection" ] if os.name == 'posix':