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_script_target_writer.h" | 5 #include "tools/gn/ninja_script_target_writer.h" |
6 | 6 |
7 #include "base/strings/string_util.h" | 7 #include "base/strings/string_util.h" |
8 #include "tools/gn/err.h" | 8 #include "tools/gn/err.h" |
9 #include "tools/gn/file_template.h" | 9 #include "tools/gn/file_template.h" |
10 #include "tools/gn/string_utils.h" | 10 #include "tools/gn/string_utils.h" |
11 #include "tools/gn/target.h" | 11 #include "tools/gn/target.h" |
12 | 12 |
13 NinjaScriptTargetWriter::NinjaScriptTargetWriter(const Target* target, | 13 NinjaScriptTargetWriter::NinjaScriptTargetWriter(const Target* target, |
14 std::ostream& out) | 14 std::ostream& out) |
15 : NinjaTargetWriter(target, out) { | 15 : NinjaTargetWriter(target, out) { |
16 } | 16 } |
17 | 17 |
18 NinjaScriptTargetWriter::~NinjaScriptTargetWriter() { | 18 NinjaScriptTargetWriter::~NinjaScriptTargetWriter() { |
19 } | 19 } |
20 | 20 |
21 void NinjaScriptTargetWriter::Run() { | 21 void NinjaScriptTargetWriter::Run() { |
22 WriteEnvironment(); | 22 WriteEnvironment(); |
23 | 23 |
24 // Run the script from the dir of the BUILD file. This has no trailing | 24 std::string custom_rule_name = WriteRuleDefinition(); |
25 // slash. | |
26 const SourceDir& script_cd = target_->label().dir(); | |
27 std::string script_cd_to_root = InvertDir(script_cd); | |
28 if (script_cd_to_root.empty()) { | |
29 script_cd_to_root = "."; | |
30 } else { | |
31 // Remove trailing slash. | |
32 DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/'); | |
33 script_cd_to_root.resize(script_cd_to_root.size() - 1); | |
34 } | |
35 | |
36 // Compute the relative script file name. The script string should start with | |
37 // 2 slashes, and we trim 1. | |
38 DCHECK(target_->script_values().script().is_source_absolute()); | |
39 std::string script_relative_to_cd = script_cd_to_root; | |
40 const std::string& script_string = target_->script_values().script().value(); | |
41 script_relative_to_cd.append(&script_string[1], script_string.size() - 1); | |
42 | |
43 std::string custom_rule_name = WriteRuleDefinition(script_relative_to_cd); | |
44 std::string implicit_deps = GetSourcesImplicitDeps(); | 25 std::string implicit_deps = GetSourcesImplicitDeps(); |
45 | 26 |
46 // Collects all output files for writing below. | 27 // Collects all output files for writing below. |
47 std::vector<OutputFile> output_files; | 28 std::vector<OutputFile> output_files; |
48 | 29 |
49 if (has_sources()) { | 30 if (has_sources()) { |
50 // Write separate rules for each input source file. | 31 // Write separate rules for each input source file. |
51 WriteSourceRules(custom_rule_name, implicit_deps, script_cd, | 32 WriteSourceRules(custom_rule_name, implicit_deps, &output_files); |
52 script_cd_to_root, &output_files); | |
53 } else { | 33 } else { |
54 // No sources, write a rule that invokes the script once with the | 34 // No sources, write a rule that invokes the script once with the |
55 // outputs as outputs, and the data as inputs. | 35 // outputs as outputs, and the data as inputs. |
56 out_ << "build"; | 36 out_ << "build"; |
57 const Target::FileList& outputs = target_->script_values().outputs(); | 37 const Target::FileList& outputs = target_->script_values().outputs(); |
58 for (size_t i = 0; i < outputs.size(); i++) { | 38 for (size_t i = 0; i < outputs.size(); i++) { |
59 OutputFile output_path( | 39 OutputFile output_path( |
60 RemovePrefix(outputs[i].value(), | 40 RemovePrefix(outputs[i].value(), |
61 settings_->build_settings()->build_dir().value())); | 41 settings_->build_settings()->build_dir().value())); |
62 output_files.push_back(output_path); | 42 output_files.push_back(output_path); |
63 out_ << " "; | 43 out_ << " "; |
64 path_output_.WriteFile(out_, output_path); | 44 path_output_.WriteFile(out_, output_path); |
65 } | 45 } |
66 out_ << ": " << custom_rule_name << implicit_deps << std::endl; | 46 out_ << ": " << custom_rule_name << implicit_deps << std::endl; |
67 } | 47 } |
68 out_ << std::endl; | 48 out_ << std::endl; |
69 | 49 |
70 WriteStamp(output_files); | 50 WriteStamp(output_files); |
71 } | 51 } |
72 | 52 |
73 std::string NinjaScriptTargetWriter::WriteRuleDefinition( | 53 std::string NinjaScriptTargetWriter::WriteRuleDefinition() { |
74 const std::string& script_relative_to_cd) { | |
75 // Make a unique name for this rule. | 54 // Make a unique name for this rule. |
| 55 // |
| 56 // Use a unique name for the response file when there are multiple build |
| 57 // steps so that they don't stomp on each other. When there are no sources, |
| 58 // there will be only one invocation so we can use a simple name. |
76 std::string target_label = target_->label().GetUserVisibleName(true); | 59 std::string target_label = target_->label().GetUserVisibleName(true); |
77 std::string custom_rule_name(target_label); | 60 std::string custom_rule_name(target_label); |
78 ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); | 61 ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); |
79 custom_rule_name.append("_rule"); | 62 custom_rule_name.append("_rule"); |
80 | 63 |
81 // Use a unique name for the response file when there are multiple build | |
82 // steps so that they don't stomp on each other. When there are no sources, | |
83 // there will be only one invocation so we can use a simple name. | |
84 | |
85 if (settings_->IsWin()) { | 64 if (settings_->IsWin()) { |
86 // Send through gyp-win-tool and use a response file. | 65 // Send through gyp-win-tool and use a response file. |
87 std::string rspfile = custom_rule_name; | 66 std::string rspfile = custom_rule_name; |
88 if (has_sources()) | 67 if (has_sources()) |
89 rspfile += ".$unique_name"; | 68 rspfile += ".$unique_name"; |
90 rspfile += ".rsp"; | 69 rspfile += ".rsp"; |
91 | 70 |
92 out_ << "rule " << custom_rule_name << std::endl; | 71 out_ << "rule " << custom_rule_name << std::endl; |
93 out_ << " command = $pythonpath gyp-win-tool action-wrapper $arch " | 72 out_ << " command = $pythonpath gyp-win-tool action-wrapper $arch " |
94 << rspfile << " "; | 73 << rspfile << std::endl; |
95 path_output_.WriteDir(out_, target_->label().dir(), | |
96 PathOutput::DIR_NO_LAST_SLASH); | |
97 out_ << std::endl; | |
98 out_ << " description = CUSTOM " << target_label << std::endl; | 74 out_ << " description = CUSTOM " << target_label << std::endl; |
99 out_ << " restat = 1" << std::endl; | 75 out_ << " restat = 1" << std::endl; |
100 out_ << " rspfile = " << rspfile << std::endl; | 76 out_ << " rspfile = " << rspfile << std::endl; |
101 | 77 |
102 // The build command goes in the rsp file. | 78 // The build command goes in the rsp file. |
103 out_ << " rspfile_content = $pythonpath " << script_relative_to_cd; | 79 out_ << " rspfile_content = $pythonpath "; |
| 80 path_output_.WriteFile(out_, target_->script_values().script()); |
104 for (size_t i = 0; i < target_->script_values().args().size(); i++) { | 81 for (size_t i = 0; i < target_->script_values().args().size(); i++) { |
105 const std::string& arg = target_->script_values().args()[i]; | 82 const std::string& arg = target_->script_values().args()[i]; |
106 out_ << " "; | 83 out_ << " "; |
107 WriteArg(arg); | 84 WriteArg(arg); |
108 } | 85 } |
109 } else { | 86 } else { |
110 // Posix can execute Python directly. | 87 // Posix can execute Python directly. |
111 out_ << "rule " << custom_rule_name << std::endl; | 88 out_ << "rule " << custom_rule_name << std::endl; |
112 out_ << " command = cd "; | 89 out_ << " command = cd "; |
113 path_output_.WriteDir(out_, target_->label().dir(), | 90 path_output_.WriteDir(out_, target_->label().dir(), |
114 PathOutput::DIR_NO_LAST_SLASH); | 91 PathOutput::DIR_NO_LAST_SLASH); |
115 out_ << "; $pythonpath " << script_relative_to_cd; | 92 out_ << "; $pythonpath "; |
| 93 path_output_.WriteFile(out_, target_->script_values().script()); |
116 for (size_t i = 0; i < target_->script_values().args().size(); i++) { | 94 for (size_t i = 0; i < target_->script_values().args().size(); i++) { |
117 const std::string& arg = target_->script_values().args()[i]; | 95 const std::string& arg = target_->script_values().args()[i]; |
118 out_ << " "; | 96 out_ << " "; |
119 WriteArg(arg); | 97 WriteArg(arg); |
120 } | 98 } |
121 out_ << std::endl; | 99 out_ << std::endl; |
122 out_ << " description = CUSTOM " << target_label << std::endl; | 100 out_ << " description = CUSTOM " << target_label << std::endl; |
123 out_ << " restat = 1" << std::endl; | 101 out_ << " restat = 1" << std::endl; |
124 } | 102 } |
125 | 103 |
(...skipping 12 matching lines...) Expand all Loading... |
138 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource, | 116 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource, |
139 "${source}"); | 117 "${source}"); |
140 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart, | 118 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart, |
141 "${source_name_part}"); | 119 "${source_name_part}"); |
142 out_ << output_str; | 120 out_ << output_str; |
143 } | 121 } |
144 | 122 |
145 void NinjaScriptTargetWriter::WriteSourceRules( | 123 void NinjaScriptTargetWriter::WriteSourceRules( |
146 const std::string& custom_rule_name, | 124 const std::string& custom_rule_name, |
147 const std::string& implicit_deps, | 125 const std::string& implicit_deps, |
148 const SourceDir& script_cd, | |
149 const std::string& script_cd_to_root, | |
150 std::vector<OutputFile>* output_files) { | 126 std::vector<OutputFile>* output_files) { |
151 // Construct the template for generating the output files from each source. | 127 // Construct the template for generating the output files from each source. |
152 const Target::FileList& outputs = target_->script_values().outputs(); | 128 const Target::FileList& outputs = target_->script_values().outputs(); |
153 std::vector<std::string> output_template_args; | 129 std::vector<std::string> output_template_args; |
154 for (size_t i = 0; i < outputs.size(); i++) { | 130 for (size_t i = 0; i < outputs.size(); i++) { |
155 // All outputs should be in the output dir. | 131 // All outputs should be in the output dir. |
156 output_template_args.push_back( | 132 output_template_args.push_back( |
157 RemovePrefix(outputs[i].value(), | 133 RemovePrefix(outputs[i].value(), |
158 settings_->build_settings()->build_dir().value())); | 134 settings_->build_settings()->build_dir().value())); |
159 } | 135 } |
160 FileTemplate output_template(output_template_args); | 136 FileTemplate output_template(output_template_args); |
161 | 137 |
162 // Prevent re-allocating each time by initializing outside the loop. | 138 // Prevent re-allocating each time by initializing outside the loop. |
163 std::vector<std::string> output_template_result; | 139 std::vector<std::string> output_template_result; |
164 | 140 |
165 // Path output formatter for wrigin source paths passed to the script. | |
166 PathOutput script_source_path_output(script_cd, ESCAPE_SHELL, true); | |
167 | |
168 const Target::FileList& sources = target_->sources(); | 141 const Target::FileList& sources = target_->sources(); |
169 for (size_t i = 0; i < sources.size(); i++) { | 142 for (size_t i = 0; i < sources.size(); i++) { |
170 // Write outputs for this source file computed by the template. | 143 // Write outputs for this source file computed by the template. |
171 out_ << "build"; | 144 out_ << "build"; |
172 output_template.ApplyString(sources[i].value(), &output_template_result); | 145 output_template.ApplyString(sources[i].value(), &output_template_result); |
173 for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) { | 146 for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) { |
174 OutputFile output_path(output_template_result[out_i]); | 147 OutputFile output_path(output_template_result[out_i]); |
175 output_files->push_back(output_path); | 148 output_files->push_back(output_path); |
176 out_ << " "; | 149 out_ << " "; |
177 path_output_.WriteFile(out_, output_path); | 150 path_output_.WriteFile(out_, output_path); |
178 } | 151 } |
179 | 152 |
180 out_ << ": " << custom_rule_name; | 153 out_ << ": " << custom_rule_name; |
181 path_output_.WriteFile(out_, sources[i]); | 154 path_output_.WriteFile(out_, sources[i]); |
182 out_ << implicit_deps << std::endl; | 155 out_ << implicit_deps << std::endl; |
183 | 156 |
184 out_ << " unique_name = " << i << std::endl; | 157 out_ << " unique_name = " << i << std::endl; |
185 | 158 |
186 // The source file here should be relative to the script directory since | 159 // The source file here should be relative to the script directory since |
187 // this is the variable passed to the script. Here we slightly abuse the | 160 // this is the variable passed to the script. Here we slightly abuse the |
188 // OutputFile object by putting a non-output-relative path in it to signal | 161 // OutputFile object by putting a non-output-relative path in it to signal |
189 // that the PathWriter should not prepend directories. | 162 // that the PathWriter should not prepend directories. |
190 out_ << " source = "; | 163 out_ << " source = "; |
191 script_source_path_output.WriteFile(out_, sources[i]); | 164 path_output_.WriteFile(out_, sources[i]); |
192 out_ << std::endl; | 165 out_ << std::endl; |
193 | 166 |
194 out_ << " source_name_part = " | 167 out_ << " source_name_part = " |
195 << FindFilenameNoExtension(&sources[i].value()).as_string() | 168 << FindFilenameNoExtension(&sources[i].value()).as_string() |
196 << std::endl; | 169 << std::endl; |
197 } | 170 } |
198 } | 171 } |
199 | 172 |
200 void NinjaScriptTargetWriter::WriteStamp( | 173 void NinjaScriptTargetWriter::WriteStamp( |
201 const std::vector<OutputFile>& output_files) { | 174 const std::vector<OutputFile>& output_files) { |
202 out_ << "build "; | 175 out_ << "build "; |
203 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); | 176 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); |
204 out_ << ": " | 177 out_ << ": " |
205 << helper_.GetRulePrefix(target_->settings()->toolchain()) | 178 << helper_.GetRulePrefix(target_->settings()->toolchain()) |
206 << "stamp"; | 179 << "stamp"; |
207 for (size_t i = 0; i < output_files.size(); i++) { | 180 for (size_t i = 0; i < output_files.size(); i++) { |
208 out_ << " "; | 181 out_ << " "; |
209 path_output_.WriteFile(out_, output_files[i]); | 182 path_output_.WriteFile(out_, output_files[i]); |
210 } | 183 } |
211 out_ << std::endl; | 184 out_ << std::endl; |
212 } | 185 } |
OLD | NEW |