1 // Copyright 2018 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.
4
5 #include "gn/compile_commands_writer.h"
6
7 #include <memory>
8 #include <sstream>
9 #include <utility>
10
11 #include "gn/config.h"
12 #include "gn/ninja_target_command_util.h"
13 #include "gn/scheduler.h"
14 #include "gn/target.h"
15 #include "gn/test_with_scheduler.h"
16 #include "gn/test_with_scope.h"
17 #include "util/build_config.h"
18 #include "util/test/test.h"
19
20 namespace {
21
22 // InputConversion needs a global scheduler object.
23 class CompileCommandsTest : public TestWithScheduler {
24 public:
25 CompileCommandsTest() = default;
26
build_settings()27 const BuildSettings* build_settings() { return setup_.build_settings(); }
settings()28 const Settings* settings() { return setup_.settings(); }
setup()29 const TestWithScope& setup() { return setup_; }
toolchain()30 const Toolchain* toolchain() { return setup_.toolchain(); }
31
32 private:
33 TestWithScope setup_;
34 };
35
36 } // namespace
37
TEST_F(CompileCommandsTest,SourceSet)38 TEST_F(CompileCommandsTest, SourceSet) {
39 Err err;
40
41 std::vector<const Target*> targets;
42 Target target(settings(), Label(SourceDir("//foo/"), "bar"));
43 target.set_output_type(Target::SOURCE_SET);
44 target.visibility().SetPublic();
45 target.sources().push_back(SourceFile("//foo/input1.cc"));
46 target.sources().push_back(SourceFile("//foo/input2.cc"));
47 // Also test object files, which should be just passed through to the
48 // dependents to link.
49 target.sources().push_back(SourceFile("//foo/input3.o"));
50 target.sources().push_back(SourceFile("//foo/input4.obj"));
51 target.SetToolchain(toolchain());
52 ASSERT_TRUE(target.OnResolved(&err));
53 targets.push_back(&target);
54
55 // Source set itself.
56 {
57 std::string out;
58 CompileCommandsWriter writer;
59 writer.RenderJSON(build_settings(), targets, &out);
60
61 #if defined(OS_WIN)
62 const char expected[] =
63 "[\r\n"
64 " {\r\n"
65 " \"file\": \"../../foo/input1.cc\",\r\n"
66 " \"directory\": \"out/Debug\",\r\n"
67 " \"command\": \"c++ ../../foo/input1.cc -o "
68 "obj/foo/bar.input1.o\"\r\n"
69 " },\r\n"
70 " {\r\n"
71 " \"file\": \"../../foo/input2.cc\",\r\n"
72 " \"directory\": \"out/Debug\",\r\n"
73 " \"command\": \"c++ ../../foo/input2.cc -o "
74 "obj/foo/bar.input2.o\"\r\n"
75 " }\r\n"
76 "]\r\n";
77 #else
78 const char expected[] =
79 "[\n"
80 " {\n"
81 " \"file\": \"../../foo/input1.cc\",\n"
82 " \"directory\": \"out/Debug\",\n"
83 " \"command\": \"c++ ../../foo/input1.cc -o "
84 "obj/foo/bar.input1.o\"\n"
85 " },\n"
86 " {\n"
87 " \"file\": \"../../foo/input2.cc\",\n"
88 " \"directory\": \"out/Debug\",\n"
89 " \"command\": \"c++ ../../foo/input2.cc -o "
90 "obj/foo/bar.input2.o\"\n"
91 " }\n"
92 "]\n";
93 #endif
94 EXPECT_EQ(expected, out);
95 }
96
97 // A shared library that depends on the source set.
98 Target shlib_target(settings(), Label(SourceDir("//foo/"), "shlib"));
99 shlib_target.sources().push_back(SourceFile("//foo/input3.cc"));
100 shlib_target.set_output_type(Target::SHARED_LIBRARY);
101 shlib_target.public_deps().push_back(LabelTargetPair(&target));
102 shlib_target.SetToolchain(toolchain());
103 ASSERT_TRUE(shlib_target.OnResolved(&err));
104 targets.push_back(&shlib_target);
105
106 {
107 std::string out;
108 CompileCommandsWriter writer;
109 writer.RenderJSON(build_settings(), targets, &out);
110
111 #if defined(OS_WIN)
112 const char expected[] =
113 "[\r\n"
114 " {\r\n"
115 " \"file\": \"../../foo/input1.cc\",\r\n"
116 " \"directory\": \"out/Debug\",\r\n"
117 " \"command\": \"c++ ../../foo/input1.cc -o "
118 "obj/foo/bar.input1.o\"\r\n"
119 " },\r\n"
120 " {\r\n"
121 " \"file\": \"../../foo/input2.cc\",\r\n"
122 " \"directory\": \"out/Debug\",\r\n"
123 " \"command\": \"c++ ../../foo/input2.cc -o "
124 "obj/foo/bar.input2.o\"\r\n"
125 " },\r\n"
126 " {\r\n"
127 " \"file\": \"../../foo/input3.cc\",\r\n"
128 " \"directory\": \"out/Debug\",\r\n"
129 " \"command\": \"c++ ../../foo/input3.cc -o "
130 "obj/foo/libshlib.input3.o\"\r\n"
131 " }\r\n"
132 "]\r\n";
133 #else
134 const char expected[] =
135 "[\n"
136 " {\n"
137 " \"file\": \"../../foo/input1.cc\",\n"
138 " \"directory\": \"out/Debug\",\n"
139 " \"command\": \"c++ ../../foo/input1.cc -o "
140 "obj/foo/bar.input1.o\"\n"
141 " },\n"
142 " {\n"
143 " \"file\": \"../../foo/input2.cc\",\n"
144 " \"directory\": \"out/Debug\",\n"
145 " \"command\": \"c++ ../../foo/input2.cc -o "
146 "obj/foo/bar.input2.o\"\n"
147 " },\n"
148 " {\n"
149 " \"file\": \"../../foo/input3.cc\",\n"
150 " \"directory\": \"out/Debug\",\n"
151 " \"command\": \"c++ ../../foo/input3.cc -o "
152 "obj/foo/libshlib.input3.o\"\n"
153 " }\n"
154 "]\n";
155 #endif
156 EXPECT_EQ(expected, out);
157 }
158
159 // A static library that depends on the source set (should not link it).
160 Target stlib_target(settings(), Label(SourceDir("//foo/"), "stlib"));
161 stlib_target.sources().push_back(SourceFile("//foo/input4.cc"));
162 stlib_target.set_output_type(Target::STATIC_LIBRARY);
163 stlib_target.public_deps().push_back(LabelTargetPair(&target));
164 stlib_target.SetToolchain(toolchain());
165 ASSERT_TRUE(stlib_target.OnResolved(&err));
166 targets.push_back(&stlib_target);
167
168 {
169 std::string out;
170 CompileCommandsWriter writer;
171 writer.RenderJSON(build_settings(), targets, &out);
172
173 #if defined(OS_WIN)
174 const char expected[] =
175 "[\r\n"
176 " {\r\n"
177 " \"file\": \"../../foo/input1.cc\",\r\n"
178 " \"directory\": \"out/Debug\",\r\n"
179 " \"command\": \"c++ ../../foo/input1.cc -o "
180 "obj/foo/bar.input1.o\"\r\n"
181 " },\r\n"
182 " {\r\n"
183 " \"file\": \"../../foo/input2.cc\",\r\n"
184 " \"directory\": \"out/Debug\",\r\n"
185 " \"command\": \"c++ ../../foo/input2.cc -o "
186 "obj/foo/bar.input2.o\"\r\n"
187 " },\r\n"
188 " {\r\n"
189 " \"file\": \"../../foo/input3.cc\",\r\n"
190 " \"directory\": \"out/Debug\",\r\n"
191 " \"command\": \"c++ ../../foo/input3.cc -o "
192 "obj/foo/libshlib.input3.o\"\r\n"
193 " },\r\n"
194 " {\r\n"
195 " \"file\": \"../../foo/input4.cc\",\r\n"
196 " \"directory\": \"out/Debug\",\r\n"
197 " \"command\": \"c++ ../../foo/input4.cc -o "
198 "obj/foo/libstlib.input4.o\"\r\n"
199 " }\r\n"
200 "]\r\n";
201 #else
202 const char expected[] =
203 "[\n"
204 " {\n"
205 " \"file\": \"../../foo/input1.cc\",\n"
206 " \"directory\": \"out/Debug\",\n"
207 " \"command\": \"c++ ../../foo/input1.cc -o "
208 "obj/foo/bar.input1.o\"\n"
209 " },\n"
210 " {\n"
211 " \"file\": \"../../foo/input2.cc\",\n"
212 " \"directory\": \"out/Debug\",\n"
213 " \"command\": \"c++ ../../foo/input2.cc -o "
214 "obj/foo/bar.input2.o\"\n"
215 " },\n"
216 " {\n"
217 " \"file\": \"../../foo/input3.cc\",\n"
218 " \"directory\": \"out/Debug\",\n"
219 " \"command\": \"c++ ../../foo/input3.cc -o "
220 "obj/foo/libshlib.input3.o\"\n"
221 " },\n"
222 " {\n"
223 " \"file\": \"../../foo/input4.cc\",\n"
224 " \"directory\": \"out/Debug\",\n"
225 " \"command\": \"c++ ../../foo/input4.cc -o "
226 "obj/foo/libstlib.input4.o\"\n"
227 " }\n"
228 "]\n";
229 #endif
230 EXPECT_EQ(expected, out);
231 }
232 }
233
TEST_F(CompileCommandsTest,EscapeDefines)234 TEST_F(CompileCommandsTest, EscapeDefines) {
235 Err err;
236
237 std::vector<const Target*> targets;
238 TestTarget target(setup(), "//foo:bar", Target::STATIC_LIBRARY);
239 target.sources().push_back(SourceFile("//foo/input.cc"));
240 target.config_values().defines().push_back("BOOL_DEF");
241 target.config_values().defines().push_back("INT_DEF=123");
242 target.config_values().defines().push_back("STR_DEF=\"ABCD 1\"");
243 ASSERT_TRUE(target.OnResolved(&err));
244 targets.push_back(&target);
245
246 std::string out;
247 CompileCommandsWriter writer;
248 writer.RenderJSON(build_settings(), targets, &out);
249
250 const char expected[] =
251 "-DBOOL_DEF -DINT_DEF=123 -DSTR_DEF=\\\\\\\"ABCD\\\\ 1\\\\\\\"";
252 EXPECT_TRUE(out.find(expected) != std::string::npos);
253 }
254
TEST_F(CompileCommandsTest,WinPrecompiledHeaders)255 TEST_F(CompileCommandsTest, WinPrecompiledHeaders) {
256 Err err;
257
258 // This setup's toolchain does not have precompiled headers defined.
259 // A precompiled header toolchain.
260 Settings pch_settings(build_settings(), "withpch/");
261 Toolchain pch_toolchain(&pch_settings,
262 Label(SourceDir("//toolchain/"), "withpch"));
263 pch_settings.set_toolchain_label(pch_toolchain.label());
264 pch_settings.set_default_toolchain_label(toolchain()->label());
265
266 // Declare a C++ compiler that supports PCH.
267 std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
268 CTool* cxx_tool = cxx->AsC();
269 TestWithScope::SetCommandForTool(
270 "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
271 "-o {{output}}",
272 cxx_tool);
273 cxx_tool->set_outputs(SubstitutionList::MakeForTest(
274 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
275 cxx_tool->set_precompiled_header_type(CTool::PCH_MSVC);
276 pch_toolchain.SetTool(std::move(cxx));
277
278 // Add a C compiler as well.
279 std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
280 CTool* cc_tool = cc->AsC();
281 TestWithScope::SetCommandForTool(
282 "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
283 "-o {{output}}",
284 cc_tool);
285 cc_tool->set_outputs(SubstitutionList::MakeForTest(
286 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
287 cc_tool->set_precompiled_header_type(CTool::PCH_MSVC);
288 pch_toolchain.SetTool(std::move(cc));
289 pch_toolchain.ToolchainSetupComplete();
290
291 // This target doesn't specify precompiled headers.
292 {
293 std::vector<const Target*> targets;
294 Target no_pch_target(&pch_settings,
295 Label(SourceDir("//foo/"), "no_pch_target"));
296 no_pch_target.set_output_type(Target::SOURCE_SET);
297 no_pch_target.visibility().SetPublic();
298 no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
299 no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
300 no_pch_target.config_values().cflags_c().push_back("-std=c99");
301 no_pch_target.SetToolchain(&pch_toolchain);
302 ASSERT_TRUE(no_pch_target.OnResolved(&err));
303 targets.push_back(&no_pch_target);
304
305 std::string out;
306 CompileCommandsWriter writer;
307 writer.RenderJSON(build_settings(), targets, &out);
308
309 #if defined(OS_WIN)
310 const char no_pch_expected[] =
311 "[\r\n"
312 " {\r\n"
313 " \"file\": \"../../foo/input1.cc\",\r\n"
314 " \"directory\": \"out/Debug\",\r\n"
315 " \"command\": \"c++ ../../foo/input1.cc -o "
316 "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
317 " },\r\n"
318 " {\r\n"
319 " \"file\": \"../../foo/input2.c\",\r\n"
320 " \"directory\": \"out/Debug\",\r\n"
321 " \"command\": \"cc ../../foo/input2.c -std=c99 -o "
322 "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
323 " }\r\n"
324 "]\r\n";
325 #else
326 const char no_pch_expected[] =
327 "[\n"
328 " {\n"
329 " \"file\": \"../../foo/input1.cc\",\n"
330 " \"directory\": \"out/Debug\",\n"
331 " \"command\": \"c++ ../../foo/input1.cc -o "
332 "withpch/obj/foo/no_pch_target.input1.o\"\n"
333 " },\n"
334 " {\n"
335 " \"file\": \"../../foo/input2.c\",\n"
336 " \"directory\": \"out/Debug\",\n"
337 " \"command\": \"cc ../../foo/input2.c -std=c99 -o "
338 "withpch/obj/foo/no_pch_target.input2.o\"\n"
339 " }\n"
340 "]\n";
341 #endif
342 EXPECT_EQ(no_pch_expected, out);
343 }
344
345 // This target specifies PCH.
346 {
347 std::vector<const Target*> targets;
348 Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
349 pch_target.config_values().set_precompiled_header("build/precompile.h");
350 pch_target.config_values().set_precompiled_source(
351 SourceFile("//build/precompile.cc"));
352 pch_target.set_output_type(Target::SOURCE_SET);
353 pch_target.visibility().SetPublic();
354 pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
355 pch_target.sources().push_back(SourceFile("//foo/input2.c"));
356 pch_target.SetToolchain(&pch_toolchain);
357 ASSERT_TRUE(pch_target.OnResolved(&err));
358 targets.push_back(&pch_target);
359
360 std::string out;
361 CompileCommandsWriter writer;
362 writer.RenderJSON(build_settings(), targets, &out);
363
364 #if defined(OS_WIN)
365 const char pch_win_expected[] =
366 "[\r\n"
367 " {\r\n"
368 " \"file\": \"../../foo/input1.cc\",\r\n"
369 " \"directory\": \"out/Debug\",\r\n"
370 " \"command\": \"c++ ../../foo/input1.cc "
371 "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h -o "
372 "withpch/obj/foo/pch_target.input1.o\"\r\n"
373 " },\r\n"
374 " {\r\n"
375 " \"file\": \"../../foo/input2.c\",\r\n"
376 " \"directory\": \"out/Debug\",\r\n"
377 " \"command\": \"cc ../../foo/input2.c "
378 "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h -o "
379 "withpch/obj/foo/pch_target.input2.o\"\r\n"
380 " }\r\n"
381 "]\r\n";
382 #else
383 const char pch_win_expected[] =
384 "[\n"
385 " {\n"
386 " \"file\": \"../../foo/input1.cc\",\n"
387 " \"directory\": \"out/Debug\",\n"
388 " \"command\": \"c++ ../../foo/input1.cc "
389 "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h -o "
390 "withpch/obj/foo/pch_target.input1.o\"\n"
391 " },\n"
392 " {\n"
393 " \"file\": \"../../foo/input2.c\",\n"
394 " \"directory\": \"out/Debug\",\n"
395 " \"command\": \"cc ../../foo/input2.c "
396 "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h -o "
397 "withpch/obj/foo/pch_target.input2.o\"\n"
398 " }\n"
399 "]\n";
400 #endif
401 EXPECT_EQ(pch_win_expected, out);
402 }
403 }
404
TEST_F(CompileCommandsTest,GCCPrecompiledHeaders)405 TEST_F(CompileCommandsTest, GCCPrecompiledHeaders) {
406 Err err;
407
408 // This setup's toolchain does not have precompiled headers defined.
409 // A precompiled header toolchain.
410 Settings pch_settings(build_settings(), "withpch/");
411 Toolchain pch_toolchain(&pch_settings,
412 Label(SourceDir("//toolchain/"), "withpch"));
413 pch_settings.set_toolchain_label(pch_toolchain.label());
414 pch_settings.set_default_toolchain_label(toolchain()->label());
415
416 // Declare a C++ compiler that supports PCH.
417 std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
418 CTool* cxx_tool = cxx->AsC();
419 TestWithScope::SetCommandForTool(
420 "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
421 "-o {{output}}",
422 cxx_tool);
423 cxx_tool->set_outputs(SubstitutionList::MakeForTest(
424 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
425 cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
426 pch_toolchain.SetTool(std::move(cxx));
427 pch_toolchain.ToolchainSetupComplete();
428
429 // Add a C compiler as well.
430 std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
431 CTool* cc_tool = cc->AsC();
432 TestWithScope::SetCommandForTool(
433 "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
434 "-o {{output}}",
435 cc_tool);
436 cc_tool->set_outputs(SubstitutionList::MakeForTest(
437 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
438 cc_tool->set_precompiled_header_type(CTool::PCH_GCC);
439 pch_toolchain.SetTool(std::move(cc));
440 pch_toolchain.ToolchainSetupComplete();
441
442 // This target doesn't specify precompiled headers.
443 {
444 std::vector<const Target*> targets;
445 Target no_pch_target(&pch_settings,
446 Label(SourceDir("//foo/"), "no_pch_target"));
447 no_pch_target.set_output_type(Target::SOURCE_SET);
448 no_pch_target.visibility().SetPublic();
449 no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
450 no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
451 no_pch_target.config_values().cflags_c().push_back("-std=c99");
452 no_pch_target.SetToolchain(&pch_toolchain);
453 ASSERT_TRUE(no_pch_target.OnResolved(&err));
454 targets.push_back(&no_pch_target);
455
456 std::string out;
457 CompileCommandsWriter writer;
458 writer.RenderJSON(build_settings(), targets, &out);
459
460 #if defined(OS_WIN)
461 const char no_pch_expected[] =
462 "[\r\n"
463 " {\r\n"
464 " \"file\": \"../../foo/input1.cc\",\r\n"
465 " \"directory\": \"out/Debug\",\r\n"
466 " \"command\": \"c++ ../../foo/input1.cc -o "
467 "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
468 " },\r\n"
469 " {\r\n"
470 " \"file\": \"../../foo/input2.c\",\r\n"
471 " \"directory\": \"out/Debug\",\r\n"
472 " \"command\": \"cc ../../foo/input2.c -std=c99 -o "
473 "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
474 " }\r\n"
475 "]\r\n";
476 #else
477 const char no_pch_expected[] =
478 "[\n"
479 " {\n"
480 " \"file\": \"../../foo/input1.cc\",\n"
481 " \"directory\": \"out/Debug\",\n"
482 " \"command\": \"c++ ../../foo/input1.cc -o "
483 "withpch/obj/foo/no_pch_target.input1.o\"\n"
484 " },\n"
485 " {\n"
486 " \"file\": \"../../foo/input2.c\",\n"
487 " \"directory\": \"out/Debug\",\n"
488 " \"command\": \"cc ../../foo/input2.c -std=c99 -o "
489 "withpch/obj/foo/no_pch_target.input2.o\"\n"
490 " }\n"
491 "]\n";
492 #endif
493 EXPECT_EQ(no_pch_expected, out);
494 }
495
496 // This target specifies PCH.
497 {
498 std::vector<const Target*> targets;
499 Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
500 pch_target.config_values().set_precompiled_source(
501 SourceFile("//build/precompile.h"));
502 pch_target.config_values().cflags_c().push_back("-std=c99");
503 pch_target.set_output_type(Target::SOURCE_SET);
504 pch_target.visibility().SetPublic();
505 pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
506 pch_target.sources().push_back(SourceFile("//foo/input2.c"));
507 pch_target.SetToolchain(&pch_toolchain);
508 ASSERT_TRUE(pch_target.OnResolved(&err));
509 targets.push_back(&pch_target);
510
511 std::string out;
512 CompileCommandsWriter writer;
513 writer.RenderJSON(build_settings(), targets, &out);
514
515 #if defined(OS_WIN)
516 const char pch_gcc_expected[] =
517 "[\r\n"
518 " {\r\n"
519 " \"file\": \"../../foo/input1.cc\",\r\n"
520 " \"directory\": \"out/Debug\",\r\n"
521 " \"command\": \"c++ ../../foo/input1.cc -include "
522 "withpch/obj/build/pch_target.precompile.h-cc -o "
523 "withpch/obj/foo/pch_target.input1.o\"\r\n"
524 " },\r\n"
525 " {\r\n"
526 " \"file\": \"../../foo/input2.c\",\r\n"
527 " \"directory\": \"out/Debug\",\r\n"
528 " \"command\": \"cc ../../foo/input2.c -std=c99 -include "
529 "withpch/obj/build/pch_target.precompile.h-c -o "
530 "withpch/obj/foo/pch_target.input2.o\"\r\n"
531 " }\r\n"
532 "]\r\n";
533 #else
534 const char pch_gcc_expected[] =
535 "[\n"
536 " {\n"
537 " \"file\": \"../../foo/input1.cc\",\n"
538 " \"directory\": \"out/Debug\",\n"
539 " \"command\": \"c++ ../../foo/input1.cc -include "
540 "withpch/obj/build/pch_target.precompile.h-cc -o "
541 "withpch/obj/foo/pch_target.input1.o\"\n"
542 " },\n"
543 " {\n"
544 " \"file\": \"../../foo/input2.c\",\n"
545 " \"directory\": \"out/Debug\",\n"
546 " \"command\": \"cc ../../foo/input2.c -std=c99 -include "
547 "withpch/obj/build/pch_target.precompile.h-c -o "
548 "withpch/obj/foo/pch_target.input2.o\"\n"
549 " }\n"
550 "]\n";
551 #endif
552 EXPECT_EQ(pch_gcc_expected, out);
553 }
554 }
555
TEST_F(CompileCommandsTest,EscapedFlags)556 TEST_F(CompileCommandsTest, EscapedFlags) {
557 Err err;
558
559 std::vector<const Target*> targets;
560 Target target(settings(), Label(SourceDir("//foo/"), "bar"));
561 target.set_output_type(Target::SOURCE_SET);
562 target.sources().push_back(SourceFile("//foo/input1.c"));
563 target.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
564 target.SetToolchain(toolchain());
565 ASSERT_TRUE(target.OnResolved(&err));
566 targets.push_back(&target);
567
568 std::string out;
569 CompileCommandsWriter writer;
570 writer.RenderJSON(build_settings(), targets, &out);
571
572 #if defined(OS_WIN)
573 const char expected[] =
574 "[\r\n"
575 " {\r\n"
576 " \"file\": \"../../foo/input1.c\",\r\n"
577 " \"directory\": \"out/Debug\",\r\n"
578 " \"command\": \"cc ../../foo/input1.c -DCONFIG=\\\"/config\\\" "
579 "-o obj/foo/bar.input1.o\"\r\n"
580 " }\r\n"
581 "]\r\n";
582 #else
583 const char expected[] =
584 "[\n"
585 " {\n"
586 " \"file\": \"../../foo/input1.c\",\n"
587 " \"directory\": \"out/Debug\",\n"
588 " \"command\": \"cc ../../foo/input1.c -DCONFIG=\\\"/config\\\" "
589 "-o obj/foo/bar.input1.o\"\n"
590 " }\n"
591 "]\n";
592 #endif
593 EXPECT_EQ(expected, out);
594 }
595
TEST_F(CompileCommandsTest,CompDBFilter)596 TEST_F(CompileCommandsTest, CompDBFilter) {
597 Err err;
598
599 std::vector<const Target*> targets;
600 Target target1(settings(), Label(SourceDir("//foo/"), "bar1"));
601 target1.set_output_type(Target::SOURCE_SET);
602 target1.sources().push_back(SourceFile("//foo/input1.c"));
603 target1.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
604 target1.SetToolchain(toolchain());
605 ASSERT_TRUE(target1.OnResolved(&err));
606 targets.push_back(&target1);
607
608 Target target2(settings(), Label(SourceDir("//foo/"), "bar2"));
609 target2.set_output_type(Target::SOURCE_SET);
610 target2.sources().push_back(SourceFile("//foo/input2.c"));
611 target2.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
612 target2.SetToolchain(toolchain());
613 ASSERT_TRUE(target2.OnResolved(&err));
614 targets.push_back(&target2);
615
616 Target target3(settings(), Label(SourceDir("//foo/"), "bar3"));
617 target3.set_output_type(Target::SOURCE_SET);
618 target3.sources().push_back(SourceFile("//foo/input3.c"));
619 target3.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
620 target3.SetToolchain(toolchain());
621 ASSERT_TRUE(target3.OnResolved(&err));
622 targets.push_back(&target3);
623
624 target1.private_deps().push_back(LabelTargetPair(&target2));
625 target1.private_deps().push_back(LabelTargetPair(&target3));
626
627 CompileCommandsWriter writer;
628
629 std::set<std::string> filter1;
630 std::vector<const Target*> test_results1 =
631 writer.FilterTargets(targets, filter1);
632 ASSERT_TRUE(test_results1.empty());
633
634 std::set<std::string> filter2;
635 filter2.insert(target1.label().name());
636 std::vector<const Target*> test_results2 =
637 writer.FilterTargets(targets, filter2);
638 ASSERT_EQ(test_results2, targets);
639
640 std::set<std::string> filter3;
641 filter3.insert(target2.label().name());
642 std::vector<const Target*> test_result3 =
643 writer.FilterTargets(targets, filter3);
644 std::vector<const Target*> expected_results3;
645 expected_results3.push_back(&target2);
646 ASSERT_EQ(test_result3, expected_results3);
647 }
648