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.
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "tools/gn/ninja_action_target_writer.h"
10 #include "tools/gn/substitution_list.h"
11 #include "tools/gn/target.h"
12 #include "tools/gn/test_with_scope.h"
14 TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLine) {
18 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
20 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
21 target.set_output_type(Target::ACTION_FOREACH);
22 target.action_values().outputs() = SubstitutionList::MakeForTest(
23 "//out/Debug/gen/a b{{source_name_part}}.h",
24 "//out/Debug/gen/{{source_name_part}}.cc");
26 target.SetToolchain(setup.toolchain());
27 ASSERT_TRUE(target.OnResolved(&err));
29 std::ostringstream out;
30 NinjaActionTargetWriter writer(&target, out);
32 SourceFile source("//foo/bar.in");
33 std::vector<OutputFile> output_files;
34 writer.WriteOutputFilesForBuildLine(source, &output_files);
36 EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out.str());
39 // Tests an action with no sources.
40 TEST(NinjaActionTargetWriter, ActionNoSources) {
44 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
45 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
46 target.set_output_type(Target::ACTION);
48 target.action_values().set_script(SourceFile("//foo/script.py"));
49 target.inputs().push_back(SourceFile("//foo/included.txt"));
51 target.action_values().outputs() =
52 SubstitutionList::MakeForTest("//out/Debug/foo.out");
54 target.SetToolchain(setup.toolchain());
55 ASSERT_TRUE(target.OnResolved(&err));
57 setup.settings()->set_target_os(Settings::LINUX);
58 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
61 std::ostringstream out;
62 NinjaActionTargetWriter writer(&target, out);
65 const char expected[] =
66 "rule __foo_bar___rule\n"
67 " command = /usr/bin/python ../../foo/script.py\n"
68 " description = ACTION //foo:bar()\n"
70 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
71 "../../foo/included.txt\n"
73 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
75 "build obj/foo/bar.stamp: stamp foo.out\n";
76 EXPECT_EQ(expected, out.str());
79 // Makes sure that we write sources as input dependencies for actions with
80 // both sources and inputs (ACTION_FOREACH treats the sources differently).
81 TEST(NinjaActionTargetWriter, ActionWithSources) {
85 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
86 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
87 target.set_output_type(Target::ACTION);
89 target.action_values().set_script(SourceFile("//foo/script.py"));
91 target.sources().push_back(SourceFile("//foo/source.txt"));
92 target.inputs().push_back(SourceFile("//foo/included.txt"));
94 target.action_values().outputs() =
95 SubstitutionList::MakeForTest("//out/Debug/foo.out");
97 target.SetToolchain(setup.toolchain());
98 ASSERT_TRUE(target.OnResolved(&err));
102 setup.settings()->set_target_os(Settings::LINUX);
103 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
104 "/usr/bin/python")));
106 std::ostringstream out;
107 NinjaActionTargetWriter writer(&target, out);
110 const char expected_linux[] =
111 "rule __foo_bar___rule\n"
112 " command = /usr/bin/python ../../foo/script.py\n"
113 " description = ACTION //foo:bar()\n"
115 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
116 "../../foo/included.txt ../../foo/source.txt\n"
118 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
120 "build obj/foo/bar.stamp: stamp foo.out\n";
121 EXPECT_EQ(expected_linux, out.str());
126 // Note: we use forward slashes here so that the output will be the same on
127 // Linux and Windows.
128 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
129 "C:/python/python.exe")));
130 setup.settings()->set_target_os(Settings::WIN);
132 std::ostringstream out;
133 NinjaActionTargetWriter writer(&target, out);
136 const char expected_win[] =
137 "rule __foo_bar___rule\n"
138 " command = C$:/python/python.exe gyp-win-tool action-wrapper environment.x86 __foo_bar___rule.$unique_name.rsp\n"
139 " description = ACTION //foo:bar()\n"
141 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
142 " rspfile_content = C$:/python/python.exe ../../foo/script.py\n"
143 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
144 "../../foo/included.txt ../../foo/source.txt\n"
146 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
148 "build obj/foo/bar.stamp: stamp foo.out\n";
149 EXPECT_EQ(expected_win, out.str());
153 TEST(NinjaActionTargetWriter, ForEach) {
157 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
159 // Some dependencies that the action can depend on. Use actions for these
160 // so they have a nice platform-independent stamp file that can appear in the
161 // output (rather than having to worry about how the current platform names
163 Target dep(setup.settings(), Label(SourceDir("//foo/"), "dep"));
164 dep.set_output_type(Target::ACTION);
165 dep.visibility().SetPublic();
166 dep.SetToolchain(setup.toolchain());
167 ASSERT_TRUE(dep.OnResolved(&err));
169 Target datadep(setup.settings(), Label(SourceDir("//foo/"), "datadep"));
170 datadep.set_output_type(Target::ACTION);
171 datadep.visibility().SetPublic();
172 datadep.SetToolchain(setup.toolchain());
173 ASSERT_TRUE(datadep.OnResolved(&err));
175 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
176 target.set_output_type(Target::ACTION_FOREACH);
177 target.private_deps().push_back(LabelTargetPair(&dep));
178 target.data_deps().push_back(LabelTargetPair(&datadep));
180 target.sources().push_back(SourceFile("//foo/input1.txt"));
181 target.sources().push_back(SourceFile("//foo/input2.txt"));
183 target.action_values().set_script(SourceFile("//foo/script.py"));
185 target.action_values().args() = SubstitutionList::MakeForTest(
188 "--out=foo bar{{source_name_part}}.o");
189 target.action_values().outputs() = SubstitutionList::MakeForTest(
190 "//out/Debug/{{source_name_part}}.out");
192 target.inputs().push_back(SourceFile("//foo/included.txt"));
194 target.SetToolchain(setup.toolchain());
195 ASSERT_TRUE(target.OnResolved(&err));
199 setup.settings()->set_target_os(Settings::LINUX);
200 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
201 "/usr/bin/python")));
203 std::ostringstream out;
204 NinjaActionTargetWriter writer(&target, out);
207 const char expected_linux[] =
208 "rule __foo_bar___rule\n"
209 " command = /usr/bin/python ../../foo/script.py -i ${in} "
210 // Escaping is different between Windows and Posix.
212 "\"--out=foo$ bar${source_name_part}.o\"\n"
214 "--out=foo\\$ bar${source_name_part}.o\n"
216 " description = ACTION //foo:bar()\n"
218 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
219 "../../foo/included.txt obj/foo/dep.stamp\n"
221 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
222 "obj/foo/bar.inputdeps.stamp\n"
223 " source_name_part = input1\n"
224 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
225 "obj/foo/bar.inputdeps.stamp\n"
226 " source_name_part = input2\n"
228 "build obj/foo/bar.stamp: "
229 "stamp input1.out input2.out || obj/foo/datadep.stamp\n";
231 std::string out_str = out.str();
233 std::replace(out_str.begin(), out_str.end(), '\\', '/');
235 EXPECT_EQ(expected_linux, out_str);
240 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
241 "C:/python/python.exe")));
242 setup.settings()->set_target_os(Settings::WIN);
244 std::ostringstream out;
245 NinjaActionTargetWriter writer(&target, out);
248 const char expected_win[] =
249 "rule __foo_bar___rule\n"
250 " command = C$:/python/python.exe gyp-win-tool action-wrapper "
251 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
252 " description = ACTION //foo:bar()\n"
254 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
255 " rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
257 "${in} \"--out=foo$ bar${source_name_part}.o\"\n"
259 "${in} --out=foo\\$ bar${source_name_part}.o\n"
261 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
262 "../../foo/included.txt obj/foo/dep.stamp\n"
264 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
265 "obj/foo/bar.inputdeps.stamp\n"
267 " source_name_part = input1\n"
268 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
269 "obj/foo/bar.inputdeps.stamp\n"
271 " source_name_part = input2\n"
273 "build obj/foo/bar.stamp: "
274 "stamp input1.out input2.out || obj/foo/datadep.stamp\n";
275 EXPECT_EQ(expected_win, out.str());
279 TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
283 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
284 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
285 target.set_output_type(Target::ACTION_FOREACH);
287 target.sources().push_back(SourceFile("//foo/input1.txt"));
288 target.sources().push_back(SourceFile("//foo/input2.txt"));
290 target.action_values().set_script(SourceFile("//foo/script.py"));
292 target.SetToolchain(setup.toolchain());
293 ASSERT_TRUE(target.OnResolved(&err));
295 SubstitutionPattern depfile;
297 depfile.Parse("//out/Debug/gen/{{source_name_part}}.d", NULL, &err));
298 target.action_values().set_depfile(depfile);
300 target.action_values().args() = SubstitutionList::MakeForTest(
303 "--out=foo bar{{source_name_part}}.o");
304 target.action_values().outputs() = SubstitutionList::MakeForTest(
305 "//out/Debug/{{source_name_part}}.out");
307 target.inputs().push_back(SourceFile("//foo/included.txt"));
311 setup.settings()->set_target_os(Settings::LINUX);
312 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
313 "/usr/bin/python")));
315 std::ostringstream out;
316 NinjaActionTargetWriter writer(&target, out);
319 const char expected_linux[] =
320 "rule __foo_bar___rule\n"
321 " command = /usr/bin/python ../../foo/script.py -i ${in} "
323 "\"--out=foo$ bar${source_name_part}.o\"\n"
325 "--out=foo\\$ bar${source_name_part}.o\n"
327 " description = ACTION //foo:bar()\n"
329 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
330 "../../foo/included.txt\n"
332 "build input1.out: __foo_bar___rule ../../foo/input1.txt"
333 " | obj/foo/bar.inputdeps.stamp\n"
334 " source_name_part = input1\n"
335 " depfile = gen/input1.d\n"
336 "build input2.out: __foo_bar___rule ../../foo/input2.txt"
337 " | obj/foo/bar.inputdeps.stamp\n"
338 " source_name_part = input2\n"
339 " depfile = gen/input2.d\n"
341 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
342 EXPECT_EQ(expected_linux, out.str());
347 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
348 "C:/python/python.exe")));
349 setup.settings()->set_target_os(Settings::WIN);
351 std::ostringstream out;
352 NinjaActionTargetWriter writer(&target, out);
355 const char expected_win[] =
356 "rule __foo_bar___rule\n"
357 " command = C$:/python/python.exe gyp-win-tool action-wrapper "
358 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
359 " description = ACTION //foo:bar()\n"
361 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
362 " rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
364 "${in} \"--out=foo$ bar${source_name_part}.o\"\n"
366 "${in} --out=foo\\$ bar${source_name_part}.o\n"
368 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
369 "../../foo/included.txt\n"
371 "build input1.out: __foo_bar___rule ../../foo/input1.txt"
372 " | obj/foo/bar.inputdeps.stamp\n"
374 " source_name_part = input1\n"
375 " depfile = gen/input1.d\n"
376 "build input2.out: __foo_bar___rule ../../foo/input2.txt"
377 " | obj/foo/bar.inputdeps.stamp\n"
379 " source_name_part = input2\n"
380 " depfile = gen/input2.d\n"
382 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
383 EXPECT_EQ(expected_win, out.str());