Add ICU message format support
[chromium-blink-merge.git] / tools / gn / ninja_binary_target_writer_unittest.cc
blob5438c4dc6bd463db230cf98c94ad79bfb30fa81c
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.
5 #include <sstream>
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "tools/gn/ninja_binary_target_writer.h"
9 #include "tools/gn/scheduler.h"
10 #include "tools/gn/target.h"
11 #include "tools/gn/test_with_scope.h"
13 TEST(NinjaBinaryTargetWriter, SourceSet) {
14 TestWithScope setup;
15 Err err;
17 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
18 setup.settings()->set_target_os(Settings::WIN);
20 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
21 target.set_output_type(Target::SOURCE_SET);
22 target.visibility().SetPublic();
23 target.sources().push_back(SourceFile("//foo/input1.cc"));
24 target.sources().push_back(SourceFile("//foo/input2.cc"));
25 // Also test object files, which should be just passed through to the
26 // dependents to link.
27 target.sources().push_back(SourceFile("//foo/input3.o"));
28 target.sources().push_back(SourceFile("//foo/input4.obj"));
29 target.SetToolchain(setup.toolchain());
30 ASSERT_TRUE(target.OnResolved(&err));
32 // Source set itself.
34 std::ostringstream out;
35 NinjaBinaryTargetWriter writer(&target, out);
36 writer.Run();
38 const char expected[] =
39 "defines =\n"
40 "include_dirs =\n"
41 "cflags =\n"
42 "cflags_cc =\n"
43 "root_out_dir = .\n"
44 "target_out_dir = obj/foo\n"
45 "target_output_name = bar\n"
46 "\n"
47 "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n"
48 "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n"
49 "\n"
50 "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
51 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n";
52 std::string out_str = out.str();
53 EXPECT_EQ(expected, out_str);
56 // A shared library that depends on the source set.
57 Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
58 shlib_target.set_output_type(Target::SHARED_LIBRARY);
59 shlib_target.public_deps().push_back(LabelTargetPair(&target));
60 shlib_target.SetToolchain(setup.toolchain());
61 ASSERT_TRUE(shlib_target.OnResolved(&err));
64 std::ostringstream out;
65 NinjaBinaryTargetWriter writer(&shlib_target, out);
66 writer.Run();
68 const char expected[] =
69 "defines =\n"
70 "include_dirs =\n"
71 "root_out_dir = .\n"
72 "target_out_dir = obj/foo\n"
73 "target_output_name = libshlib\n"
74 "\n"
75 "\n"
76 // Ordering of the obj files here should come out in the order
77 // specified, with the target's first, followed by the source set's, in
78 // order.
79 "build ./libshlib.so: solink obj/foo/bar.input1.o "
80 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
81 "|| obj/foo/bar.stamp\n"
82 " ldflags =\n"
83 " libs =\n"
84 " output_extension = .so\n";
85 std::string out_str = out.str();
86 EXPECT_EQ(expected, out_str);
89 // A static library that depends on the source set (should not link it).
90 Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib"));
91 stlib_target.set_output_type(Target::STATIC_LIBRARY);
92 stlib_target.public_deps().push_back(LabelTargetPair(&target));
93 stlib_target.SetToolchain(setup.toolchain());
94 ASSERT_TRUE(stlib_target.OnResolved(&err));
97 std::ostringstream out;
98 NinjaBinaryTargetWriter writer(&stlib_target, out);
99 writer.Run();
101 const char expected[] =
102 "defines =\n"
103 "include_dirs =\n"
104 "root_out_dir = .\n"
105 "target_out_dir = obj/foo\n"
106 "target_output_name = libstlib\n"
107 "\n"
108 "\n"
109 // There are no sources so there are no params to alink. (In practice
110 // this will probably fail in the archive tool.)
111 "build obj/foo/libstlib.a: alink || obj/foo/bar.stamp\n"
112 " ldflags =\n"
113 " libs =\n"
114 " output_extension = \n";
115 std::string out_str = out.str();
116 EXPECT_EQ(expected, out_str);
119 // Make the static library 'complete', which means it should be linked.
120 stlib_target.set_complete_static_lib(true);
122 std::ostringstream out;
123 NinjaBinaryTargetWriter writer(&stlib_target, out);
124 writer.Run();
126 const char expected[] =
127 "defines =\n"
128 "include_dirs =\n"
129 "root_out_dir = .\n"
130 "target_out_dir = obj/foo\n"
131 "target_output_name = libstlib\n"
132 "\n"
133 "\n"
134 // Ordering of the obj files here should come out in the order
135 // specified, with the target's first, followed by the source set's, in
136 // order.
137 "build obj/foo/libstlib.a: alink obj/foo/bar.input1.o "
138 "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj "
139 "|| obj/foo/bar.stamp\n"
140 " ldflags =\n"
141 " libs =\n"
142 " output_extension = \n";
143 std::string out_str = out.str();
144 EXPECT_EQ(expected, out_str);
148 // This tests that output extension overrides apply, and input dependencies
149 // are applied.
150 TEST(NinjaBinaryTargetWriter, ProductExtensionAndInputDeps) {
151 TestWithScope setup;
152 Err err;
154 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
155 setup.settings()->set_target_os(Settings::LINUX);
157 // An action for our library to depend on.
158 Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
159 action.set_output_type(Target::ACTION_FOREACH);
160 action.visibility().SetPublic();
161 action.SetToolchain(setup.toolchain());
162 ASSERT_TRUE(action.OnResolved(&err));
164 // A shared library w/ the product_extension set to a custom value.
165 Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
166 target.set_output_type(Target::SHARED_LIBRARY);
167 target.set_output_extension(std::string("so.6"));
168 target.sources().push_back(SourceFile("//foo/input1.cc"));
169 target.sources().push_back(SourceFile("//foo/input2.cc"));
170 target.public_deps().push_back(LabelTargetPair(&action));
171 target.SetToolchain(setup.toolchain());
172 ASSERT_TRUE(target.OnResolved(&err));
174 std::ostringstream out;
175 NinjaBinaryTargetWriter writer(&target, out);
176 writer.Run();
178 const char expected[] =
179 "defines =\n"
180 "include_dirs =\n"
181 "cflags =\n"
182 "cflags_cc =\n"
183 "root_out_dir = .\n"
184 "target_out_dir = obj/foo\n"
185 "target_output_name = libshlib\n"
186 "\n"
187 "build obj/foo/shlib.inputdeps.stamp: stamp obj/foo/action.stamp\n"
188 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc"
189 " || obj/foo/shlib.inputdeps.stamp\n"
190 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc"
191 " || obj/foo/shlib.inputdeps.stamp\n"
192 "\n"
193 "build ./libshlib.so.6: solink obj/foo/libshlib.input1.o "
194 // The order-only dependency here is stricly unnecessary since the
195 // sources list this as an order-only dep. See discussion in the code
196 // that writes this.
197 "obj/foo/libshlib.input2.o || obj/foo/action.stamp\n"
198 " ldflags =\n"
199 " libs =\n"
200 " output_extension = .so.6\n";
202 std::string out_str = out.str();
203 EXPECT_EQ(expected, out_str);
206 TEST(NinjaBinaryTargetWriter, EmptyProductExtension) {
207 TestWithScope setup;
208 Err err;
210 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
211 setup.settings()->set_target_os(Settings::LINUX);
213 // This test is the same as ProductExtension, except that
214 // we call set_output_extension("") and ensure that we still get the default.
215 Target target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
216 target.set_output_type(Target::SHARED_LIBRARY);
217 target.set_output_extension(std::string());
218 target.sources().push_back(SourceFile("//foo/input1.cc"));
219 target.sources().push_back(SourceFile("//foo/input2.cc"));
221 target.SetToolchain(setup.toolchain());
222 ASSERT_TRUE(target.OnResolved(&err));
224 std::ostringstream out;
225 NinjaBinaryTargetWriter writer(&target, out);
226 writer.Run();
228 const char expected[] =
229 "defines =\n"
230 "include_dirs =\n"
231 "cflags =\n"
232 "cflags_cc =\n"
233 "root_out_dir = .\n"
234 "target_out_dir = obj/foo\n"
235 "target_output_name = libshlib\n"
236 "\n"
237 "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc\n"
238 "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc\n"
239 "\n"
240 "build ./libshlib.so: solink obj/foo/libshlib.input1.o "
241 "obj/foo/libshlib.input2.o\n"
242 " ldflags =\n"
243 " libs =\n"
244 " output_extension = .so\n";
246 std::string out_str = out.str();
247 EXPECT_EQ(expected, out_str);
250 TEST(NinjaBinaryTargetWriter, SourceSetDataDeps) {
251 TestWithScope setup;
252 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
253 setup.settings()->set_target_os(Settings::LINUX);
255 Err err;
257 // This target is a data (runtime) dependency of the intermediate target.
258 Target data(setup.settings(), Label(SourceDir("//foo/"), "data_target"));
259 data.set_output_type(Target::EXECUTABLE);
260 data.visibility().SetPublic();
261 data.SetToolchain(setup.toolchain());
262 ASSERT_TRUE(data.OnResolved(&err));
264 // Intermediate source set target.
265 Target inter(setup.settings(), Label(SourceDir("//foo/"), "inter"));
266 inter.set_output_type(Target::SOURCE_SET);
267 inter.visibility().SetPublic();
268 inter.data_deps().push_back(LabelTargetPair(&data));
269 inter.SetToolchain(setup.toolchain());
270 inter.sources().push_back(SourceFile("//foo/inter.cc"));
271 ASSERT_TRUE(inter.OnResolved(&err)) << err.message();
273 // Write out the intermediate target.
274 std::ostringstream inter_out;
275 NinjaBinaryTargetWriter inter_writer(&inter, inter_out);
276 inter_writer.Run();
278 // The intermediate source set will be a stamp file that depends on the
279 // object files, and will have an order-only dependency on its data dep and
280 // data file.
281 const char inter_expected[] =
282 "defines =\n"
283 "include_dirs =\n"
284 "cflags =\n"
285 "cflags_cc =\n"
286 "root_out_dir = .\n"
287 "target_out_dir = obj/foo\n"
288 "target_output_name = inter\n"
289 "\n"
290 "build obj/foo/inter.inter.o: cxx ../../foo/inter.cc\n"
291 "\n"
292 "build obj/foo/inter.stamp: stamp obj/foo/inter.inter.o || "
293 "./data_target\n";
294 EXPECT_EQ(inter_expected, inter_out.str());
296 // Final target.
297 Target exe(setup.settings(), Label(SourceDir("//foo/"), "exe"));
298 exe.set_output_type(Target::EXECUTABLE);
299 exe.public_deps().push_back(LabelTargetPair(&inter));
300 exe.SetToolchain(setup.toolchain());
301 exe.sources().push_back(SourceFile("//foo/final.cc"));
302 ASSERT_TRUE(exe.OnResolved(&err));
304 std::ostringstream final_out;
305 NinjaBinaryTargetWriter final_writer(&exe, final_out);
306 final_writer.Run();
308 // The final output depends on both object files (one from the final target,
309 // one from the source set) and has an order-only dependency on the source
310 // set's stamp file and the final target's data file. The source set stamp
311 // dependency will create an implicit order-only dependency on the data
312 // target.
313 const char final_expected[] =
314 "defines =\n"
315 "include_dirs =\n"
316 "cflags =\n"
317 "cflags_cc =\n"
318 "root_out_dir = .\n"
319 "target_out_dir = obj/foo\n"
320 "target_output_name = exe\n"
321 "\n"
322 "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n"
323 "\n"
324 "build ./exe: link obj/foo/exe.final.o obj/foo/inter.inter.o || "
325 "obj/foo/inter.stamp\n"
326 " ldflags =\n"
327 " libs =\n"
328 " output_extension = \n";
329 EXPECT_EQ(final_expected, final_out.str());
332 TEST(NinjaBinaryTargetWriter, SharedLibraryModuleDefinitionFile) {
333 TestWithScope setup;
334 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
335 setup.settings()->set_target_os(Settings::WIN);
337 Target shared_lib(setup.settings(), Label(SourceDir("//foo/"), "bar"));
338 shared_lib.set_output_type(Target::SHARED_LIBRARY);
339 shared_lib.SetToolchain(setup.toolchain());
340 shared_lib.sources().push_back(SourceFile("//foo/sources.cc"));
341 shared_lib.sources().push_back(SourceFile("//foo/bar.def"));
343 Err err;
344 ASSERT_TRUE(shared_lib.OnResolved(&err));
346 std::ostringstream out;
347 NinjaBinaryTargetWriter writer(&shared_lib, out);
348 writer.Run();
350 const char expected[] =
351 "defines =\n"
352 "include_dirs =\n"
353 "cflags =\n"
354 "cflags_cc =\n"
355 "root_out_dir = .\n"
356 "target_out_dir = obj/foo\n"
357 "target_output_name = libbar\n"
358 "\n"
359 "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n"
360 "\n"
361 "build ./libbar.so: solink obj/foo/libbar.sources.o | ../../foo/bar.def\n"
362 " ldflags = /DEF:../../foo/bar.def\n"
363 " libs =\n"
364 " output_extension = .so\n";
365 EXPECT_EQ(expected, out.str());
368 TEST(NinjaBinaryTargetWriter, WinPrecompiledHeaders) {
369 Err err;
371 // This setup's toolchain does not have precompiled headers defined.
372 TestWithScope setup;
374 // A precompiled header toolchain.
375 Settings pch_settings(setup.build_settings(), "withpch/");
376 Toolchain pch_toolchain(&pch_settings,
377 Label(SourceDir("//toolchain/"), "withpch"));
379 // Declare a C++ compiler that supports PCH.
380 scoped_ptr<Tool> cxx_tool(new Tool);
381 TestWithScope::SetCommandForTool(
382 "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
383 "-o {{output}}",
384 cxx_tool.get());
385 cxx_tool->set_outputs(SubstitutionList::MakeForTest(
386 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
387 cxx_tool->set_precompiled_header_type(Tool::PCH_MSVC);
388 pch_toolchain.SetTool(Toolchain::TYPE_CXX, cxx_tool.Pass());
389 pch_toolchain.ToolchainSetupComplete();
391 // This target doesn't specify precompiled headers.
393 Target no_pch_target(&pch_settings,
394 Label(SourceDir("//foo/"), "no_pch_target"));
395 no_pch_target.set_output_type(Target::SOURCE_SET);
396 no_pch_target.visibility().SetPublic();
397 no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
398 no_pch_target.SetToolchain(&pch_toolchain);
399 ASSERT_TRUE(no_pch_target.OnResolved(&err));
401 std::ostringstream out;
402 NinjaBinaryTargetWriter writer(&no_pch_target, out);
403 writer.Run();
405 const char no_pch_expected[] =
406 "defines =\n"
407 "include_dirs =\n"
408 "cflags =\n"
409 "cflags_cc =\n"
410 "target_output_name = no_pch_target\n"
411 "\n"
412 "build withpch/obj/foo/no_pch_target.input1.o: "
413 "cxx ../../foo/input1.cc\n"
414 "\n"
415 "build withpch/obj/foo/no_pch_target.stamp: "
416 "stamp withpch/obj/foo/no_pch_target.input1.o\n";
417 EXPECT_EQ(no_pch_expected, out.str());
420 // This target specifies PCH.
422 Target pch_target(&pch_settings,
423 Label(SourceDir("//foo/"), "pch_target"));
424 pch_target.config_values().set_precompiled_header("build/precompile.h");
425 pch_target.config_values().set_precompiled_source(
426 SourceFile("//build/precompile.cc"));
427 pch_target.set_output_type(Target::SOURCE_SET);
428 pch_target.visibility().SetPublic();
429 pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
430 pch_target.SetToolchain(&pch_toolchain);
431 ASSERT_TRUE(pch_target.OnResolved(&err));
433 std::ostringstream out;
434 NinjaBinaryTargetWriter writer(&pch_target, out);
435 writer.Run();
437 const char pch_win_expected[] =
438 "defines =\n"
439 "include_dirs =\n"
440 "cflags =\n"
441 // There should only be one .pch file created, for C++ files.
442 "cflags_cc = /Fpwithpch/obj/foo/pch_target_cc.pch "
443 "/Yubuild/precompile.h\n"
444 "target_output_name = pch_target\n"
445 "\n"
446 // Compile the precompiled source file with /Yc.
447 "build withpch/obj/build/pch_target.precompile.cc.o: "
448 "cxx ../../build/precompile.cc\n"
449 " cflags_cc = ${cflags_cc} /Ycbuild/precompile.h\n"
450 "\n"
451 "build withpch/obj/foo/pch_target.input1.o: "
452 "cxx ../../foo/input1.cc | "
453 // Explicit dependency on the PCH build step.
454 "withpch/obj/build/pch_target.precompile.cc.o\n"
455 "\n"
456 "build withpch/obj/foo/pch_target.stamp: "
457 "stamp withpch/obj/foo/pch_target.input1.o "
458 // The precompiled object file was added to the outputs.
459 "withpch/obj/build/pch_target.precompile.cc.o\n";
460 EXPECT_EQ(pch_win_expected, out.str());
464 // Should throw an error with the scheduler if a duplicate object file exists.
465 // This is dependent on the toolchain's object file mapping.
466 TEST(NinjaBinaryTargetWriter, DupeObjFileError) {
467 Scheduler scheduler;
469 TestWithScope setup;
470 TestTarget target(setup, "//foo:bar", Target::EXECUTABLE);
471 target.sources().push_back(SourceFile("//a.cc"));
472 target.sources().push_back(SourceFile("//a.cc"));
474 EXPECT_FALSE(scheduler.is_failed());
476 std::ostringstream out;
477 NinjaBinaryTargetWriter writer(&target, out);
478 writer.Run();
480 // Should have issued an error.
481 EXPECT_TRUE(scheduler.is_failed());