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