diff --git a/v2/build-system.jam b/v2/build-system.jam index 911aad207..a27331fcb 100755 --- a/v2/build-system.jam +++ b/v2/build-system.jam @@ -20,6 +20,7 @@ import feature ; import property-set ; import build-request ; import errors : error ; +import virtual-target ; import "class" : new ; import builtin ; @@ -169,11 +170,17 @@ local targets local clean ; +if "--clean-all" in [ modules.peek : ARGV ] +{ + cleanall = true ; +} + if "--clean" in [ modules.peek : ARGV ] { clean = true ; } + local bjam-targets ; # Given a target it, try to find and return corresponding target. @@ -225,7 +232,7 @@ for local id in $(target-ids) if $(id) = clean { clean = true ; - } + } else { local t ; @@ -278,6 +285,70 @@ else } } +# The cleaning is tricky. Say, if +# user says: +# +# bjam --clean foo +# +# where 'foo' is a directory, then we want to clean targets +# which are in 'foo' or in any children Jamfiles, but not in any +# unrelated Jamfiles. So, we collect the list of project under which +# cleaning is allowed. +# + +local projects-to-clean ; +for local t in $(targets) +{ + if [ class.is-a $(t) : project-target ] + { + projects-to-clean += [ $(t).project-module ] ; + } + else + { + # If user says: + # + # bjam --clean some_project//sometarget + # + # We'll clean any target created in 'project' and below. + # + # It might be desirable to clean only files that are + # part of 'sometarget', and don't belong to other + # main target, but it's not clear if this is good, + # and harder to implement. + local p = [ $(t).project ] ; + projects-to-clean += [ $(p).project-module ] ; + } +} + +# Returns 'true' if 'project' is a child of 'current-project', +# possibly indirect, or is equal to 'project'. +# Returns 'false' otherwise. +rule is-child ( project ) +{ + if ! $(.is-child.$(project)) + { + local r = false ; + if $(project) in $(projects-to-clean) + { + r = true ; + } + else + { + local parent = [ project.attribute $(project) parent-module ] ; + if $(parent) && $(parent) != user-config + { + r = [ is-child $(parent) ] ; + } + } + + .is-child.$(project) = $(r) ; + } + + return $(.is-child.$(project)) ; +} + + + actual-targets = ; for t in $(virtual-targets) @@ -289,12 +360,34 @@ DEPENDS all : $(actual-targets) ; if $(bjam-targets) { - UPDATE $(bjam-targets:G=e) ; + UPDATE $(bjam-targets:G=e) ; +} +else if $(cleanall) +{ + UPDATE clean-all ; } else if $(clean) { + local to-clean ; + for local t in [ virtual-target.all-targets ] + { + local p = [ $(t).project ] ; + if [ is-child [ $(p).project-module ] ] = true + { + to-clean += $(t) ; + } + } + local to-clean-actual ; + for local t in $(to-clean) + { + to-clean-actual += [ $(t).actualize ] ; + } + common.Clean clean : $(to-clean-actual) ; UPDATE clean ; + + } + else { UPDATE all ; diff --git a/v2/build/project.jam b/v2/build/project.jam index 2f1b60034..7aa34b183 100644 --- a/v2/build/project.jam +++ b/v2/build/project.jam @@ -456,6 +456,7 @@ rule initialize ( if $(parent-module) { inherit-attributes $(module-name) : $(parent-module) ; + $(attributes).set parent-module : $(parent-module) : exact ; } if $(jamroot) diff --git a/v2/build/virtual-target.jam b/v2/build/virtual-target.jam index d5211299b..7dce7a37a 100644 --- a/v2/build/virtual-target.jam +++ b/v2/build/virtual-target.jam @@ -706,7 +706,7 @@ class action # Since we set up creating action here, we also set up # action for cleaning up - common.Clean clean : $(actual-targets) ; + common.Clean clean-all : $(actual-targets) ; } } @@ -885,6 +885,7 @@ rule register ( target ) } .recent-targets += $(result) ; + .all-targets += $(result) ; return $(result) ; } @@ -904,6 +905,11 @@ rule clear-recent-targets ( ) .recent-targets = ; } +# Returns all virtual targets ever created +rule all-targets ( ) +{ + return $(.all-targets) ; +} diff --git a/v2/test/clean.py b/v2/test/clean.py new file mode 100644 index 000000000..dd30198cc --- /dev/null +++ b/v2/test/clean.py @@ -0,0 +1,98 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from BoostBuild import Tester, List +import string + +t = Tester() + +t.write("a.cpp", """ +int main() {} + +""") + +t.write("Jamroot", """ +exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ; +""") + +t.write("sub1/Jamfile", """ +lib sub1 : sub1.cpp ../sub2//sub2 ; +""") + +t.write("sub1/sub1.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub1() {} + +""") + +t.write("sub2/Jamfile", """ +lib sub2 : sub2.cpp ; +""") + +t.write("sub2/sub2.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub2() {} + +""") + +t.write("sub3/Jamroot", """ +lib sub3 : sub3.cpp ; +""") + +t.write("sub3/sub3.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub3() {} + +""") + + +# The 'clean' should not remove files under separate Jamroot. +t.run_build_system() +t.run_build_system("--clean") +t.expect_removal("bin/$toolset/debug/a.obj") +t.expect_removal("sub1/bin/$toolset/debug/sub1.obj") +t.expect_removal("sub2/bin/$toolset/debug/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj") + +# The 'clean-all' removes everything it can reach. +t.run_build_system() +t.run_build_system("--clean") +t.expect_removal("bin/$toolset/debug/a.obj") +t.expect_removal("sub1/bin/$toolset/debug/sub1.obj") +t.expect_removal("sub2/bin/$toolset/debug/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj") + +# The 'clean' together with project target removes +# only under that probject +t.run_build_system() +t.run_build_system("sub1 --clean") +t.expect_nothing("bin/$toolset/debug/a.obj") +t.expect_removal("sub1/bin/$toolset/debug/sub1.obj") +t.expect_nothing("sub2/bin/$toolset/debug/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj") + +# And clean-all removes everything. +t.run_build_system() +t.run_build_system("sub1 --clean-all") +t.expect_nothing("bin/$toolset/debug/a.obj") +t.expect_removal("sub1/bin/$toolset/debug/sub1.obj") +t.expect_removal("sub2/bin/$toolset/debug/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj") + + + + + + +t.cleanup() + diff --git a/v2/test/project_test3.py b/v2/test/project_test3.py index d4f8580e4..d8d4b57e0 100644 --- a/v2/test/project_test3.py +++ b/v2/test/project_test3.py @@ -89,7 +89,7 @@ t.expect_addition(["bin/$toolset/release/a.exe", "bin/$toolset/release/optimization-off/a.exe", "bin/$toolset/release/optimization-off/a.obj"]) -t.run_build_system(extra_args='clean') +t.run_build_system(extra_args='--clean-all') t.expect_removal(["bin/$toolset/debug/a.obj", "bin/$toolset/debug/a.exe", "lib/bin/$toolset/debug/b.obj", @@ -106,7 +106,7 @@ t.run_build_system("lib//b.obj") t.expect_addition("lib/bin/$toolset/debug/b.obj") t.expect_nothing_more() -t.run_build_system("clean lib//b.obj") +t.run_build_system("--clean lib//b.obj") t.expect_removal("lib/bin/$toolset/debug/b.obj") t.expect_nothing_more() diff --git a/v2/test/test_all.py b/v2/test/test_all.py index 29e6f5e5f..5246eb13b 100644 --- a/v2/test/test_all.py +++ b/v2/test/test_all.py @@ -137,6 +137,7 @@ tests = [ "rebuilds", "indirect_conditional", "build_no", "disambiguation", + "clean", ] if os.name == 'posix':