From 290e284ffeef6ffccb5c05db69398c47cd0cf1ea Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Apr 2014 13:12:17 -0700 Subject: [PATCH] topological sort ordered includes. --- src/build/toolset.jam | 27 +++++- src/tools/types/cpp.jam | 10 +-- test/ordered_include.py | 176 +++++++++++++++++++++++++++++++++++----- 3 files changed, 183 insertions(+), 30 deletions(-) diff --git a/src/build/toolset.jam b/src/build/toolset.jam index b5defd5f4..a942cd906 100644 --- a/src/build/toolset.jam +++ b/src/build/toolset.jam @@ -17,6 +17,8 @@ import regex ; import sequence ; import set ; import property-set ; +import order ; +import "class" : new ; .flag-no = 1 ; @@ -237,6 +239,7 @@ rule handle-flag-value ( value * : properties * ) if $(value:G) { local matches = [ property.select $(value) : $(properties) ] ; + local order ; for local p in $(matches) { local att = [ feature.attributes $(p:G) ] ; @@ -263,11 +266,24 @@ rule handle-flag-value ( value * : properties * ) } if path in $(att) { - result += [ sequence.transform path.native : $(values) ] ; + values = [ sequence.transform path.native : $(values) ] ; } - else + result += $(values) ; + if $(values[2]) { - result += $(values) ; + if ! $(order) + { + order = [ new order ] ; + } + local prev ; + for local v in $(values) + { + if $(prev) + { + $(order).add-pair $(prev) $(v) ; + } + prev = $(v) ; + } } } else @@ -275,6 +291,11 @@ rule handle-flag-value ( value * : properties * ) result += $(p:G=) ; } } + if $(order) + { + result = [ $(order).order [ sequence.unique $(result) : stable ] ] ; + DELETE_MODULE $(order) ; + } } else { diff --git a/src/tools/types/cpp.jam b/src/tools/types/cpp.jam index 846ba5356..3fcf449a2 100644 --- a/src/tools/types/cpp.jam +++ b/src/tools/types/cpp.jam @@ -15,17 +15,17 @@ class c-scanner : scanner import regex ; import scanner ; import sequence ; + import toolset ; import virtual-target ; rule __init__ ( includes * ) { scanner.__init__ ; - for local i in $(includes) - { - self.includes += [ sequence.transform path.native : [ regex.split - $(i:G=) "&&" ] ] ; - } + # toolset.handle-flag-value is a bit of overkill, but it + # does correctly handle the topological sort of && separated + # include paths + self.includes = [ toolset.handle-flag-value : $(includes) ] ; } rule pattern ( ) diff --git a/test/ordered_include.py b/test/ordered_include.py index 1fe5e9613..2ce955c0d 100644 --- a/test/ordered_include.py +++ b/test/ordered_include.py @@ -8,34 +8,166 @@ import BoostBuild -tester = BoostBuild.Tester(use_test_config=False) +def test_basic(): + tester = BoostBuild.Tester(use_test_config=False) + tester.write("jamroot.jam", """ + obj test : test.cpp : a&&b ; + """) -tester.write("jamroot.jam", """ -obj test : test.cpp : a&&b ; -""") + tester.write("test.cpp", """ + #include + #include + int main() {} + """) + + tester.write("a/test1.hpp", """ + """) + + tester.write("b/test2.hpp", """ + """) + + tester.run_build_system() + + tester.expect_addition("bin/$toolset/debug/test.obj") + + # Check that the dependencies are correct + tester.touch("a/test1.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug/test.obj") + + tester.touch("b/test2.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug/test.obj") -tester.write("test.cpp", """ -#include -#include -int main() {} -""") + tester.cleanup() -tester.write("a/test1.hpp", """ -""") +def test_order1(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : a&&b ; + """) + t.write("test.cpp", """ + #include + int main() {} + """) + t.write("a/test.h", """ + """) + t.write("b/test.h", """ + #error should find a/test.h + """) + t.run_build_system() -tester.write("b/test2.hpp", """ -""") + t.touch("a/test.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() -tester.run_build_system() + t.touch("b/test.h") + t.run_build_system() + t.expect_nothing_more() -tester.expect_addition("bin/$toolset/debug/test.obj") + t.cleanup() -tester.touch("a/test1.hpp") -tester.run_build_system() -tester.expect_touch("bin/$toolset/debug/test.obj") +def test_order2(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : b&&a ; + """) + t.write("test.cpp", """ + #include + int main() {} + """) + t.write("a/test.h", """ + #error should find b/test.h + """) + t.write("b/test.h", """ + """) + t.run_build_system() -tester.touch("b/test2.hpp") -tester.run_build_system() -tester.expect_touch("bin/$toolset/debug/test.obj") + t.touch("a/test.h") + t.run_build_system() + t.expect_nothing_more() -tester.cleanup() + t.touch("b/test.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() + + t.cleanup() + +def test_order_graph(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : + b&&a + c&&b + a + c + b + e&&b&&d + ; + """) + t.write("test.cpp", """ + #include + #include + #include + #include + int main() {} + """) + t.write("b/test1.h", "") + t.write("a/test1.h", "#error should find b/test1.h\n") + + t.write("c/test2.h", "") + t.write("b/test2.h", "#error should find c/test2.h\n") + + t.write("e/test3.h", "") + t.write("b/test3.h", "#error should find e/test3.h\n") + + t.write("b/test4.h", "") + t.write("d/test4.h", "#error should find b/test4.h\n") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug/test.obj") + + t.touch("b/test1.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() + + t.touch("a/test1.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("c/test2.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() + + t.touch("b/test2.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("e/test3.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() + + t.touch("b/test3.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("b/test4.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug/test.obj") + t.expect_nothing_more() + + t.touch("d/test4.h") + t.run_build_system() + t.expect_nothing_more() + + t.cleanup() + +test_basic() +test_order1() +test_order2() +test_order_graph()