1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "tools/gn/ninja_binary_target_writer.h"
9 #include "tools/gn/target.h"
10 #include "tools/gn/test_with_scope.h"
12 TEST(NinjaBinaryTargetWriter
, SourceSet
) {
16 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
17 setup
.settings()->set_target_os(Settings::WIN
);
19 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
20 target
.set_output_type(Target::SOURCE_SET
);
21 target
.visibility().SetPublic();
22 target
.sources().push_back(SourceFile("//foo/input1.cc"));
23 target
.sources().push_back(SourceFile("//foo/input2.cc"));
24 // Also test object files, which should be just passed through to the
25 // dependents to link.
26 target
.sources().push_back(SourceFile("//foo/input3.o"));
27 target
.sources().push_back(SourceFile("//foo/input4.obj"));
28 target
.SetToolchain(setup
.toolchain());
29 ASSERT_TRUE(target
.OnResolved(&err
));
33 std::ostringstream out
;
34 NinjaBinaryTargetWriter
writer(&target
, out
);
37 const char expected
[] =
46 "target_out_dir = obj/foo\n"
47 "target_output_name = bar\n"
49 "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n"
50 "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n"
52 "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
53 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
54 std::string out_str
= out
.str();
55 EXPECT_EQ(expected
, out_str
);
58 // A shared library that depends on the source set.
59 Target
shlib_target(setup
.settings(), Label(SourceDir("//foo/"), "shlib"));
60 shlib_target
.set_output_type(Target::SHARED_LIBRARY
);
61 shlib_target
.public_deps().push_back(LabelTargetPair(&target
));
62 shlib_target
.SetToolchain(setup
.toolchain());
63 ASSERT_TRUE(shlib_target
.OnResolved(&err
));
66 std::ostringstream out
;
67 NinjaBinaryTargetWriter
writer(&shlib_target
, out
);
70 const char expected
[] =
79 "target_out_dir = obj/foo\n"
80 "target_output_name = libshlib\n"
83 // Ordering of the obj files here should come out in the order
84 // specified, with the target's first, followed by the source set's, in
86 "build ./libshlib.so: solink obj/foo/bar.input1.o "
87 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
88 "|| obj/foo/bar.stamp\n"
91 " output_extension = .so\n";
92 std::string out_str
= out
.str();
93 EXPECT_EQ(expected
, out_str
);
96 // A static library that depends on the source set (should not link it).
97 Target
stlib_target(setup
.settings(), Label(SourceDir("//foo/"), "stlib"));
98 stlib_target
.set_output_type(Target::STATIC_LIBRARY
);
99 stlib_target
.public_deps().push_back(LabelTargetPair(&target
));
100 stlib_target
.SetToolchain(setup
.toolchain());
101 ASSERT_TRUE(stlib_target
.OnResolved(&err
));
104 std::ostringstream out
;
105 NinjaBinaryTargetWriter
writer(&stlib_target
, out
);
108 const char expected
[] =
117 "target_out_dir = obj/foo\n"
118 "target_output_name = libstlib\n"
121 // There are no sources so there are no params to alink. (In practice
122 // this will probably fail in the archive tool.)
123 "build obj/foo/libstlib.a: alink || obj/foo/bar.stamp\n"
126 " output_extension = \n";
127 std::string out_str
= out
.str();
128 EXPECT_EQ(expected
, out_str
);
131 // Make the static library 'complete', which means it should be linked.
132 stlib_target
.set_complete_static_lib(true);
134 std::ostringstream out
;
135 NinjaBinaryTargetWriter
writer(&stlib_target
, out
);
138 const char expected
[] =
147 "target_out_dir = obj/foo\n"
148 "target_output_name = libstlib\n"
151 // Ordering of the obj files here should come out in the order
152 // specified, with the target's first, followed by the source set's, in
154 "build obj/foo/libstlib.a: alink obj/foo/bar.input1.o "
155 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
156 "|| obj/foo/bar.stamp\n"
159 " output_extension = \n";
160 std::string out_str
= out
.str();
161 EXPECT_EQ(expected
, out_str
);
165 // This tests that output extension overrides apply, and input dependencies
167 TEST(NinjaBinaryTargetWriter
, ProductExtensionAndInputDeps
) {
171 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
172 setup
.settings()->set_target_os(Settings::LINUX
);
174 // An action for our library to depend on.
175 Target
action(setup
.settings(), Label(SourceDir("//foo/"), "action"));
176 action
.set_output_type(Target::ACTION_FOREACH
);
177 action
.visibility().SetPublic();
178 action
.SetToolchain(setup
.toolchain());
179 ASSERT_TRUE(action
.OnResolved(&err
));
181 // A shared library w/ the product_extension set to a custom value.
182 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "shlib"));
183 target
.set_output_type(Target::SHARED_LIBRARY
);
184 target
.set_output_extension(std::string("so.6"));
185 target
.sources().push_back(SourceFile("//foo/input1.cc"));
186 target
.sources().push_back(SourceFile("//foo/input2.cc"));
187 target
.public_deps().push_back(LabelTargetPair(&action
));
188 target
.SetToolchain(setup
.toolchain());
189 ASSERT_TRUE(target
.OnResolved(&err
));
191 std::ostringstream out
;
192 NinjaBinaryTargetWriter
writer(&target
, out
);
195 const char expected
[] =
204 "target_out_dir = obj/foo\n"
205 "target_output_name = libshlib\n"
207 "build obj/foo/shlib.inputdeps.stamp: stamp obj/foo/action.stamp\n"
208 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc"
209 " || obj/foo/shlib.inputdeps.stamp\n"
210 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc"
211 " || obj/foo/shlib.inputdeps.stamp\n"
213 "build ./libshlib.so.6: solink obj/foo/libshlib.input1.o "
214 // The order-only dependency here is stricly unnecessary since the
215 // sources list this as an order-only dep. See discussion in the code
217 "obj/foo/libshlib.input2.o || obj/foo/action.stamp\n"
220 " output_extension = .so.6\n";
222 std::string out_str
= out
.str();
223 EXPECT_EQ(expected
, out_str
);
226 TEST(NinjaBinaryTargetWriter
, EmptyProductExtension
) {
230 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
231 setup
.settings()->set_target_os(Settings::LINUX
);
233 // This test is the same as ProductExtension, except that
234 // we call set_output_extension("") and ensure that we still get the default.
235 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "shlib"));
236 target
.set_output_type(Target::SHARED_LIBRARY
);
237 target
.set_output_extension(std::string());
238 target
.sources().push_back(SourceFile("//foo/input1.cc"));
239 target
.sources().push_back(SourceFile("//foo/input2.cc"));
241 target
.SetToolchain(setup
.toolchain());
242 ASSERT_TRUE(target
.OnResolved(&err
));
244 std::ostringstream out
;
245 NinjaBinaryTargetWriter
writer(&target
, out
);
248 const char expected
[] =
257 "target_out_dir = obj/foo\n"
258 "target_output_name = libshlib\n"
260 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc\n"
261 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc\n"
263 "build ./libshlib.so: solink obj/foo/libshlib.input1.o "
264 "obj/foo/libshlib.input2.o\n"
267 " output_extension = .so\n";
269 std::string out_str
= out
.str();
270 EXPECT_EQ(expected
, out_str
);
273 TEST(NinjaBinaryTargetWriter
, SourceSetDataDeps
) {
275 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
276 setup
.settings()->set_target_os(Settings::LINUX
);
280 // This target is a data (runtime) dependency of the intermediate target.
281 Target
data(setup
.settings(), Label(SourceDir("//foo/"), "data_target"));
282 data
.set_output_type(Target::EXECUTABLE
);
283 data
.visibility().SetPublic();
284 data
.SetToolchain(setup
.toolchain());
285 ASSERT_TRUE(data
.OnResolved(&err
));
287 // Intermediate source set target.
288 Target
inter(setup
.settings(), Label(SourceDir("//foo/"), "inter"));
289 inter
.set_output_type(Target::SOURCE_SET
);
290 inter
.visibility().SetPublic();
291 inter
.data_deps().push_back(LabelTargetPair(&data
));
292 inter
.SetToolchain(setup
.toolchain());
293 inter
.sources().push_back(SourceFile("//foo/inter.cc"));
294 ASSERT_TRUE(inter
.OnResolved(&err
)) << err
.message();
296 // Write out the intermediate target.
297 std::ostringstream inter_out
;
298 NinjaBinaryTargetWriter
inter_writer(&inter
, inter_out
);
301 // The intermediate source set will be a stamp file that depends on the
302 // object files, and will have an order-only dependency on its data dep and
304 const char inter_expected
[] =
313 "target_out_dir = obj/foo\n"
314 "target_output_name = inter\n"
316 "build obj/foo/inter.inter.o: cxx ../../foo/inter.cc\n"
318 "build obj/foo/inter.stamp: stamp obj/foo/inter.inter.o || "
320 EXPECT_EQ(inter_expected
, inter_out
.str());
323 Target
exe(setup
.settings(), Label(SourceDir("//foo/"), "exe"));
324 exe
.set_output_type(Target::EXECUTABLE
);
325 exe
.public_deps().push_back(LabelTargetPair(&inter
));
326 exe
.SetToolchain(setup
.toolchain());
327 exe
.sources().push_back(SourceFile("//foo/final.cc"));
328 ASSERT_TRUE(exe
.OnResolved(&err
));
330 std::ostringstream final_out
;
331 NinjaBinaryTargetWriter
final_writer(&exe
, final_out
);
334 // The final output depends on both object files (one from the final target,
335 // one from the source set) and has an order-only dependency on the source
336 // set's stamp file and the final target's data file. The source set stamp
337 // dependency will create an implicit order-only dependency on the data
339 const char final_expected
[] =
348 "target_out_dir = obj/foo\n"
349 "target_output_name = exe\n"
351 "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n"
353 "build ./exe: link obj/foo/exe.final.o obj/foo/inter.inter.o || "
354 "obj/foo/inter.stamp\n"
357 " output_extension = \n";
358 EXPECT_EQ(final_expected
, final_out
.str());