Try to work around that clang/win bug in another file.
[chromium-blink-merge.git] / tools / gn / ninja_copy_target_writer.cc
blobb0313bec3f279dc55bc02a7cbaf1f629d2fa57b4
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "tools/gn/ninja_copy_target_writer.h"
7 #include "base/strings/string_util.h"
8 #include "tools/gn/ninja_utils.h"
9 #include "tools/gn/output_file.h"
10 #include "tools/gn/scheduler.h"
11 #include "tools/gn/string_utils.h"
12 #include "tools/gn/substitution_list.h"
13 #include "tools/gn/substitution_writer.h"
14 #include "tools/gn/target.h"
15 #include "tools/gn/toolchain.h"
17 NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target,
18 std::ostream& out)
19 : NinjaTargetWriter(target, out) {
22 NinjaCopyTargetWriter::~NinjaCopyTargetWriter() {
25 void NinjaCopyTargetWriter::Run() {
26 const Tool* copy_tool = target_->toolchain()->GetTool(Toolchain::TYPE_COPY);
27 if (!copy_tool) {
28 g_scheduler->FailWithError(Err(
29 nullptr, "Copy tool not defined",
30 "The toolchain " +
31 target_->toolchain()->label().GetUserVisibleName(false) +
32 "\n used by target " + target_->label().GetUserVisibleName(false) +
33 "\n doesn't define a \"copy\" tool."));
34 return;
37 const Tool* stamp_tool = target_->toolchain()->GetTool(Toolchain::TYPE_STAMP);
38 if (!stamp_tool) {
39 g_scheduler->FailWithError(Err(
40 nullptr, "Copy tool not defined",
41 "The toolchain " +
42 target_->toolchain()->label().GetUserVisibleName(false) +
43 "\n used by target " + target_->label().GetUserVisibleName(false) +
44 "\n doesn't define a \"stamp\" tool."));
45 return;
48 // Figure out the substitutions used by the copy and stamp tools.
49 SubstitutionBits required_bits = copy_tool->substitution_bits();
50 required_bits.MergeFrom(stamp_tool->substitution_bits());
52 // General target-related substitutions needed by both tools.
53 WriteSharedVars(required_bits);
55 std::vector<OutputFile> output_files;
56 WriteCopyRules(&output_files);
57 out_ << std::endl;
58 WriteStampForTarget(output_files, std::vector<OutputFile>());
61 void NinjaCopyTargetWriter::WriteCopyRules(
62 std::vector<OutputFile>* output_files) {
63 CHECK(target_->action_values().outputs().list().size() == 1);
64 const SubstitutionList& output_subst_list =
65 target_->action_values().outputs();
66 CHECK_EQ(1u, output_subst_list.list().size())
67 << "Should have one entry exactly.";
68 const SubstitutionPattern& output_subst = output_subst_list.list()[0];
70 std::string tool_name =
71 GetNinjaRulePrefixForToolchain(settings_) +
72 Toolchain::ToolTypeToName(Toolchain::TYPE_COPY);
74 OutputFile input_dep =
75 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
77 // Note that we don't write implicit deps for copy steps. "copy" only
78 // depends on the output files themselves, rather than having includes
79 // (the possibility of generated #includes is the main reason for implicit
80 // dependencies).
82 // It would seem that specifying implicit dependencies on the deps of the
83 // copy command would still be harmeless. But Chrome implements copy tools
84 // as hard links (much faster) which don't change the timestamp. If the
85 // ninja rule looks like this:
86 // output: copy input | foo.stamp
87 // The copy will not make a new timestamp on the output file, but the
88 // foo.stamp file generated from a previous step will have a new timestamp.
89 // The copy rule will therefore look out-of-date to Ninja and the rule will
90 // get rebuilt.
92 // If this copy is copying a generated file, not listing the implicit
93 // dependency will be fine as long as the input to the copy is properly
94 // listed as the output from the step that generated it.
96 // Moreover, doing this assumes that the copy step is always a simple
97 // locally run command, so there is no need for a toolchain dependency.
99 // Note that there is the need in some cases for order-only dependencies
100 // where a command might need to make sure something else runs before it runs
101 // to avoid conflicts. Such cases should be avoided where possible, but
102 // sometimes that's not possible.
103 for (const auto& input_file : target_->sources()) {
104 OutputFile output_file =
105 SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
106 target_->settings(), output_subst, input_file);
107 output_files->push_back(output_file);
109 out_ << "build ";
110 path_output_.WriteFile(out_, output_file);
111 out_ << ": " << tool_name << " ";
112 path_output_.WriteFile(out_, input_file);
113 if (!input_dep.value().empty()) {
114 out_ << " || ";
115 path_output_.WriteFile(out_, input_dep);
117 out_ << std::endl;