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/file_template.h"
10 #include "tools/gn/ninja_action_target_writer.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"));
18 target
.action_values().outputs().push_back(
19 SourceFile("//out/Debug/gen/a b{{source_name_part}}.h"));
20 target
.action_values().outputs().push_back(
21 SourceFile("//out/Debug/gen/{{source_name_part}}.cc"));
23 std::ostringstream out
;
24 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
26 FileTemplate output_template
= writer
.GetOutputTemplate();
28 SourceFile
source("//foo/bar.in");
29 std::vector
<OutputFile
> output_files
;
30 writer
.WriteOutputFilesForBuildLine(output_template
, source
, &output_files
);
32 std::string out_str
= out
.str();
34 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
36 EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out_str
);
39 TEST(NinjaActionTargetWriter
, WriteOutputFilesForBuildLineWithDepfile
) {
41 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
42 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
44 target
.action_values().set_depfile(
45 SourceFile("//out/Debug/gen/{{source_name_part}}.d"));
46 target
.action_values().outputs().push_back(
47 SourceFile("//out/Debug/gen/{{source_name_part}}.h"));
48 target
.action_values().outputs().push_back(
49 SourceFile("//out/Debug/gen/{{source_name_part}}.cc"));
51 std::ostringstream out
;
52 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
54 FileTemplate output_template
= writer
.GetOutputTemplate();
56 SourceFile
source("//foo/bar.in");
57 std::vector
<OutputFile
> output_files
;
58 writer
.WriteOutputFilesForBuildLine(output_template
, source
, &output_files
);
60 std::string out_str
= out
.str();
62 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
64 EXPECT_EQ(" gen/bar.d gen/bar.h gen/bar.cc", out_str
);
67 TEST(NinjaActionTargetWriter
, WriteArgsSubstitutions
) {
69 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
70 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
72 std::ostringstream out
;
73 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
75 std::vector
<std::string
> args
;
77 args
.push_back("{{source}}");
78 args
.push_back("--out=foo bar{{source_name_part}}.o");
79 FileTemplate
args_template(args
);
81 writer
.WriteArgsSubstitutions(SourceFile("//foo/b ar.in"), args_template
);
83 std::string out_str
= out
.str();
85 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
87 EXPECT_EQ(" source = ../../foo/b$ ar.in\n source_name_part = b$ ar\n",
91 // Makes sure that we write sources as input dependencies for actions with
92 // both sources and source_prereqs (ACTION_FOREACH treats the sources
94 TEST(NinjaActionTargetWriter
, ActionWithSources
) {
96 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
97 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
98 target
.set_output_type(Target::ACTION
);
100 target
.action_values().set_script(SourceFile("//foo/script.py"));
102 target
.sources().push_back(SourceFile("//foo/source.txt"));
103 target
.source_prereqs().push_back(SourceFile("//foo/included.txt"));
105 target
.action_values().outputs().push_back(
106 SourceFile("//out/Debug/foo.out"));
110 setup
.settings()->set_target_os(Settings::LINUX
);
111 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
112 "/usr/bin/python")));
114 std::ostringstream out
;
115 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
118 const char expected_linux
[] =
119 "rule __foo_bar___rule\n"
120 " command = /usr/bin/python ../../foo/script.py\n"
121 " description = ACTION //foo:bar()\n"
125 "build foo.out: __foo_bar___rule | ../../foo/included.txt ../../foo/source.txt\n"
127 "build obj/foo/bar.stamp: stamp foo.out\n";
128 std::string out_str
= out
.str();
130 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
132 EXPECT_EQ(expected_linux
, out_str
);
137 // Note: we use forward slashes here so that the output will be the same on
138 // Linux and Windows.
139 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
140 "C:/python/python.exe")));
141 setup
.settings()->set_target_os(Settings::WIN
);
143 std::ostringstream out
;
144 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
147 // TODO(brettw) I think we'll need to worry about backslashes here
148 // depending if we're on actual Windows or Linux pretending to be Windows.
149 const char expected_win
[] =
150 "rule __foo_bar___rule\n"
151 " command = C:/python/python.exe gyp-win-tool action-wrapper environment.x86 __foo_bar___rule.$unique_name.rsp\n"
152 " description = ACTION //foo:bar()\n"
154 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
155 " rspfile_content = C:/python/python.exe ../../foo/script.py\n"
157 "build foo.out: __foo_bar___rule | ../../foo/included.txt ../../foo/source.txt\n"
159 "build obj/foo/bar.stamp: stamp foo.out\n";
160 std::string out_str
= out
.str();
162 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
164 EXPECT_EQ(expected_win
, out_str
);
168 TEST(NinjaActionTargetWriter
, ForEach
) {
170 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
171 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
172 target
.set_output_type(Target::ACTION_FOREACH
);
174 target
.sources().push_back(SourceFile("//foo/input1.txt"));
175 target
.sources().push_back(SourceFile("//foo/input2.txt"));
177 target
.action_values().set_script(SourceFile("//foo/script.py"));
179 target
.action_values().args().push_back("-i");
180 target
.action_values().args().push_back("{{source}}");
181 target
.action_values().args().push_back(
182 "--out=foo bar{{source_name_part}}.o");
184 target
.action_values().outputs().push_back(
185 SourceFile("//out/Debug/{{source_name_part}}.out"));
187 target
.source_prereqs().push_back(SourceFile("//foo/included.txt"));
191 setup
.settings()->set_target_os(Settings::LINUX
);
192 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
193 "/usr/bin/python")));
195 std::ostringstream out
;
196 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
199 const char expected_linux
[] =
200 "rule __foo_bar___rule\n"
201 " command = /usr/bin/python ../../foo/script.py -i ${source} "
202 "\"--out=foo$ bar${source_name_part}.o\"\n"
203 " description = ACTION //foo:bar()\n"
206 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
207 "../../foo/included.txt\n"
208 " source = ../../foo/input1.txt\n"
209 " source_name_part = input1\n"
210 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
211 "../../foo/included.txt\n"
212 " source = ../../foo/input2.txt\n"
213 " source_name_part = input2\n"
215 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
217 std::string out_str
= out
.str();
219 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
221 EXPECT_EQ(expected_linux
, out_str
);
226 // Note: we use forward slashes here so that the output will be the same on
227 // Linux and Windows.
228 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
229 "C:/python/python.exe")));
230 setup
.settings()->set_target_os(Settings::WIN
);
232 std::ostringstream out
;
233 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
236 // TODO(brettw) I think we'll need to worry about backslashes here
237 // depending if we're on actual Windows or Linux pretending to be Windows.
238 const char expected_win
[] =
239 "rule __foo_bar___rule\n"
240 " command = C:/python/python.exe gyp-win-tool action-wrapper "
241 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
242 " description = ACTION //foo:bar()\n"
244 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
245 " rspfile_content = C:/python/python.exe ../../foo/script.py -i "
246 "${source} \"--out=foo$ bar${source_name_part}.o\"\n"
248 "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
249 "../../foo/included.txt\n"
251 " source = ../../foo/input1.txt\n"
252 " source_name_part = input1\n"
253 "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
254 "../../foo/included.txt\n"
256 " source = ../../foo/input2.txt\n"
257 " source_name_part = input2\n"
259 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
260 std::string out_str
= out
.str();
262 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
264 EXPECT_EQ(expected_win
, out_str
);
268 TEST(NinjaActionTargetWriter
, ForEachWithDepfile
) {
270 setup
.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
271 Target
target(setup
.settings(), Label(SourceDir("//foo/"), "bar"));
272 target
.set_output_type(Target::ACTION_FOREACH
);
274 target
.sources().push_back(SourceFile("//foo/input1.txt"));
275 target
.sources().push_back(SourceFile("//foo/input2.txt"));
277 target
.action_values().set_script(SourceFile("//foo/script.py"));
278 target
.action_values().set_depfile(
279 SourceFile("//out/Debug/gen/{{source_name_part}}.d"));
281 target
.action_values().args().push_back("-i");
282 target
.action_values().args().push_back("{{source}}");
283 target
.action_values().args().push_back(
284 "--out=foo bar{{source_name_part}}.o");
286 target
.action_values().outputs().push_back(
287 SourceFile("//out/Debug/{{source_name_part}}.out"));
289 target
.source_prereqs().push_back(SourceFile("//foo/included.txt"));
293 setup
.settings()->set_target_os(Settings::LINUX
);
294 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
295 "/usr/bin/python")));
297 std::ostringstream out
;
298 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
301 const char expected_linux
[] =
302 "rule __foo_bar___rule\n"
303 " command = /usr/bin/python ../../foo/script.py -i ${source} "
304 "\"--out=foo$ bar${source_name_part}.o\"\n"
305 " description = ACTION //foo:bar()\n"
308 "build gen/input1.d input1.out: __foo_bar___rule ../../foo/input1.txt"
309 " | ../../foo/included.txt\n"
310 " source = ../../foo/input1.txt\n"
311 " source_name_part = input1\n"
312 " depfile = gen/input1.d\n"
313 "build gen/input2.d input2.out: __foo_bar___rule ../../foo/input2.txt"
314 " | ../../foo/included.txt\n"
315 " source = ../../foo/input2.txt\n"
316 " source_name_part = input2\n"
317 " depfile = gen/input2.d\n"
319 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
321 std::string out_str
= out
.str();
323 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
325 EXPECT_EQ(expected_linux
, out_str
);
330 // Note: we use forward slashes here so that the output will be the same on
331 // Linux and Windows.
332 setup
.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
333 "C:/python/python.exe")));
334 setup
.settings()->set_target_os(Settings::WIN
);
336 std::ostringstream out
;
337 NinjaActionTargetWriter
writer(&target
, setup
.toolchain(), out
);
340 // TODO(brettw) I think we'll need to worry about backslashes here
341 // depending if we're on actual Windows or Linux pretending to be Windows.
342 const char expected_win
[] =
343 "rule __foo_bar___rule\n"
344 " command = C:/python/python.exe gyp-win-tool action-wrapper "
345 "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
346 " description = ACTION //foo:bar()\n"
348 " rspfile = __foo_bar___rule.$unique_name.rsp\n"
349 " rspfile_content = C:/python/python.exe ../../foo/script.py -i "
350 "${source} \"--out=foo$ bar${source_name_part}.o\"\n"
352 "build gen/input1.d input1.out: __foo_bar___rule ../../foo/input1.txt"
353 " | ../../foo/included.txt\n"
355 " source = ../../foo/input1.txt\n"
356 " source_name_part = input1\n"
357 " depfile = gen/input1.d\n"
358 "build gen/input2.d input2.out: __foo_bar___rule ../../foo/input2.txt"
359 " | ../../foo/included.txt\n"
361 " source = ../../foo/input2.txt\n"
362 " source_name_part = input2\n"
363 " depfile = gen/input2.d\n"
365 "build obj/foo/bar.stamp: stamp input1.out input2.out\n";
366 std::string out_str
= out
.str();
368 std::replace(out_str
.begin(), out_str
.end(), '\\', '/');
370 EXPECT_EQ(expected_win
, out_str
);