]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #!/usr/bin/python |
2 | ||
3 | # Copyright 2003 Dave Abrahams | |
4 | # Copyright 2002, 2003, 2005, 2006 Vladimir Prus | |
5 | # Distributed under the Boost Software License, Version 1.0. | |
1e59de90 TL |
6 | # (See accompanying file LICENSE.txt or copy at |
7 | # https://www.bfgroup.xyz/b2/LICENSE.txt) | |
7c673cae FG |
8 | |
9 | import BoostBuild | |
10 | ||
11 | ||
12 | def test_basic(): | |
11fdf7f2 | 13 | t = BoostBuild.Tester(["-d3", "-d+12"], use_test_config=False) |
7c673cae FG |
14 | |
15 | t.write("a.cpp", """ | |
16 | #include <a.h> | |
17 | # include "a.h" | |
18 | #include <x.h> | |
19 | int main() {} | |
20 | """) | |
21 | t.write("a.h", "\n") | |
22 | t.write("a_c.c", """\ | |
23 | #include <a.h> | |
24 | # include "a.h" | |
25 | #include <x.h> | |
26 | """) | |
27 | t.write("b.cpp", """\ | |
28 | #include "a.h" | |
29 | int main() {} | |
30 | """) | |
31 | t.write("b.h", "\n") | |
32 | t.write("c.cpp", """\ | |
33 | #include "x.h" | |
34 | int main() {} | |
35 | """) | |
36 | t.write("e.cpp", """\ | |
37 | #include "x.h" | |
38 | int main() {} | |
39 | """) | |
40 | t.write("x.foo", "") | |
41 | t.write("y.foo", "") | |
42 | ||
43 | t.write("src1/a.h", '#include "b.h"\n') | |
44 | t.write("src1/b.h", '#include "c.h"\n') | |
45 | t.write("src1/c.h", "\n") | |
46 | t.write("src1/z.h", """\ | |
47 | extern int dummy_variable_suppressing_empty_file_warning_on_hp_cxx_compiler; | |
48 | """) | |
49 | ||
50 | t.write("src2/b.h", "\n") | |
51 | ||
52 | t.write("jamroot.jam", """\ | |
53 | import foo ; | |
54 | import types/cpp ; | |
55 | import types/exe ; | |
56 | ||
57 | project test : requirements <include>src1 ; | |
58 | ||
59 | exe a : x.foo a.cpp a_c.c ; | |
60 | exe b : b.cpp ; | |
61 | ||
62 | # Because of <define>FOO, c.cpp will be compiled to a different directory than | |
63 | # everything for main target "a". Therefore, without <implicit-dependency>, C | |
64 | # preprocessor processing that module will not find "x.h", which is part of | |
65 | # "a"'s dependency graph. | |
66 | # | |
67 | # -------------------------- | |
68 | # More detailed explanation: | |
69 | # -------------------------- | |
70 | # c.cpp includes x.h which does not exist on the current include path so Boost | |
71 | # Jam will try to match it to existing Jam targets to cover cases as this one | |
72 | # where the file is generated by the same build. | |
73 | # | |
74 | # However, as x.h is not part of "c" metatarget's dependency graph, Boost | |
75 | # Build will not actualize its target by default, i.e. create its Jam target. | |
76 | # | |
77 | # To get the Jam target created in time, we use the <implicit-dependency> | |
78 | # feature. This tells Boost Build that it needs to actualize the dependency | |
79 | # graph for metatarget "a", even though that metatarget has not been directly | |
80 | # mentioned and is not a dependency for any of the metatargets mentioned in the | |
81 | # current build request. | |
82 | # | |
83 | # Note that Boost Build does not automatically add a dependency between the | |
84 | # Jam targets in question so, if Boost Jam does not add a dependency on a target | |
85 | # from that other dependency graph (x.h in our case), i.e. if c.cpp does not | |
86 | # actually include x.h, us actualizing it will have no effect in the end as | |
87 | # Boost Jam will not have a reason to actually build those targets in spite of | |
88 | # knowing about them. | |
89 | exe c : c.cpp : <define>FOO <implicit-dependency>a ; | |
90 | """) | |
91 | ||
92 | t.write("foo.jam", """\ | |
93 | import generators ; | |
94 | import modules ; | |
95 | import os ; | |
96 | import print ; | |
97 | import type ; | |
98 | import types/cpp ; | |
99 | ||
100 | type.register FOO : foo ; | |
101 | ||
102 | generators.register-standard foo.foo : FOO : CPP H ; | |
103 | ||
104 | nl = " | |
105 | " ; | |
106 | ||
107 | rule foo ( targets * : sources * : properties * ) | |
108 | { | |
109 | # On NT, you need an exported symbol in order to have an import library | |
110 | # generated. We will not really use the symbol defined here, just force the | |
111 | # import library creation. | |
112 | if ( [ os.name ] = NT || [ modules.peek : OS ] in CYGWIN ) && | |
113 | <main-target-type>LIB in $(properties) | |
114 | { | |
115 | .decl = "void __declspec(dllexport) foo() {}" ; | |
116 | } | |
117 | print.output $(<[1]) ; | |
118 | print.text $(.decl:E="//")$(nl) ; | |
119 | print.output $(<[2]) ; | |
120 | print.text "#include <z.h>"$(nl) ; | |
121 | } | |
122 | """) | |
123 | ||
124 | t.write("foo.py", | |
125 | r"""import bjam | |
126 | import b2.build.type as type | |
127 | import b2.build.generators as generators | |
128 | ||
129 | from b2.manager import get_manager | |
130 | ||
131 | type.register("FOO", ["foo"]) | |
132 | generators.register_standard("foo.foo", ["FOO"], ["CPP", "H"]) | |
133 | ||
134 | def prepare_foo(targets, sources, properties): | |
135 | if properties.get('os') in ['windows', 'cygwin']: | |
136 | bjam.call('set-target-variable', targets, "DECL", | |
137 | "void __declspec(dllexport) foo() {}") | |
138 | ||
139 | get_manager().engine().register_action("foo.foo", | |
140 | "echo -e $(DECL:E=//)\\n > $(<[1])\n" | |
141 | "echo -e "#include <z.h>\\n" > $(<[2])\n", function=prepare_foo) | |
142 | """) | |
143 | ||
144 | # Check that main target 'c' was able to find 'x.h' from 'a's dependency | |
145 | # graph. | |
146 | t.run_build_system() | |
b32b8144 | 147 | t.expect_addition("bin/$toolset/debug*/c.exe") |
7c673cae FG |
148 | |
149 | # Check handling of first level includes. | |
150 | ||
151 | # Both 'a' and 'b' include "a.h" and should be updated. | |
152 | t.touch("a.h") | |
153 | t.run_build_system() | |
154 | ||
b32b8144 FG |
155 | t.expect_touch("bin/$toolset/debug*/a.exe") |
156 | t.expect_touch("bin/$toolset/debug*/a.obj") | |
157 | t.expect_touch("bin/$toolset/debug*/a_c.obj") | |
158 | t.expect_touch("bin/$toolset/debug*/b.exe") | |
159 | t.expect_touch("bin/$toolset/debug*/b.obj") | |
20effc67 TL |
160 | t.ignore_touch("bin/*/a.rsp") |
161 | t.ignore_touch("bin/*/b.rsp") | |
7c673cae FG |
162 | t.expect_nothing_more() |
163 | ||
164 | # Only source files using include <a.h> should be compiled. | |
165 | t.touch("src1/a.h") | |
166 | t.run_build_system() | |
167 | ||
b32b8144 FG |
168 | t.expect_touch("bin/$toolset/debug*/a.exe") |
169 | t.expect_touch("bin/$toolset/debug*/a.obj") | |
170 | t.expect_touch("bin/$toolset/debug*/a_c.obj") | |
20effc67 | 171 | t.ignore_touch("bin/*/a.rsp") |
7c673cae FG |
172 | t.expect_nothing_more() |
173 | ||
174 | # "src/a.h" includes "b.h" (in the same dir). | |
175 | t.touch("src1/b.h") | |
176 | t.run_build_system() | |
b32b8144 FG |
177 | t.expect_touch("bin/$toolset/debug*/a.exe") |
178 | t.expect_touch("bin/$toolset/debug*/a.obj") | |
179 | t.expect_touch("bin/$toolset/debug*/a_c.obj") | |
20effc67 | 180 | t.ignore_touch("bin/*/a.rsp") |
7c673cae FG |
181 | t.expect_nothing_more() |
182 | ||
183 | # Included by "src/b.h". We had a bug: file included using double quotes | |
184 | # (e.g. "b.h") was not scanned at all in this case. | |
185 | t.touch("src1/c.h") | |
186 | t.run_build_system() | |
b32b8144 | 187 | t.expect_touch("bin/$toolset/debug*/a.exe") |
7c673cae FG |
188 | |
189 | t.touch("b.h") | |
190 | t.run_build_system() | |
191 | t.expect_nothing_more() | |
192 | ||
193 | # Test dependency on a generated header. | |
194 | # | |
195 | # TODO: we have also to check that generated header is found correctly if | |
196 | # it is different for different subvariants. Lacking any toolset support, | |
197 | # this check will be implemented later. | |
198 | t.touch("x.foo") | |
199 | t.run_build_system() | |
b32b8144 FG |
200 | t.expect_touch("bin/$toolset/debug*/a.obj") |
201 | t.expect_touch("bin/$toolset/debug*/a_c.obj") | |
7c673cae FG |
202 | |
203 | # Check that generated headers are scanned for dependencies as well. | |
204 | t.touch("src1/z.h") | |
205 | t.run_build_system() | |
b32b8144 FG |
206 | t.expect_touch("bin/$toolset/debug*/a.obj") |
207 | t.expect_touch("bin/$toolset/debug*/a_c.obj") | |
7c673cae FG |
208 | |
209 | t.cleanup() | |
210 | ||
211 | ||
212 | def test_scanned_includes_with_absolute_paths(): | |
213 | """ | |
214 | Regression test: on Windows, <includes> with absolute paths were not | |
215 | considered when scanning dependencies. | |
216 | ||
217 | """ | |
11fdf7f2 | 218 | t = BoostBuild.Tester(["-d3", "-d+12"]) |
7c673cae FG |
219 | |
220 | t.write("jamroot.jam", """\ | |
221 | path-constant TOP : . ; | |
222 | exe app : main.cpp : <include>$(TOP)/include ; | |
223 | """); | |
224 | ||
225 | t.write("main.cpp", """\ | |
226 | #include <dir/header.h> | |
227 | int main() {} | |
228 | """) | |
229 | ||
230 | t.write("include/dir/header.h", "\n") | |
231 | ||
232 | t.run_build_system() | |
b32b8144 | 233 | t.expect_addition("bin/$toolset/debug*/main.obj") |
7c673cae FG |
234 | |
235 | t.touch("include/dir/header.h") | |
236 | t.run_build_system() | |
b32b8144 | 237 | t.expect_touch("bin/$toolset/debug*/main.obj") |
7c673cae FG |
238 | |
239 | t.cleanup() | |
240 | ||
241 | ||
242 | test_basic() | |
243 | test_scanned_includes_with_absolute_paths() |