• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "gn/ninja_copy_target_writer.h"
6 
7 #include "base/strings/string_util.h"
8 #include "gn/general_tool.h"
9 #include "gn/ninja_utils.h"
10 #include "gn/output_file.h"
11 #include "gn/scheduler.h"
12 #include "gn/string_utils.h"
13 #include "gn/substitution_list.h"
14 #include "gn/substitution_writer.h"
15 #include "gn/target.h"
16 #include "gn/toolchain.h"
17 
NinjaCopyTargetWriter(const Target * target,std::ostream & out)18 NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target,
19                                              std::ostream& out)
20     : NinjaTargetWriter(target, out) {}
21 
22 NinjaCopyTargetWriter::~NinjaCopyTargetWriter() = default;
23 
Run()24 void NinjaCopyTargetWriter::Run() {
25   const Tool* copy_tool =
26       target_->toolchain()->GetTool(GeneralTool::kGeneralToolCopy);
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;
35   }
36 
37   const Tool* stamp_tool =
38       target_->toolchain()->GetTool(GeneralTool::kGeneralToolStamp);
39   if (!stamp_tool) {
40     g_scheduler->FailWithError(Err(
41         nullptr, "Copy tool not defined",
42         "The toolchain " +
43             target_->toolchain()->label().GetUserVisibleName(false) +
44             "\n used by target " + target_->label().GetUserVisibleName(false) +
45             "\n doesn't define a \"stamp\" tool."));
46     return;
47   }
48 
49   // Figure out the substitutions used by the copy and stamp tools.
50   SubstitutionBits required_bits = copy_tool->substitution_bits();
51   required_bits.MergeFrom(stamp_tool->substitution_bits());
52 
53   // General target-related substitutions needed by both tools.
54   WriteSharedVars(required_bits);
55 
56   std::vector<OutputFile> output_files;
57   WriteCopyRules(&output_files);
58   out_ << std::endl;
59   WriteStampForTarget(output_files, std::vector<OutputFile>());
60 }
61 
WriteCopyRules(std::vector<OutputFile> * output_files)62 void NinjaCopyTargetWriter::WriteCopyRules(
63     std::vector<OutputFile>* output_files) {
64   CHECK(target_->action_values().outputs().list().size() == 1);
65   const SubstitutionList& output_subst_list =
66       target_->action_values().outputs();
67   CHECK_EQ(1u, output_subst_list.list().size())
68       << "Should have one entry exactly.";
69   const SubstitutionPattern& output_subst = output_subst_list.list()[0];
70 
71   std::string tool_name =
72       GetNinjaRulePrefixForToolchain(settings_) + GeneralTool::kGeneralToolCopy;
73 
74   size_t num_stamp_uses = target_->sources().size();
75   std::vector<OutputFile> input_deps = WriteInputDepsStampAndGetDep(
76       std::vector<const Target*>(), num_stamp_uses);
77 
78   std::vector<OutputFile> data_outs;
79   for (const Target* data_dep : resolved().GetDataDeps(target_))
80     data_outs.push_back(data_dep->dependency_output_file());
81 
82   // Note that we don't write implicit deps for copy steps. "copy" only
83   // depends on the output files themselves, rather than having includes
84   // (the possibility of generated #includes is the main reason for implicit
85   // dependencies).
86   //
87   // It would seem that specifying implicit dependencies on the deps of the
88   // copy command would still be harmless. But Chrome implements copy tools
89   // as hard links (much faster) which don't change the timestamp. If the
90   // ninja rule looks like this:
91   //   output: copy input | foo.stamp
92   // The copy will not make a new timestamp on the output file, but the
93   // foo.stamp file generated from a previous step will have a new timestamp.
94   // The copy rule will therefore look out-of-date to Ninja and the rule will
95   // get rebuilt.
96   //
97   // If this copy is copying a generated file, not listing the implicit
98   // dependency will be fine as long as the input to the copy is properly
99   // listed as the output from the step that generated it.
100   //
101   // Moreover, doing this assumes that the copy step is always a simple
102   // locally run command, so there is no need for a toolchain dependency.
103   //
104   // Note that there is the need in some cases for order-only dependencies
105   // where a command might need to make sure something else runs before it runs
106   // to avoid conflicts. This is also needed for data_deps on a copy target.
107   // Such cases should be avoided where possible, but sometimes that's not
108   // possible.
109   for (const auto& input_file : target_->sources()) {
110     OutputFile output_file =
111         SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
112             target_, target_->settings(), output_subst, input_file);
113     output_files->push_back(output_file);
114 
115     out_ << "build ";
116     WriteOutput(std::move(output_file));
117 
118     out_ << ": " << tool_name << " ";
119     path_output_.WriteFile(out_, input_file);
120     if (!input_deps.empty() || !data_outs.empty()) {
121       out_ << " ||";
122       path_output_.WriteFiles(out_, input_deps);
123       path_output_.WriteFiles(out_, data_outs);
124     }
125     out_ << std::endl;
126   }
127 }
128