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/test_with_scope.h"
13 TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLine) {
15 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
16 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
17 target.action_values().outputs() = SubstitutionList::MakeForTest(
18 "//out/Debug/gen/a b{{source_name_part}}.h",
19 "//out/Debug/gen/{{source_name_part}}.cc");
21 std::ostringstream out;
22 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
24 SourceFile source("//foo/bar.in");
25 std::vector<OutputFile> output_files;
26 writer.WriteOutputFilesForBuildLine(source, &output_files);
28 EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out.str());
31 // Tests an action with no sources.
32 TEST(NinjaActionTargetWriter, ActionNoSources) {
34 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
35 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
36 target.set_output_type(Target::ACTION);
38 target.action_values().set_script(SourceFile("//foo/script.py"));
39 target.inputs().push_back(SourceFile("//foo/included.txt"));
41 target.action_values().outputs() =
42 SubstitutionList::MakeForTest("//out/Debug/foo.out");
44 setup.settings()->set_target_os(Settings::LINUX);
45 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
48 std::ostringstream out;
49 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
52 const char expected[] =
53 "rule __foo_bar___rule\n"
54 " command = /usr/bin/python ../../foo/script.py\n"
55 " description = ACTION //foo:bar()\n"
57 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
58 "../../foo/included.txt\n"
60 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
62 "build obj/foo/bar.stamp: stamp foo.out\n";
63 EXPECT_EQ(expected, out.str());
66 // Makes sure that we write sources as input dependencies for actions with
67 // both sources and inputs (ACTION_FOREACH treats the sources differently).
68 TEST(NinjaActionTargetWriter, ActionWithSources) {
70 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
71 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
72 target.set_output_type(Target::ACTION);
74 target.action_values().set_script(SourceFile("//foo/script.py"));
76 target.sources().push_back(SourceFile("//foo/source.txt"));
77 target.inputs().push_back(SourceFile("//foo/included.txt"));
79 target.action_values().outputs() =
80 SubstitutionList::MakeForTest("//out/Debug/foo.out");
84 setup.settings()->set_target_os(Settings::LINUX);
85 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
88 std::ostringstream out;
89 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
92 const char expected_linux[] =
93 "rule __foo_bar___rule\n"
94 " command = /usr/bin/python ../../foo/script.py\n"
95 " description = ACTION //foo:bar()\n"
97 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
98 "../../foo/included.txt ../../foo/source.txt\n"
100 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
102 "build obj/foo/bar.stamp: stamp foo.out\n";
103 EXPECT_EQ(expected_linux, out.str());
108 // Note: we use forward slashes here so that the output will be the same on
109 // Linux and Windows.
110 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
111 "C:/python/python.exe")));
112 setup.settings()->set_target_os(Settings::WIN);
114 std::ostringstream out;
115 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
118 const char expected_win[] =
119 "rule __foo_bar___rule\n"
120 " command = C$:/python/python.exe gyp-win-tool action-wrapper environment.x86 __foo_bar___rule.$unique_name.rsp\n"
121 " description = ACTION //foo:bar()\n"
123 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
124 " rspfile_content = C$:/python/python.exe ../../foo/script.py\n"
125 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
126 "../../foo/included.txt ../../foo/source.txt\n"
128 "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
130 "build obj/foo/bar.stamp: stamp foo.out\n";
131 EXPECT_EQ(expected_win, out.str());
135 TEST(NinjaActionTargetWriter, ForEach) {
137 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
139 // Some dependencies that the action can depend on. Use actions for these
140 // so they have a nice platform-independent stamp file that can appear in the
141 // output (rather than having to worry about how the current platform names
143 Target dep(setup.settings(), Label(SourceDir("//foo/"), "dep"));
144 dep.set_output_type(Target::ACTION);
145 Target datadep(setup.settings(), Label(SourceDir("//foo/"), "datadep"));
146 datadep.set_output_type(Target::ACTION);
148 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
149 target.set_output_type(Target::ACTION_FOREACH);
150 target.deps().push_back(LabelTargetPair(&dep));
151 target.datadeps().push_back(LabelTargetPair(&datadep));
153 target.sources().push_back(SourceFile("//foo/input1.txt"));
154 target.sources().push_back(SourceFile("//foo/input2.txt"));
156 target.action_values().set_script(SourceFile("//foo/script.py"));
158 target.action_values().args() = SubstitutionList::MakeForTest(
161 "--out=foo bar{{source_name_part}}.o");
162 target.action_values().outputs() = SubstitutionList::MakeForTest(
163 "//out/Debug/{{source_name_part}}.out");
165 target.inputs().push_back(SourceFile("//foo/included.txt"));
169 setup.settings()->set_target_os(Settings::LINUX);
170 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
171 "/usr/bin/python")));
173 std::ostringstream out;
174 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
177 const char expected_linux[] =
178 "rule __foo_bar___rule\n"
179 " command = /usr/bin/python ../../foo/script.py -i ${in} "
180 // Escaping is different between Windows and Posix.
182 "\"--out=foo$ bar${source_name_part}.o\"\n"
184 "--out=foo\\$ bar${source_name_part}.o\n"
186 " description = ACTION //foo:bar()\n"
188 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
189 "../../foo/included.txt obj/foo/dep.stamp\n"
191 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
192 "obj/foo/bar.inputdeps.stamp\n"
193 " source_name_part = input1\n"
194 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
195 "obj/foo/bar.inputdeps.stamp\n"
196 " source_name_part = input2\n"
198 "build obj/foo/bar.stamp: "
199 "stamp input1.out input2.out obj/foo/datadep.stamp\n";
201 std::string out_str = out.str();
203 std::replace(out_str.begin(), out_str.end(), '\\', '/');
205 EXPECT_EQ(expected_linux, out_str);
210 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
211 "C:/python/python.exe")));
212 setup.settings()->set_target_os(Settings::WIN);
214 std::ostringstream out;
215 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
218 const char expected_win[] =
219 "rule __foo_bar___rule\n"
220 " command = C$:/python/python.exe gyp-win-tool action-wrapper "
221 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
222 " description = ACTION //foo:bar()\n"
224 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
225 " rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
227 "${in} \"--out=foo$ bar${source_name_part}.o\"\n"
229 "${in} --out=foo\\$ bar${source_name_part}.o\n"
231 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
232 "../../foo/included.txt obj/foo/dep.stamp\n"
234 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
235 "obj/foo/bar.inputdeps.stamp\n"
237 " source_name_part = input1\n"
238 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
239 "obj/foo/bar.inputdeps.stamp\n"
241 " source_name_part = input2\n"
243 "build obj/foo/bar.stamp: "
244 "stamp input1.out input2.out obj/foo/datadep.stamp\n";
245 EXPECT_EQ(expected_win, out.str());
249 TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
251 setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
252 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
253 target.set_output_type(Target::ACTION_FOREACH);
255 target.sources().push_back(SourceFile("//foo/input1.txt"));
256 target.sources().push_back(SourceFile("//foo/input2.txt"));
258 target.action_values().set_script(SourceFile("//foo/script.py"));
260 SubstitutionPattern depfile;
263 depfile.Parse("//out/Debug/gen/{{source_name_part}}.d", NULL, &err));
264 target.action_values().set_depfile(depfile);
266 target.action_values().args() = SubstitutionList::MakeForTest(
269 "--out=foo bar{{source_name_part}}.o");
270 target.action_values().outputs() = SubstitutionList::MakeForTest(
271 "//out/Debug/{{source_name_part}}.out");
273 target.inputs().push_back(SourceFile("//foo/included.txt"));
277 setup.settings()->set_target_os(Settings::LINUX);
278 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
279 "/usr/bin/python")));
281 std::ostringstream out;
282 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
285 const char expected_linux[] =
286 "rule __foo_bar___rule\n"
287 " command = /usr/bin/python ../../foo/script.py -i ${in} "
289 "\"--out=foo$ bar${source_name_part}.o\"\n"
291 "--out=foo\\$ bar${source_name_part}.o\n"
293 " description = ACTION //foo:bar()\n"
295 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
296 "../../foo/included.txt\n"
298 "build input1.out: __foo_bar___rule ../../foo/input1.txt"
299 " | obj/foo/bar.inputdeps.stamp\n"
300 " source_name_part = input1\n"
301 " depfile = gen/input1.d\n"
302 "build input2.out: __foo_bar___rule ../../foo/input2.txt"
303 " | obj/foo/bar.inputdeps.stamp\n"
304 " source_name_part = input2\n"
305 " depfile = gen/input2.d\n"
307 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
308 EXPECT_EQ(expected_linux, out.str());
313 setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
314 "C:/python/python.exe")));
315 setup.settings()->set_target_os(Settings::WIN);
317 std::ostringstream out;
318 NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
321 const char expected_win[] =
322 "rule __foo_bar___rule\n"
323 " command = C$:/python/python.exe gyp-win-tool action-wrapper "
324 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
325 " description = ACTION //foo:bar()\n"
327 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
328 " rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
330 "${in} \"--out=foo$ bar${source_name_part}.o\"\n"
332 "${in} --out=foo\\$ bar${source_name_part}.o\n"
334 "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
335 "../../foo/included.txt\n"
337 "build input1.out: __foo_bar___rule ../../foo/input1.txt"
338 " | obj/foo/bar.inputdeps.stamp\n"
340 " source_name_part = input1\n"
341 " depfile = gen/input1.d\n"
342 "build input2.out: __foo_bar___rule ../../foo/input2.txt"
343 " | obj/foo/bar.inputdeps.stamp\n"
345 " source_name_part = input2\n"
346 " depfile = gen/input2.d\n"
348 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
349 EXPECT_EQ(expected_win, out.str());