Chromium Code Reviews| 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 |