diff --git a/src/build/virtual-target.jam b/src/build/virtual-target.jam index ec63fde8d..9e6d681d3 100644 --- a/src/build/virtual-target.jam +++ b/src/build/virtual-target.jam @@ -298,7 +298,17 @@ rule abstract-file-target ( name common.Clean clean : $(name) ; } } - + + # Returns the name of main target this virtual target is specific too. + # Ordinary, it's assumed that grist of the actual Jam target and target path + # is determined by project, base properties, target name and type. + # Derived classes may return non-empty string to indicate that the target is + # specific to the given main target. + rule specific-main-target ( ) + { + return "" ; + } + rule str ( ) { local action = [ action ] ; @@ -367,7 +377,12 @@ rule abstract-file-target ( name { grist = $(grist)/$(self.extra-grist) ; } - + local smt = [ specific-main-target ] ; + if $(smt) + { + grist = $(grist)/main-target-$(smt) ; + } + if $(self.suffix) { self.actual-name = [ sequence.join <$(grist)>$(self.name) @@ -415,7 +430,6 @@ rule file-target ( rule actualize-location ( target ) { - compute-extra-path ; if $(self.path) { LOCATE on $(target) = $(self.path) ; @@ -442,55 +456,52 @@ rule file-target ( # This is a source file. SEARCH on $(target) = [ path.native [ project.attribute $(self.project) source-location ] ] ; - } + } } - rule compute-extra-path ( ) - { - if $(self.action) - { - local ps = [ $(self.action).properties-ps ] ; - - local main-target = [ $(self.dg).main-target ] ; - local project = [ $(main-target).project ] ; - local plocation = [ project.attribute $(project) location ] ; - local ptarget = [ project.target $(plocation) ] ; - local ref-ps = [ $(ptarget).reference-properties [ $(self.dg).properties-ps ] ] ; - - - if [ $(ps).free ] != [ $(ref-ps).free ] - { - self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ; - } - } - } + rule specific-main-target ( ) + { + if $(self.action) + { + local ps = [ $(self.action).properties-ps ] ; + + local main-target = [ $(self.dg).main-target ] ; + local project = [ $(main-target).project ] ; + local plocation = [ project.attribute $(project) location ] ; + local ptarget = [ project.target $(plocation) ] ; + local ref-ps = [ $(ptarget).reference-properties [ $(self.dg).properties-ps ] ] ; + if [ $(ps).free ] != [ $(ref-ps).free ] + { + return [ $(main-target).name ] ; + } + } + } + # Returns the directory for this target rule path ( ) { - if $(self.path) + if ! $(self.path) { - return $(self.path) ; - } - else - { - compute-extra-path ; - local build-dir = [ project.attribute $(self.project) build-dir ] ; if ! $(build-dir) { build-dir = [ project.attribute $(self.project) location ] ; } + local smt = [ specific-main-target ] ; local path = [ path.join $(build-dir) bin [ $(self.action).path ] - $(self.extra-path) + main-target-$(smt) ] ; - - return [ path.native $(path) ] ; + + # Store the computed path, so that it's not recomputed + # any more + self.path = [ path.native $(path) ] ; } + return $(self.path) ; } } diff --git a/test/main_properties.py b/test/main_properties.py index deae70fbb..dd1f1dc13 100644 --- a/test/main_properties.py +++ b/test/main_properties.py @@ -22,5 +22,21 @@ t.write("b.cpp", "void foo() {}\n") t.run_build_system() t.expect_addition("bin/gcc/debug/main-target-b/b.o") +# This tests another bug: when source file was used by two main targets, +# one without any requirements and another with free requirements, it +# was compiled twice with to the same locaiton. + +t.write("Jamfile", """ +exe a : a.cpp ; +exe b : a.cpp : FOO ; +""") +t.write("a.cpp", """ +int main() {} +""") + +t.rm("bin") +t.run_build_system() +t.expect_addition(["bin/gcc/debug/a.o", "bin/gcc/debug/main-target-b/a.o"]) + t.cleanup()