OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/ninja_binary_target_writer.h" | 5 #include "tools/gn/ninja_binary_target_writer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include <cstring> | 10 #include <cstring> |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 } | 263 } |
264 | 264 |
265 void NinjaBinaryTargetWriter::Run() { | 265 void NinjaBinaryTargetWriter::Run() { |
266 // Figure out what source types are needed. | 266 // Figure out what source types are needed. |
267 SourceFileTypeSet used_types; | 267 SourceFileTypeSet used_types; |
268 for (const auto& source : target_->sources()) | 268 for (const auto& source : target_->sources()) |
269 used_types.Set(GetSourceFileType(source)); | 269 used_types.Set(GetSourceFileType(source)); |
270 | 270 |
271 WriteCompilerVars(used_types); | 271 WriteCompilerVars(used_types); |
272 | 272 |
273 // The input dependencies will be an order-only dependency. This will cause | 273 // The input dependencies will be an implicit dependency. This will cause |
274 // Ninja to make sure the inputs are up to date before compiling this source, | 274 // Ninja to make sure the inputs are up to date before compiling this source; |
275 // but changes in the inputs deps won't cause the file to be recompiled. | 275 // changes in the inputs deps will cause the file to be recompiled. |
276 // | 276 // |
277 // This is important to prevent changes in unrelated actions that are | 277 // This is to make sure that we force rebuild the source when the inputs |
278 // upstream of this target from causing everything to be recompiled. | 278 // change. Why cannot we rely on the dependencies computed by the compiler? |
279 // | 279 // These dependencies only include headers and might miss other resources |
280 // Why can we get away with this rather than using implicit deps ("|", which | 280 // that are used by the input file. |
281 // will force rebuilds when the inputs change)? For source code, the | 281 OutputFile input_dep = |
282 // computed dependencies of all headers will be computed by the compiler, | |
283 // which will cause source rebuilds if any "real" upstream dependencies | |
284 // change. | |
285 // | |
286 // If a .cc file is generated by an input dependency, Ninja will see the | |
287 // input to the build rule doesn't exist, and that it is an output from a | |
288 // previous step, and build the previous step first. This is a "real" | |
289 // dependency and doesn't need | or || to express. | |
290 // | |
291 // The only case where this rule matters is for the first build where no .d | |
292 // files exist, and Ninja doesn't know what that source file depends on. In | |
293 // this case it's sufficient to ensure that the upstream dependencies are | |
294 // built first. This is exactly what Ninja's order-only dependencies | |
295 // expresses. | |
296 OutputFile order_only_dep = | |
297 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); | 282 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); |
298 | 283 |
299 // For GCC builds, the .gch files are not object files, but still need to be | 284 // For GCC builds, the .gch files are not object files, but still need to be |
300 // added as explicit dependencies below. The .gch output files are placed in | 285 // added as explicit dependencies below. The .gch output files are placed in |
301 // |pch_other_files|. This is to prevent linking against them. | 286 // |pch_other_files|. This is to prevent linking against them. |
302 std::vector<OutputFile> pch_obj_files; | 287 std::vector<OutputFile> pch_obj_files; |
303 std::vector<OutputFile> pch_other_files; | 288 std::vector<OutputFile> pch_other_files; |
304 WritePCHCommands(used_types, order_only_dep, | 289 WritePCHCommands(used_types, input_dep, |
305 &pch_obj_files, &pch_other_files); | 290 &pch_obj_files, &pch_other_files); |
306 std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ? | 291 std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ? |
307 &pch_obj_files : &pch_other_files; | 292 &pch_obj_files : &pch_other_files; |
308 | 293 |
309 // Treat all pch output files as explicit dependencies of all | 294 // Treat all pch output files as explicit dependencies of all |
310 // compiles that support them. Some notes: | 295 // compiles that support them. Some notes: |
311 // | 296 // |
312 // - On Windows, the .pch file is the input to the compile, not the | 297 // - On Windows, the .pch file is the input to the compile, not the |
313 // precompiled header's corresponding object file that we're using here. | 298 // precompiled header's corresponding object file that we're using here. |
314 // But Ninja's depslog doesn't support multiple outputs from the | 299 // But Ninja's depslog doesn't support multiple outputs from the |
315 // precompiled header compile step (it outputs both the .pch file and a | 300 // precompiled header compile step (it outputs both the .pch file and a |
316 // corresponding .obj file). So we consistently list the .obj file and the | 301 // corresponding .obj file). So we consistently list the .obj file and the |
317 // .pch file we really need comes along with it. | 302 // .pch file we really need comes along with it. |
318 // | 303 // |
319 // - GCC .gch files are not object files, therefore they are not added to the | 304 // - GCC .gch files are not object files, therefore they are not added to the |
320 // object file list. | 305 // object file list. |
321 std::vector<OutputFile> obj_files; | 306 std::vector<OutputFile> obj_files; |
322 std::vector<SourceFile> other_files; | 307 std::vector<SourceFile> other_files; |
323 WriteSources(*pch_files, order_only_dep, &obj_files, &other_files); | 308 WriteSources(*pch_files, input_dep, &obj_files, &other_files); |
324 | 309 |
325 // Link all MSVC pch object files. The vector will be empty on GCC toolchains. | 310 // Link all MSVC pch object files. The vector will be empty on GCC toolchains. |
326 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); | 311 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); |
327 if (!CheckForDuplicateObjectFiles(obj_files)) | 312 if (!CheckForDuplicateObjectFiles(obj_files)) |
328 return; | 313 return; |
329 | 314 |
330 if (target_->output_type() == Target::SOURCE_SET) { | 315 if (target_->output_type() == Target::SOURCE_SET) { |
331 WriteSourceSetStamp(obj_files); | 316 WriteSourceSetStamp(obj_files); |
332 #ifndef NDEBUG | 317 #ifndef NDEBUG |
333 // Verify that the function that separately computes a source set's object | 318 // Verify that the function that separately computes a source set's object |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
446 } | 431 } |
447 } else { | 432 } else { |
448 RecursiveTargetConfigStringsToStream(target_, getter, | 433 RecursiveTargetConfigStringsToStream(target_, getter, |
449 flag_escape_options, out_); | 434 flag_escape_options, out_); |
450 } | 435 } |
451 out_ << std::endl; | 436 out_ << std::endl; |
452 } | 437 } |
453 | 438 |
454 void NinjaBinaryTargetWriter::WritePCHCommands( | 439 void NinjaBinaryTargetWriter::WritePCHCommands( |
455 const SourceFileTypeSet& used_types, | 440 const SourceFileTypeSet& used_types, |
456 const OutputFile& order_only_dep, | 441 const OutputFile& input_dep, |
457 std::vector<OutputFile>* object_files, | 442 std::vector<OutputFile>* object_files, |
458 std::vector<OutputFile>* other_files) { | 443 std::vector<OutputFile>* other_files) { |
459 if (!target_->config_values().has_precompiled_headers()) | 444 if (!target_->config_values().has_precompiled_headers()) |
460 return; | 445 return; |
461 | 446 |
462 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); | 447 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); |
463 if (tool_c && | 448 if (tool_c && |
464 tool_c->precompiled_header_type() != Tool::PCH_NONE && | 449 tool_c->precompiled_header_type() != Tool::PCH_NONE && |
465 used_types.Get(SOURCE_C)) { | 450 used_types.Get(SOURCE_C)) { |
466 WritePCHCommand(SUBSTITUTION_CFLAGS_C, | 451 WritePCHCommand(SUBSTITUTION_CFLAGS_C, |
467 Toolchain::TYPE_CC, | 452 Toolchain::TYPE_CC, |
468 tool_c->precompiled_header_type(), | 453 tool_c->precompiled_header_type(), |
469 order_only_dep, object_files, other_files); | 454 input_dep, object_files, other_files); |
470 } | 455 } |
471 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); | 456 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); |
472 if (tool_cxx && | 457 if (tool_cxx && |
473 tool_cxx->precompiled_header_type() != Tool::PCH_NONE && | 458 tool_cxx->precompiled_header_type() != Tool::PCH_NONE && |
474 used_types.Get(SOURCE_CPP)) { | 459 used_types.Get(SOURCE_CPP)) { |
475 WritePCHCommand(SUBSTITUTION_CFLAGS_CC, | 460 WritePCHCommand(SUBSTITUTION_CFLAGS_CC, |
476 Toolchain::TYPE_CXX, | 461 Toolchain::TYPE_CXX, |
477 tool_cxx->precompiled_header_type(), | 462 tool_cxx->precompiled_header_type(), |
478 order_only_dep, object_files, other_files); | 463 input_dep, object_files, other_files); |
479 } | 464 } |
480 | 465 |
481 const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC); | 466 const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC); |
482 if (tool_objc && | 467 if (tool_objc && |
483 tool_objc->precompiled_header_type() == Tool::PCH_GCC && | 468 tool_objc->precompiled_header_type() == Tool::PCH_GCC && |
484 used_types.Get(SOURCE_M)) { | 469 used_types.Get(SOURCE_M)) { |
485 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC, | 470 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC, |
486 Toolchain::TYPE_OBJC, | 471 Toolchain::TYPE_OBJC, |
487 tool_objc->precompiled_header_type(), | 472 tool_objc->precompiled_header_type(), |
488 order_only_dep, object_files, other_files); | 473 input_dep, object_files, other_files); |
489 } | 474 } |
490 | 475 |
491 const Tool* tool_objcxx = | 476 const Tool* tool_objcxx = |
492 target_->toolchain()->GetTool(Toolchain::TYPE_OBJCXX); | 477 target_->toolchain()->GetTool(Toolchain::TYPE_OBJCXX); |
493 if (tool_objcxx && | 478 if (tool_objcxx && |
494 tool_objcxx->precompiled_header_type() == Tool::PCH_GCC && | 479 tool_objcxx->precompiled_header_type() == Tool::PCH_GCC && |
495 used_types.Get(SOURCE_MM)) { | 480 used_types.Get(SOURCE_MM)) { |
496 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC, | 481 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC, |
497 Toolchain::TYPE_OBJCXX, | 482 Toolchain::TYPE_OBJCXX, |
498 tool_objcxx->precompiled_header_type(), | 483 tool_objcxx->precompiled_header_type(), |
499 order_only_dep, object_files, other_files); | 484 input_dep, object_files, other_files); |
500 } | 485 } |
501 } | 486 } |
502 | 487 |
503 void NinjaBinaryTargetWriter::WritePCHCommand( | 488 void NinjaBinaryTargetWriter::WritePCHCommand( |
504 SubstitutionType flag_type, | 489 SubstitutionType flag_type, |
505 Toolchain::ToolType tool_type, | 490 Toolchain::ToolType tool_type, |
506 Tool::PrecompiledHeaderType header_type, | 491 Tool::PrecompiledHeaderType header_type, |
507 const OutputFile& order_only_dep, | 492 const OutputFile& input_dep, |
508 std::vector<OutputFile>* object_files, | 493 std::vector<OutputFile>* object_files, |
509 std::vector<OutputFile>* other_files) { | 494 std::vector<OutputFile>* other_files) { |
510 switch (header_type) { | 495 switch (header_type) { |
511 case Tool::PCH_MSVC: | 496 case Tool::PCH_MSVC: |
512 WriteWindowsPCHCommand(flag_type, tool_type, order_only_dep, | 497 WriteWindowsPCHCommand(flag_type, tool_type, input_dep, |
513 object_files); | 498 object_files); |
514 break; | 499 break; |
515 case Tool::PCH_GCC: | 500 case Tool::PCH_GCC: |
516 WriteGCCPCHCommand(flag_type, tool_type, order_only_dep, | 501 WriteGCCPCHCommand(flag_type, tool_type, input_dep, |
517 other_files); | 502 other_files); |
518 break; | 503 break; |
519 case Tool::PCH_NONE: | 504 case Tool::PCH_NONE: |
520 NOTREACHED() << "Cannot write a PCH command with no PCH header type"; | 505 NOTREACHED() << "Cannot write a PCH command with no PCH header type"; |
521 break; | 506 break; |
522 } | 507 } |
523 } | 508 } |
524 | 509 |
525 void NinjaBinaryTargetWriter::WriteGCCPCHCommand( | 510 void NinjaBinaryTargetWriter::WriteGCCPCHCommand( |
526 SubstitutionType flag_type, | 511 SubstitutionType flag_type, |
527 Toolchain::ToolType tool_type, | 512 Toolchain::ToolType tool_type, |
528 const OutputFile& order_only_dep, | 513 const OutputFile& input_dep, |
529 std::vector<OutputFile>* gch_files) { | 514 std::vector<OutputFile>* gch_files) { |
530 // Compute the pch output file (it will be language-specific). | 515 // Compute the pch output file (it will be language-specific). |
531 std::vector<OutputFile> outputs; | 516 std::vector<OutputFile> outputs; |
532 GetPCHOutputFiles(target_, tool_type, &outputs); | 517 GetPCHOutputFiles(target_, tool_type, &outputs); |
533 if (outputs.empty()) | 518 if (outputs.empty()) |
534 return; | 519 return; |
535 | 520 |
536 gch_files->insert(gch_files->end(), outputs.begin(), outputs.end()); | 521 gch_files->insert(gch_files->end(), outputs.begin(), outputs.end()); |
537 | 522 |
523 std::vector<OutputFile> deps; | |
524 if (!input_dep.value().empty()) { | |
brettw
2016/06/16 19:41:34
No {}, same for the additions below.
Petr Hosek
2016/06/16 23:11:47
Done.
| |
525 deps.push_back(input_dep); | |
526 } | |
527 | |
538 // Build line to compile the file. | 528 // Build line to compile the file. |
539 WriteCompilerBuildLine(target_->config_values().precompiled_source(), | 529 WriteCompilerBuildLine(target_->config_values().precompiled_source(), |
540 std::vector<OutputFile>(), order_only_dep, tool_type, | 530 deps, tool_type, outputs); |
541 outputs); | |
542 | 531 |
543 // This build line needs a custom language-specific flags value. Rule-specific | 532 // This build line needs a custom language-specific flags value. Rule-specific |
544 // variables are just indented underneath the rule line. | 533 // variables are just indented underneath the rule line. |
545 out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; | 534 out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; |
546 | 535 |
547 // Each substitution flag is overwritten in the target rule to replace the | 536 // Each substitution flag is overwritten in the target rule to replace the |
548 // implicitly generated -include flag with the -x <header lang> flag required | 537 // implicitly generated -include flag with the -x <header lang> flag required |
549 // for .gch targets. | 538 // for .gch targets. |
550 EscapeOptions opts = GetFlagOptions(); | 539 EscapeOptions opts = GetFlagOptions(); |
551 if (tool_type == Toolchain::TYPE_CC) { | 540 if (tool_type == Toolchain::TYPE_CC) { |
(...skipping 14 matching lines...) Expand all Loading... | |
566 out_ << " -x " << GetPCHLangForToolType(tool_type); | 555 out_ << " -x " << GetPCHLangForToolType(tool_type); |
567 | 556 |
568 // Write two blank lines to help separate the PCH build lines from the | 557 // Write two blank lines to help separate the PCH build lines from the |
569 // regular source build lines. | 558 // regular source build lines. |
570 out_ << std::endl << std::endl; | 559 out_ << std::endl << std::endl; |
571 } | 560 } |
572 | 561 |
573 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( | 562 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( |
574 SubstitutionType flag_type, | 563 SubstitutionType flag_type, |
575 Toolchain::ToolType tool_type, | 564 Toolchain::ToolType tool_type, |
576 const OutputFile& order_only_dep, | 565 const OutputFile& input_dep, |
577 std::vector<OutputFile>* object_files) { | 566 std::vector<OutputFile>* object_files) { |
578 // Compute the pch output file (it will be language-specific). | 567 // Compute the pch output file (it will be language-specific). |
579 std::vector<OutputFile> outputs; | 568 std::vector<OutputFile> outputs; |
580 GetPCHOutputFiles(target_, tool_type, &outputs); | 569 GetPCHOutputFiles(target_, tool_type, &outputs); |
581 if (outputs.empty()) | 570 if (outputs.empty()) |
582 return; | 571 return; |
583 | 572 |
584 object_files->insert(object_files->end(), outputs.begin(), outputs.end()); | 573 object_files->insert(object_files->end(), outputs.begin(), outputs.end()); |
585 | 574 |
575 std::vector<OutputFile> deps; | |
576 if (!input_dep.value().empty()) { | |
577 deps.push_back(input_dep); | |
578 } | |
579 | |
586 // Build line to compile the file. | 580 // Build line to compile the file. |
587 WriteCompilerBuildLine(target_->config_values().precompiled_source(), | 581 WriteCompilerBuildLine(target_->config_values().precompiled_source(), |
588 std::vector<OutputFile>(), order_only_dep, tool_type, | 582 deps, tool_type, outputs); |
589 outputs); | |
590 | 583 |
591 // This build line needs a custom language-specific flags value. Rule-specific | 584 // This build line needs a custom language-specific flags value. Rule-specific |
592 // variables are just indented underneath the rule line. | 585 // variables are just indented underneath the rule line. |
593 out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; | 586 out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; |
594 | 587 |
595 // Append the command to generate the .pch file. | 588 // Append the command to generate the .pch file. |
596 // This adds the value to the existing flag instead of overwriting it. | 589 // This adds the value to the existing flag instead of overwriting it. |
597 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}"; | 590 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}"; |
598 out_ << " /Yc" << target_->config_values().precompiled_header(); | 591 out_ << " /Yc" << target_->config_values().precompiled_header(); |
599 | 592 |
600 // Write two blank lines to help separate the PCH build lines from the | 593 // Write two blank lines to help separate the PCH build lines from the |
601 // regular source build lines. | 594 // regular source build lines. |
602 out_ << std::endl << std::endl; | 595 out_ << std::endl << std::endl; |
603 } | 596 } |
604 | 597 |
605 void NinjaBinaryTargetWriter::WriteSources( | 598 void NinjaBinaryTargetWriter::WriteSources( |
606 const std::vector<OutputFile>& pch_deps, | 599 const std::vector<OutputFile>& pch_deps, |
607 const OutputFile& order_only_dep, | 600 const OutputFile& input_dep, |
608 std::vector<OutputFile>* object_files, | 601 std::vector<OutputFile>* object_files, |
609 std::vector<SourceFile>* other_files) { | 602 std::vector<SourceFile>* other_files) { |
610 object_files->reserve(object_files->size() + target_->sources().size()); | 603 object_files->reserve(object_files->size() + target_->sources().size()); |
611 | 604 |
612 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. | 605 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. |
613 std::vector<OutputFile> deps; | 606 std::vector<OutputFile> deps; |
607 | |
614 for (const auto& source : target_->sources()) { | 608 for (const auto& source : target_->sources()) { |
615 // Clear the vector but maintain the max capacity to prevent reallocations. | 609 // Clear the vector but maintain the max capacity to prevent reallocations. |
616 deps.resize(0); | 610 deps.resize(0); |
617 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; | 611 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; |
618 if (!target_->GetOutputFilesForSource(source, &tool_type, &tool_outputs)) { | 612 if (!target_->GetOutputFilesForSource(source, &tool_type, &tool_outputs)) { |
619 if (GetSourceFileType(source) == SOURCE_DEF) | 613 if (GetSourceFileType(source) == SOURCE_DEF) |
620 other_files->push_back(source); | 614 other_files->push_back(source); |
621 continue; // No output for this source. | 615 continue; // No output for this source. |
622 } | 616 } |
623 | 617 |
618 if (!input_dep.value().empty()) { | |
619 deps.push_back(input_dep); | |
620 } | |
621 | |
624 if (tool_type != Toolchain::TYPE_NONE) { | 622 if (tool_type != Toolchain::TYPE_NONE) { |
625 // Only include PCH deps that correspond to the tool type, for instance, | 623 // Only include PCH deps that correspond to the tool type, for instance, |
626 // do not specify target_name.precompile.cc.obj (a CXX PCH file) as a dep | 624 // do not specify target_name.precompile.cc.obj (a CXX PCH file) as a dep |
627 // for the output of a C tool type. | 625 // for the output of a C tool type. |
628 // | 626 // |
629 // This makes the assumption that pch_deps only contains pch output files | 627 // This makes the assumption that pch_deps only contains pch output files |
630 // with the naming scheme specified in GetWindowsPCHObjectExtension or | 628 // with the naming scheme specified in GetWindowsPCHObjectExtension or |
631 // GetGCCPCHOutputExtension. | 629 // GetGCCPCHOutputExtension. |
632 const Tool* tool = target_->toolchain()->GetTool(tool_type); | 630 const Tool* tool = target_->toolchain()->GetTool(tool_type); |
633 if (tool->precompiled_header_type() != Tool::PCH_NONE) { | 631 if (tool->precompiled_header_type() != Tool::PCH_NONE) { |
634 for (const auto& dep : pch_deps) { | 632 for (const auto& dep : pch_deps) { |
635 const std::string& output_value = dep.value(); | 633 const std::string& output_value = dep.value(); |
636 size_t extension_offset = FindExtensionOffset(output_value); | 634 size_t extension_offset = FindExtensionOffset(output_value); |
637 if (extension_offset == std::string::npos) | 635 if (extension_offset == std::string::npos) |
638 continue; | 636 continue; |
639 std::string output_extension; | 637 std::string output_extension; |
640 if (tool->precompiled_header_type() == Tool::PCH_MSVC) { | 638 if (tool->precompiled_header_type() == Tool::PCH_MSVC) { |
641 output_extension = GetWindowsPCHObjectExtension( | 639 output_extension = GetWindowsPCHObjectExtension( |
642 tool_type, output_value.substr(extension_offset - 1)); | 640 tool_type, output_value.substr(extension_offset - 1)); |
643 } else if (tool->precompiled_header_type() == Tool::PCH_GCC) { | 641 } else if (tool->precompiled_header_type() == Tool::PCH_GCC) { |
644 output_extension = GetGCCPCHOutputExtension(tool_type); | 642 output_extension = GetGCCPCHOutputExtension(tool_type); |
645 } | 643 } |
646 if (output_value.compare(output_value.size() - | 644 if (output_value.compare(output_value.size() - |
647 output_extension.size(), output_extension.size(), | 645 output_extension.size(), output_extension.size(), |
648 output_extension) == 0) { | 646 output_extension) == 0) { |
649 deps.push_back(dep); | 647 deps.push_back(dep); |
650 } | 648 } |
651 } | 649 } |
652 } | 650 } |
653 WriteCompilerBuildLine(source, deps, order_only_dep, tool_type, | 651 WriteCompilerBuildLine(source, deps, tool_type, tool_outputs); |
654 tool_outputs); | |
655 } | 652 } |
656 | 653 |
657 // It's theoretically possible for a compiler to produce more than one | 654 // It's theoretically possible for a compiler to produce more than one |
658 // output, but we'll only link to the first output. | 655 // output, but we'll only link to the first output. |
659 object_files->push_back(tool_outputs[0]); | 656 object_files->push_back(tool_outputs[0]); |
660 } | 657 } |
661 out_ << std::endl; | 658 out_ << std::endl; |
662 } | 659 } |
663 | 660 |
664 void NinjaBinaryTargetWriter::WriteCompilerBuildLine( | 661 void NinjaBinaryTargetWriter::WriteCompilerBuildLine( |
665 const SourceFile& source, | 662 const SourceFile& source, |
666 const std::vector<OutputFile>& extra_deps, | 663 const std::vector<OutputFile>& extra_deps, |
667 const OutputFile& order_only_dep, | |
668 Toolchain::ToolType tool_type, | 664 Toolchain::ToolType tool_type, |
669 const std::vector<OutputFile>& outputs) { | 665 const std::vector<OutputFile>& outputs) { |
670 out_ << "build"; | 666 out_ << "build"; |
671 path_output_.WriteFiles(out_, outputs); | 667 path_output_.WriteFiles(out_, outputs); |
672 | 668 |
673 out_ << ": " << rule_prefix_ << Toolchain::ToolTypeToName(tool_type); | 669 out_ << ": " << rule_prefix_ << Toolchain::ToolTypeToName(tool_type); |
674 out_ << " "; | 670 out_ << " "; |
675 path_output_.WriteFile(out_, source); | 671 path_output_.WriteFile(out_, source); |
676 | 672 |
677 if (!extra_deps.empty()) { | 673 if (!extra_deps.empty()) { |
678 out_ << " |"; | 674 out_ << " |"; |
679 for (const OutputFile& dep : extra_deps) { | 675 for (const OutputFile& dep : extra_deps) { |
680 out_ << " "; | 676 out_ << " "; |
681 path_output_.WriteFile(out_, dep); | 677 path_output_.WriteFile(out_, dep); |
682 } | 678 } |
683 } | 679 } |
684 | |
685 if (!order_only_dep.value().empty()) { | |
686 out_ << " || "; | |
687 path_output_.WriteFile(out_, order_only_dep); | |
688 } | |
689 out_ << std::endl; | 680 out_ << std::endl; |
690 } | 681 } |
691 | 682 |
692 void NinjaBinaryTargetWriter::WriteLinkerStuff( | 683 void NinjaBinaryTargetWriter::WriteLinkerStuff( |
693 const std::vector<OutputFile>& object_files, | 684 const std::vector<OutputFile>& object_files, |
694 const std::vector<SourceFile>& other_files) { | 685 const std::vector<SourceFile>& other_files) { |
695 std::vector<OutputFile> output_files; | 686 std::vector<OutputFile> output_files; |
696 SubstitutionWriter::ApplyListToLinkerAsOutputFile( | 687 SubstitutionWriter::ApplyListToLinkerAsOutputFile( |
697 target_, tool_, tool_->outputs(), &output_files); | 688 target_, tool_, tool_->outputs(), &output_files); |
698 | 689 |
699 out_ << "build"; | 690 out_ << "build"; |
700 path_output_.WriteFiles(out_, output_files); | 691 path_output_.WriteFiles(out_, output_files); |
701 | 692 |
702 out_ << ": " << rule_prefix_ | 693 out_ << ": " << rule_prefix_ |
703 << Toolchain::ToolTypeToName( | 694 << Toolchain::ToolTypeToName( |
704 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_)); | 695 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_)); |
705 | 696 |
706 UniqueVector<OutputFile> extra_object_files; | 697 UniqueVector<OutputFile> extra_object_files; |
707 UniqueVector<const Target*> linkable_deps; | 698 UniqueVector<const Target*> linkable_deps; |
708 UniqueVector<const Target*> non_linkable_deps; | 699 UniqueVector<const Target*> non_linkable_deps; |
709 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); | 700 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); |
710 | 701 |
711 // Object files. | 702 // Object files. |
712 path_output_.WriteFiles(out_, object_files); | 703 path_output_.WriteFiles(out_, object_files); |
713 path_output_.WriteFiles(out_, extra_object_files); | 704 path_output_.WriteFiles(out_, extra_object_files); |
714 | 705 |
715 // Dependencies. | 706 // Dependencies. |
716 std::vector<OutputFile> implicit_deps; | 707 std::vector<OutputFile> input_deps; |
717 std::vector<OutputFile> solibs; | 708 std::vector<OutputFile> solibs; |
718 for (const Target* cur : linkable_deps) { | 709 for (const Target* cur : linkable_deps) { |
719 // All linkable deps should have a link output file. | 710 // All linkable deps should have a link output file. |
720 DCHECK(!cur->link_output_file().value().empty()) | 711 DCHECK(!cur->link_output_file().value().empty()) |
721 << "No link output file for " | 712 << "No link output file for " |
722 << target_->label().GetUserVisibleName(false); | 713 << target_->label().GetUserVisibleName(false); |
723 | 714 |
724 if (cur->dependency_output_file().value() != | 715 if (cur->dependency_output_file().value() != |
725 cur->link_output_file().value()) { | 716 cur->link_output_file().value()) { |
726 // This is a shared library with separate link and deps files. Save for | 717 // This is a shared library with separate link and deps files. Save for |
727 // later. | 718 // later. |
728 implicit_deps.push_back(cur->dependency_output_file()); | 719 input_deps.push_back(cur->dependency_output_file()); |
729 solibs.push_back(cur->link_output_file()); | 720 solibs.push_back(cur->link_output_file()); |
730 } else { | 721 } else { |
731 // Normal case, just link to this target. | 722 // Normal case, just link to this target. |
732 out_ << " "; | 723 out_ << " "; |
733 path_output_.WriteFile(out_, cur->link_output_file()); | 724 path_output_.WriteFile(out_, cur->link_output_file()); |
734 } | 725 } |
735 } | 726 } |
736 | 727 |
737 const SourceFile* optional_def_file = nullptr; | 728 const SourceFile* optional_def_file = nullptr; |
738 if (!other_files.empty()) { | 729 if (!other_files.empty()) { |
739 for (const SourceFile& src_file : other_files) { | 730 for (const SourceFile& src_file : other_files) { |
740 if (GetSourceFileType(src_file) == SOURCE_DEF) { | 731 if (GetSourceFileType(src_file) == SOURCE_DEF) { |
741 optional_def_file = &src_file; | 732 optional_def_file = &src_file; |
742 implicit_deps.push_back( | 733 input_deps.push_back( |
743 OutputFile(settings_->build_settings(), src_file)); | 734 OutputFile(settings_->build_settings(), src_file)); |
744 break; // Only one def file is allowed. | 735 break; // Only one def file is allowed. |
745 } | 736 } |
746 } | 737 } |
747 } | 738 } |
748 | 739 |
749 // Libraries specified by paths. | 740 // Libraries specified by paths. |
750 const OrderedSet<LibFile>& libs = target_->all_libs(); | 741 const OrderedSet<LibFile>& libs = target_->all_libs(); |
751 for (size_t i = 0; i < libs.size(); i++) { | 742 for (size_t i = 0; i < libs.size(); i++) { |
752 if (libs[i].is_source_file()) { | 743 if (libs[i].is_source_file()) { |
753 implicit_deps.push_back( | 744 input_deps.push_back( |
754 OutputFile(settings_->build_settings(), libs[i].source_file())); | 745 OutputFile(settings_->build_settings(), libs[i].source_file())); |
755 } | 746 } |
756 } | 747 } |
757 | 748 |
758 // Append implicit dependencies collected above. | 749 // Append implicit dependencies collected above. |
759 if (!implicit_deps.empty()) { | 750 if (!input_deps.empty()) { |
760 out_ << " |"; | 751 out_ << " |"; |
761 path_output_.WriteFiles(out_, implicit_deps); | 752 path_output_.WriteFiles(out_, input_deps); |
762 } | 753 } |
763 | 754 |
764 // Append data dependencies as order-only dependencies. | 755 // Append data dependencies as order-only dependencies. |
765 // | 756 // |
766 // This will include data dependencies and input dependencies (like when | 757 // This will include data dependencies and input dependencies (like when |
767 // this target depends on an action). Having the data dependencies in this | 758 // this target depends on an action). Having the data dependencies in this |
768 // list ensures that the data is available at runtime when the user builds | 759 // list ensures that the data is available at runtime when the user builds |
769 // this target. | 760 // this target. |
770 // | 761 // |
771 // The action dependencies are not strictly necessary in this case. They | 762 // The action dependencies are not strictly necessary in this case. They |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1015 "\n" | 1006 "\n" |
1016 "In the latter case, either rename one of the files or move one of\n" | 1007 "In the latter case, either rename one of the files or move one of\n" |
1017 "the sources to a separate source_set to avoid them both being in\n" | 1008 "the sources to a separate source_set to avoid them both being in\n" |
1018 "the same target."); | 1009 "the same target."); |
1019 g_scheduler->FailWithError(err); | 1010 g_scheduler->FailWithError(err); |
1020 return false; | 1011 return false; |
1021 } | 1012 } |
1022 } | 1013 } |
1023 return true; | 1014 return true; |
1024 } | 1015 } |
OLD | NEW |