Index: tools/build/v2/build/generators.jam =================================================================== --- tools/build/v2/build/generators.jam (revision 45477) +++ tools/build/v2/build/generators.jam (working copy) @@ -107,6 +107,7 @@ import virtual-target ; import "class" : new ; import property ; + import path ; EXPORT class@generator : indent increase-indent decrease-indent generators.dout ; @@ -377,6 +378,52 @@ return $(result) ; } + rule add-prefix ( name : prefix ? ) + { + if $(prefix) + { + name = $(prefix)$(name) ; + name = $(name:J=) ; + } + return $(name) ; + } + + rule add-postfix ( name : postfix ? ) + { + if $(postfix) + { + name = $(name)$(postfix) ; + name = $(name:J=) ; + } + return $(name) ; + } + + # Determine target name from fullname (maybe including path components) + # Place optional prefix and postfix around basename + # + rule determine-target-name ( fullname : prefix ? postfix ? ) + { + # See if we need to add directory to the target name. + local dir = $(fullname:D) ; + local name = $(fullname:B) ; + + name = [ add-prefix $(name) : $(prefix) ] ; + name = [ add-postfix $(name) : $(postfix) ] ; + + if $(dir) && + # Never append '..' to target path. + ! [ MATCH .*(\\.\\.).* : $(dir) ] + && + ! [ path.is-rooted $(dir) ] + { + # Relative path is always relative to the source + # directory. Retain it, so that users can have files + # with the same in two different subdirectories. + name = $(dir)/$(name) ; + } + return $(name) ; + } + # Determine the name of the produced target from the names of the sources. # rule determine-output-name ( sources + ) @@ -399,10 +446,7 @@ errors.error "$(self.id): source targets have different names: cannot determine target name" ; } } - - # Names of sources might include directory. We should strip it. - name = $(name:D=) ; - + name = [ determine-target-name [ $(sources[1]).name ] ] ; return $(name) ; } @@ -445,7 +489,7 @@ local post = $(self.name-postfix) ; for local t in $(self.target-types) { - local generated-name = $(pre[1])$(name)$(post[1]) ; + local generated-name = [ determine-target-name $(name) : $(pre[1]) $(post[1]) ] ; pre = $(pre[2-]) ; post = $(post[2-]) ; Index: tools/build/v2/build/project.jam =================================================================== --- tools/build/v2/build/project.jam (revision 45477) +++ tools/build/v2/build/project.jam (working copy) @@ -794,7 +794,17 @@ # absolute. for local p in $(paths) { - result += [ path.root $(p) [ path.pwd ] ] ; + # If the path is below source location, use relative path. + # Otherwise, use full path just to avoid any ambiguities. + local rel = [ path.relative $(p) $(location) : no-error ] ; + if $(rel) = not-a-child + { + result += [ path.root $(p) [ path.pwd ] ] ; + } + else + { + result += $(rel) ; + } } } else Index: tools/build/v2/test/relative_sources.py =================================================================== --- tools/build/v2/test/relative_sources.py (revision 45477) +++ tools/build/v2/test/relative_sources.py (working copy) @@ -10,10 +10,30 @@ from BoostBuild import Tester t = Tester() -t.write("project-root.jam", "import gcc ;") -t.write("Jamfile", "exe a : src/a.cpp ;") +# Test that relative path to source, 'src', is preserved. +t.write("Jamroot", "exe a : src/a.cpp ;") t.write("src/a.cpp", "int main() { return 0; }\n") t.run_build_system() +t.expect_addition("bin/$toolset/debug/src/a.obj") + +# Test that the relative path to source is preserved +# when using 'glob'. +t.rm("bin") +t.write("Jamroot", "exe a : [ glob src/*.cpp ] ;") +t.run_build_system() +t.expect_addition("bin/$toolset/debug/src/a.obj") + + +# Test that relative path with ".." is *not* added to +# target path. +t.rm(".") +t.write("Jamroot", "") +t.write("a.cpp", "int main() { return 0; }\n") +t.write("build/Jamfile", "exe a : ../a.cpp ; ") +t.run_build_system(subdir="build") +t.expect_addition("build/bin/$toolset/debug/a.obj") + + t.cleanup() Index: tools/build/v2/util/path.jam =================================================================== --- tools/build/v2/util/path.jam (revision 45477) +++ tools/build/v2/util/path.jam (working copy) @@ -375,8 +375,9 @@ # Assuming 'child' is a subdirectory of 'parent', return the relative path from # 'parent' to 'child'. # -rule relative ( child parent ) +rule relative ( child parent : no-error ? ) { + local not-a-child ; if $(parent) = "." { return $(child) ; @@ -395,12 +396,27 @@ } else { - errors.error $(child) is not a subdir of $(parent) ; + not-a-child = true ; + split1 = ; } } if $(split2) { - return [ join $(split2) ] ; + if $(not-a-child) + { + if $(no-error) + { + return not-a-child ; + } + else + { + errors.error $(child) is not a subdir of $(parent) ; + } + } + else + { + return [ join $(split2) ] ; + } } else {