Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: tools/gn/ninja_binary_target_writer.cc

Issue 440333002: Support more configurability in GN toolchains (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: unsigned check Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/ninja_binary_target_writer.h ('k') | tools/gn/ninja_binary_target_writer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <set> 7 #include <set>
8 8
9 #include "base/strings/string_util.h" 9 #include "base/strings/string_util.h"
10 #include "tools/gn/config_values_extractors.h" 10 #include "tools/gn/config_values_extractors.h"
11 #include "tools/gn/err.h" 11 #include "tools/gn/err.h"
12 #include "tools/gn/escape.h" 12 #include "tools/gn/escape.h"
13 #include "tools/gn/ninja_utils.h"
14 #include "tools/gn/settings.h"
13 #include "tools/gn/string_utils.h" 15 #include "tools/gn/string_utils.h"
16 #include "tools/gn/substitution_writer.h"
17 #include "tools/gn/target.h"
14 18
15 namespace { 19 namespace {
16 20
17 // Returns the proper escape options for writing compiler and linker flags. 21 // Returns the proper escape options for writing compiler and linker flags.
18 EscapeOptions GetFlagOptions() { 22 EscapeOptions GetFlagOptions() {
19 EscapeOptions opts; 23 EscapeOptions opts;
20 opts.mode = ESCAPE_NINJA_COMMAND; 24 opts.mode = ESCAPE_NINJA_COMMAND;
21 25
22 // Some flag strings are actually multiple flags that expect to be just 26 // Some flag strings are actually multiple flags that expect to be just
23 // added to the command line. We assume that quoting is done by the 27 // added to the command line. We assume that quoting is done by the
(...skipping 10 matching lines...) Expand all
34 38
35 void operator()(const std::string& s, std::ostream& out) const { 39 void operator()(const std::string& s, std::ostream& out) const {
36 out << " -D"; 40 out << " -D";
37 EscapeStringToStream(out, s, options); 41 EscapeStringToStream(out, s, options);
38 } 42 }
39 43
40 EscapeOptions options; 44 EscapeOptions options;
41 }; 45 };
42 46
43 struct IncludeWriter { 47 struct IncludeWriter {
44 IncludeWriter(PathOutput& path_output, const NinjaHelper& h) 48 IncludeWriter(PathOutput& path_output) : path_output_(path_output) {
45 : helper(h),
46 path_output_(path_output) {
47 } 49 }
48 ~IncludeWriter() { 50 ~IncludeWriter() {
49 } 51 }
50 52
51 void operator()(const SourceDir& d, std::ostream& out) const { 53 void operator()(const SourceDir& d, std::ostream& out) const {
52 out << " -I"; 54 out << " -I";
53 path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH); 55 path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
54 } 56 }
55 57
56 const NinjaHelper& helper;
57 PathOutput& path_output_; 58 PathOutput& path_output_;
58 }; 59 };
59 60
60 Toolchain::ToolType GetToolTypeForTarget(const Target* target) {
61 switch (target->output_type()) {
62 case Target::STATIC_LIBRARY:
63 return Toolchain::TYPE_ALINK;
64 case Target::SHARED_LIBRARY:
65 return Toolchain::TYPE_SOLINK;
66 case Target::EXECUTABLE:
67 return Toolchain::TYPE_LINK;
68 default:
69 return Toolchain::TYPE_NONE;
70 }
71 }
72
73 } // namespace 61 } // namespace
74 62
75 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, 63 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
76 const Toolchain* toolchain,
77 std::ostream& out) 64 std::ostream& out)
78 : NinjaTargetWriter(target, toolchain, out), 65 : NinjaTargetWriter(target, out),
79 tool_type_(GetToolTypeForTarget(target)){ 66 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) {
80 } 67 }
81 68
82 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { 69 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
83 } 70 }
84 71
85 void NinjaBinaryTargetWriter::Run() { 72 void NinjaBinaryTargetWriter::Run() {
86 WriteCompilerVars(); 73 WriteCompilerVars();
87 74
88 std::vector<OutputFile> obj_files; 75 std::vector<OutputFile> obj_files;
89 WriteSources(&obj_files); 76 WriteSources(&obj_files);
90 77
91 if (target_->output_type() == Target::SOURCE_SET) 78 if (target_->output_type() == Target::SOURCE_SET)
92 WriteSourceSetStamp(obj_files); 79 WriteSourceSetStamp(obj_files);
93 else 80 else
94 WriteLinkerStuff(obj_files); 81 WriteLinkerStuff(obj_files);
95 } 82 }
96 83
97 void NinjaBinaryTargetWriter::WriteCompilerVars() { 84 void NinjaBinaryTargetWriter::WriteCompilerVars() {
85 const SubstitutionBits& subst = target_->toolchain()->substitution_bits();
86
98 // Defines. 87 // Defines.
99 out_ << "defines ="; 88 if (subst.used[SUBSTITUTION_DEFINES]) {
100 RecursiveTargetConfigToStream<std::string>(target_, &ConfigValues::defines, 89 out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " =";
101 DefineWriter(), out_); 90 RecursiveTargetConfigToStream<std::string>(
102 out_ << std::endl; 91 target_, &ConfigValues::defines, DefineWriter(), out_);
92 out_ << std::endl;
93 }
103 94
104 // Include directories. 95 // Include directories.
105 out_ << "includes ="; 96 if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) {
106 RecursiveTargetConfigToStream<SourceDir>(target_, &ConfigValues::include_dirs, 97 out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " =";
107 IncludeWriter(path_output_, helper_), 98 RecursiveTargetConfigToStream<SourceDir>(
108 out_); 99 target_, &ConfigValues::include_dirs,
109 100 IncludeWriter(path_output_), out_);
110 out_ << std::endl; 101 out_ << std::endl;
102 }
111 103
112 // C flags and friends. 104 // C flags and friends.
113 EscapeOptions flag_escape_options = GetFlagOptions(); 105 EscapeOptions flag_escape_options = GetFlagOptions();
114 #define WRITE_FLAGS(name) \ 106 #define WRITE_FLAGS(name, subst_enum) \
115 out_ << #name " ="; \ 107 if (subst.used[subst_enum]) { \
116 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \ 108 out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \
117 flag_escape_options, out_); \ 109 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \
118 out_ << std::endl; 110 flag_escape_options, out_); \
111 out_ << std::endl; \
112 }
119 113
120 WRITE_FLAGS(cflags) 114 WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS)
121 WRITE_FLAGS(cflags_c) 115 WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C)
122 WRITE_FLAGS(cflags_cc) 116 WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC)
123 WRITE_FLAGS(cflags_objc) 117 WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC)
124 WRITE_FLAGS(cflags_objcc) 118 WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC)
125 119
126 #undef WRITE_FLAGS 120 #undef WRITE_FLAGS
127 121
128 // Write some variables about the target for the toolchain definition to use. 122 WriteSharedVars(subst);
129 out_ << "target_name = " << target_->label().name() << std::endl;
130 out_ << "target_out_dir = ";
131 path_output_.WriteDir(out_, helper_.GetTargetOutputDir(target_),
132 PathOutput::DIR_NO_LAST_SLASH);
133 out_ << std::endl;
134 out_ << "root_out_dir = ";
135 path_output_.WriteDir(out_, target_->settings()->toolchain_output_subdir(),
136 PathOutput::DIR_NO_LAST_SLASH);
137 out_ << std::endl << std::endl;
138 } 123 }
139 124
140 void NinjaBinaryTargetWriter::WriteSources( 125 void NinjaBinaryTargetWriter::WriteSources(
141 std::vector<OutputFile>* object_files) { 126 std::vector<OutputFile>* object_files) {
142 const Target::FileList& sources = target_->sources(); 127 const Target::FileList& sources = target_->sources();
143 object_files->reserve(sources.size()); 128 object_files->reserve(sources.size());
144 129
145 std::string implicit_deps = 130 std::string implicit_deps =
146 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); 131 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
147 132
133 std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
134
135 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
148 for (size_t i = 0; i < sources.size(); i++) { 136 for (size_t i = 0; i < sources.size(); i++) {
149 const SourceFile& input_file = sources[i]; 137 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
138 if (!GetOutputFilesForSource(target_, sources[i],
139 &tool_type, &tool_outputs))
140 continue; // No output for this source.
150 141
151 SourceFileType input_file_type = GetSourceFileType(input_file); 142 if (tool_type != Toolchain::TYPE_NONE) {
152 if (input_file_type == SOURCE_UNKNOWN) 143 out_ << "build";
153 continue; // Skip unknown file types. 144 path_output_.WriteFiles(out_, tool_outputs);
154 if (input_file_type == SOURCE_O) { 145 out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type);
155 // Object files just get passed to the output and not compiled. 146 out_ << " ";
156 object_files->push_back(helper_.GetOutputFileForSource( 147 path_output_.WriteFile(out_, sources[i]);
157 target_, input_file, input_file_type)); 148 out_ << implicit_deps << std::endl;
158 continue;
159 } 149 }
160 std::string command =
161 helper_.GetRuleForSourceType(settings_, input_file_type);
162 if (command.empty())
163 continue; // Skip files not needing compilation.
164 150
165 OutputFile output_file = helper_.GetOutputFileForSource( 151 // It's theoretically possible for a compiler to produce more than one
166 target_, input_file, input_file_type); 152 // output, but we'll only link to the first output.
167 object_files->push_back(output_file); 153 object_files->push_back(tool_outputs[0]);
168
169 out_ << "build ";
170 path_output_.WriteFile(out_, output_file);
171 out_ << ": " << command << " ";
172 path_output_.WriteFile(out_, input_file);
173 out_ << implicit_deps << std::endl;
174 } 154 }
175 out_ << std::endl; 155 out_ << std::endl;
176 } 156 }
177 157
178 void NinjaBinaryTargetWriter::WriteLinkerStuff( 158 void NinjaBinaryTargetWriter::WriteLinkerStuff(
179 const std::vector<OutputFile>& object_files) { 159 const std::vector<OutputFile>& object_files) {
180 // Manifest file on Windows. 160 std::vector<OutputFile> output_files;
181 // TODO(brettw) this seems not to be necessary for static libs, skip in 161 SubstitutionWriter::ApplyListToLinkerAsOutputFile(
182 // that case? 162 target_, tool_, tool_->outputs(), &output_files);
183 OutputFile windows_manifest; 163
184 if (settings_->IsWin()) { 164 out_ << "build";
185 windows_manifest = helper_.GetTargetOutputDir(target_); 165 path_output_.WriteFiles(out_, output_files);
186 windows_manifest.value().append(target_->label().name()); 166
187 windows_manifest.value().append(".intermediate.manifest"); 167 out_ << ": "
188 out_ << "manifests = "; 168 << GetNinjaRulePrefixForToolchain(settings_)
189 path_output_.WriteFile(out_, windows_manifest); 169 << Toolchain::ToolTypeToName(
190 out_ << std::endl; 170 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_));
171
172 UniqueVector<OutputFile> extra_object_files;
173 UniqueVector<const Target*> linkable_deps;
174 UniqueVector<const Target*> non_linkable_deps;
175 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
176
177 // Object files.
178 for (size_t i = 0; i < object_files.size(); i++) {
179 out_ << " ";
180 path_output_.WriteFile(out_, object_files[i]);
181 }
182 for (size_t i = 0; i < extra_object_files.size(); i++) {
183 out_ << " ";
184 path_output_.WriteFile(out_, extra_object_files[i]);
191 } 185 }
192 186
193 const Toolchain::Tool& tool = toolchain_->GetTool(tool_type_); 187 std::vector<OutputFile> implicit_deps;
194 WriteLinkerFlags(tool, windows_manifest); 188 std::vector<OutputFile> solibs;
195 WriteLibs(tool);
196 189
197 // The external output file is the one that other libs depend on. 190 for (size_t i = 0; i < linkable_deps.size(); i++) {
198 OutputFile external_output_file = helper_.GetTargetOutputFile(target_); 191 const Target* cur = linkable_deps[i];
199 192
200 // The internal output file is the "main thing" we think we're making. In 193 // All linkable deps should have a link output file.
201 // the case of shared libraries, this is the shared library and the external 194 DCHECK(!cur->link_output_file().value().empty())
202 // output file is the import library. In other cases, the internal one and 195 << "No link output file for "
203 // the external one are the same. 196 << target_->label().GetUserVisibleName(false);
204 OutputFile internal_output_file; 197
205 if (target_->output_type() == Target::SHARED_LIBRARY) { 198 if (cur->dependency_output_file().value() !=
206 if (settings_->IsWin()) { 199 cur->link_output_file().value()) {
207 internal_output_file.value() = 200 // This is a shared library with separate link and deps files. Save for
208 target_->settings()->toolchain_output_subdir().value(); 201 // later.
209 internal_output_file.value().append(target_->label().name()); 202 implicit_deps.push_back(cur->dependency_output_file());
210 internal_output_file.value().append(".dll"); 203 solibs.push_back(cur->link_output_file());
211 } else { 204 } else {
212 internal_output_file = external_output_file; 205 // Normal case, just link to this target.
206 out_ << " ";
207 path_output_.WriteFile(out_, cur->link_output_file());
213 } 208 }
214 } else {
215 internal_output_file = external_output_file;
216 } 209 }
217 210
218 // In Python see "self.ninja.build(output, command, input," 211 // Append implicit dependencies collected above.
219 WriteLinkCommand(external_output_file, internal_output_file, object_files); 212 if (!implicit_deps.empty()) {
220 213 out_ << " |";
221 if (target_->output_type() == Target::SHARED_LIBRARY) { 214 path_output_.WriteFiles(out_, implicit_deps);
222 // The shared object name doesn't include a path.
223 out_ << " soname = ";
224 out_ << FindFilename(&internal_output_file.value());
225 out_ << std::endl;
226
227 out_ << " lib = ";
228 path_output_.WriteFile(out_, internal_output_file);
229 out_ << std::endl;
230
231 if (settings_->IsWin()) {
232 out_ << " dll = ";
233 path_output_.WriteFile(out_, internal_output_file);
234 out_ << std::endl;
235 }
236
237 if (settings_->IsWin()) {
238 out_ << " implibflag = /IMPLIB:";
239 path_output_.WriteFile(out_, external_output_file);
240 out_ << std::endl;
241 }
242
243 // TODO(brettw) postbuild steps.
244 if (settings_->IsMac())
245 out_ << " postbuilds = $ && (export BUILT_PRODUCTS_DIR=/Users/brettw/prj/ src/out/gn; export CONFIGURATION=Debug; export DYLIB_INSTALL_NAME_BASE=@rpath; e xport EXECUTABLE_NAME=libbase.dylib; export EXECUTABLE_PATH=libbase.dylib; expor t FULL_PRODUCT_NAME=libbase.dylib; export LD_DYLIB_INSTALL_NAME=@rpath/libbase.d ylib; export MACH_O_TYPE=mh_dylib; export PRODUCT_NAME=base; export PRODUCT_TYPE =com.apple.product-type.library.dynamic; export SDKROOT=/Applications/Xcode.app/ Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk; expo rt SRCROOT=/Users/brettw/prj/src/out/gn/../../base; export SOURCE_ROOT=\"$${SRCR OOT}\"; export TARGET_BUILD_DIR=/Users/brettw/prj/src/out/gn; export TEMP_DIR=\" $${TMPDIR}\"; (cd ../../base && ../build/mac/strip_from_xcode); G=$$?; ((exit $$ G) || rm -rf libbase.dylib) && exit $$G)";
246 } 215 }
247 216
217 // Append data dependencies as order-only dependencies.
218 WriteOrderOnlyDependencies(non_linkable_deps);
219
220 // End of the link "build" line.
248 out_ << std::endl; 221 out_ << std::endl;
222
223 // These go in the inner scope of the link line.
224 WriteLinkerFlags();
225 WriteLibs();
226 WriteOutputExtension();
227 WriteSolibs(solibs);
249 } 228 }
250 229
251 void NinjaBinaryTargetWriter::WriteLinkerFlags( 230 void NinjaBinaryTargetWriter::WriteLinkerFlags() {
252 const Toolchain::Tool& tool, 231 out_ << " ldflags =";
253 const OutputFile& windows_manifest) {
254 out_ << "ldflags =";
255 232
256 // First the ldflags from the target and its config. 233 // First the ldflags from the target and its config.
257 EscapeOptions flag_options = GetFlagOptions(); 234 EscapeOptions flag_options = GetFlagOptions();
258 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, 235 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
259 flag_options, out_); 236 flag_options, out_);
260 237
261 // Followed by library search paths that have been recursively pushed 238 // Followed by library search paths that have been recursively pushed
262 // through the dependency tree. 239 // through the dependency tree.
263 const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs(); 240 const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
264 if (!all_lib_dirs.empty()) { 241 if (!all_lib_dirs.empty()) {
265 // Since we're passing these on the command line to the linker and not 242 // Since we're passing these on the command line to the linker and not
266 // to Ninja, we need to do shell escaping. 243 // to Ninja, we need to do shell escaping.
267 PathOutput lib_path_output(path_output_.current_dir(), 244 PathOutput lib_path_output(path_output_.current_dir(),
268 ESCAPE_NINJA_COMMAND); 245 ESCAPE_NINJA_COMMAND);
269 for (size_t i = 0; i < all_lib_dirs.size(); i++) { 246 for (size_t i = 0; i < all_lib_dirs.size(); i++) {
270 out_ << " " << tool.lib_dir_prefix; 247 out_ << " " << tool_->lib_dir_switch();
271 lib_path_output.WriteDir(out_, all_lib_dirs[i], 248 lib_path_output.WriteDir(out_, all_lib_dirs[i],
272 PathOutput::DIR_NO_LAST_SLASH); 249 PathOutput::DIR_NO_LAST_SLASH);
273 } 250 }
274 } 251 }
275
276 // Append manifest flag on Windows to reference our file.
277 // HACK ERASEME BRETTW FIXME
278 if (settings_->IsWin()) {
279 out_ << " /MANIFEST /ManifestFile:";
280 path_output_.WriteFile(out_, windows_manifest);
281 }
282 out_ << std::endl; 252 out_ << std::endl;
283 } 253 }
284 254
285 void NinjaBinaryTargetWriter::WriteLibs(const Toolchain::Tool& tool) { 255 void NinjaBinaryTargetWriter::WriteLibs() {
286 out_ << "libs ="; 256 out_ << " libs =";
287 257
288 // Libraries that have been recursively pushed through the dependency tree. 258 // Libraries that have been recursively pushed through the dependency tree.
289 EscapeOptions lib_escape_opts; 259 EscapeOptions lib_escape_opts;
290 lib_escape_opts.mode = ESCAPE_NINJA_COMMAND; 260 lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
291 const OrderedSet<std::string> all_libs = target_->all_libs(); 261 const OrderedSet<std::string> all_libs = target_->all_libs();
292 const std::string framework_ending(".framework"); 262 const std::string framework_ending(".framework");
293 for (size_t i = 0; i < all_libs.size(); i++) { 263 for (size_t i = 0; i < all_libs.size(); i++) {
294 if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) { 264 if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) {
295 // Special-case libraries ending in ".framework" on Mac. Add the 265 // Special-case libraries ending in ".framework" on Mac. Add the
296 // -framework switch and don't add the extension to the output. 266 // -framework switch and don't add the extension to the output.
297 out_ << " -framework "; 267 out_ << " -framework ";
298 EscapeStringToStream(out_, 268 EscapeStringToStream(out_,
299 all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()), 269 all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()),
300 lib_escape_opts); 270 lib_escape_opts);
301 } else { 271 } else {
302 out_ << " " << tool.lib_prefix; 272 out_ << " " << tool_->lib_switch();
303 EscapeStringToStream(out_, all_libs[i], lib_escape_opts); 273 EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
304 } 274 }
305 } 275 }
306 out_ << std::endl; 276 out_ << std::endl;
307 } 277 }
308 278
309 void NinjaBinaryTargetWriter::WriteLinkCommand( 279 void NinjaBinaryTargetWriter::WriteOutputExtension() {
310 const OutputFile& external_output_file, 280 out_ << " output_extension = ";
311 const OutputFile& internal_output_file, 281 if (target_->output_extension().empty()) {
312 const std::vector<OutputFile>& object_files) { 282 // Use the default from the tool.
313 out_ << "build "; 283 out_ << tool_->default_output_extension();
314 path_output_.WriteFile(out_, internal_output_file); 284 } else {
315 if (external_output_file != internal_output_file) { 285 // Use the one specified in the target. Note that the one in the target
316 out_ << " "; 286 // does not include the leading dot, so add that.
317 path_output_.WriteFile(out_, external_output_file); 287 out_ << "." << target_->output_extension();
318 } 288 }
319 out_ << ": "
320 << helper_.GetRulePrefix(target_->settings())
321 << Toolchain::ToolTypeToName(tool_type_);
322
323 UniqueVector<OutputFile> extra_object_files;
324 UniqueVector<const Target*> linkable_deps;
325 UniqueVector<const Target*> non_linkable_deps;
326 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
327
328 // Object files.
329 for (size_t i = 0; i < object_files.size(); i++) {
330 out_ << " ";
331 path_output_.WriteFile(out_, object_files[i]);
332 }
333 for (size_t i = 0; i < extra_object_files.size(); i++) {
334 out_ << " ";
335 path_output_.WriteFile(out_, extra_object_files[i]);
336 }
337
338 // Libs.
339 for (size_t i = 0; i < linkable_deps.size(); i++) {
340 out_ << " ";
341 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(linkable_deps[i]));
342 }
343
344 // Append data dependencies as implicit dependencies.
345 WriteImplicitDependencies(non_linkable_deps);
346
347 out_ << std::endl; 289 out_ << std::endl;
348 } 290 }
349 291
292 void NinjaBinaryTargetWriter::WriteSolibs(
293 const std::vector<OutputFile>& solibs) {
294 if (solibs.empty())
295 return;
296
297 out_ << " solibs =";
298 path_output_.WriteFiles(out_, solibs);
299 out_ << std::endl;
300 }
301
350 void NinjaBinaryTargetWriter::WriteSourceSetStamp( 302 void NinjaBinaryTargetWriter::WriteSourceSetStamp(
351 const std::vector<OutputFile>& object_files) { 303 const std::vector<OutputFile>& object_files) {
352 // The stamp rule for source sets is generally not used, since targets that 304 // The stamp rule for source sets is generally not used, since targets that
353 // depend on this will reference the object files directly. However, writing 305 // depend on this will reference the object files directly. However, writing
354 // this rule allows the user to type the name of the target and get a build 306 // this rule allows the user to type the name of the target and get a build
355 // which can be convenient for development. 307 // which can be convenient for development.
356 out_ << "build ";
357 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
358 out_ << ": "
359 << helper_.GetRulePrefix(target_->settings())
360 << "stamp";
361
362 UniqueVector<OutputFile> extra_object_files; 308 UniqueVector<OutputFile> extra_object_files;
363 UniqueVector<const Target*> linkable_deps; 309 UniqueVector<const Target*> linkable_deps;
364 UniqueVector<const Target*> non_linkable_deps; 310 UniqueVector<const Target*> non_linkable_deps;
365 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); 311 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
366 312
367 // The classifier should never put extra object files in a source set: 313 // The classifier should never put extra object files in a source set:
368 // any source sets that we depend on should appear in our non-linkable 314 // any source sets that we depend on should appear in our non-linkable
369 // deps instead. 315 // deps instead.
370 DCHECK(extra_object_files.empty()); 316 DCHECK(extra_object_files.empty());
371 317
372 for (size_t i = 0; i < object_files.size(); i++) { 318 std::vector<OutputFile> order_only_deps;
373 out_ << " "; 319 for (size_t i = 0; i < non_linkable_deps.size(); i++)
374 path_output_.WriteFile(out_, object_files[i]); 320 order_only_deps.push_back(non_linkable_deps[i]->dependency_output_file());
375 }
376 321
377 // Append data dependencies as implicit dependencies. 322 WriteStampForTarget(object_files, order_only_deps);
378 WriteImplicitDependencies(non_linkable_deps);
379
380 out_ << std::endl;
381 } 323 }
382 324
383 void NinjaBinaryTargetWriter::GetDeps( 325 void NinjaBinaryTargetWriter::GetDeps(
384 UniqueVector<OutputFile>* extra_object_files, 326 UniqueVector<OutputFile>* extra_object_files,
385 UniqueVector<const Target*>* linkable_deps, 327 UniqueVector<const Target*>* linkable_deps,
386 UniqueVector<const Target*>* non_linkable_deps) const { 328 UniqueVector<const Target*>* non_linkable_deps) const {
387 const LabelTargetVector& deps = target_->deps(); 329 const LabelTargetVector& deps = target_->deps();
388 const UniqueVector<const Target*>& inherited = 330 const UniqueVector<const Target*>& inherited =
389 target_->inherited_libraries(); 331 target_->inherited_libraries();
390 332
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 // source set can easily get linked more than once which will cause 367 // source set can easily get linked more than once which will cause
426 // multiple definition errors. 368 // multiple definition errors.
427 // 369 //
428 // In the future, we may need a way to specify a "complete" static library 370 // In the future, we may need a way to specify a "complete" static library
429 // for cases where you want a static library that includes all source sets 371 // for cases where you want a static library that includes all source sets
430 // (like if you're shipping that to customers to link against). 372 // (like if you're shipping that to customers to link against).
431 if (target_->output_type() != Target::SOURCE_SET && 373 if (target_->output_type() != Target::SOURCE_SET &&
432 target_->output_type() != Target::STATIC_LIBRARY) { 374 target_->output_type() != Target::STATIC_LIBRARY) {
433 // Linking in a source set to an executable or shared library, copy its 375 // Linking in a source set to an executable or shared library, copy its
434 // object files. 376 // object files.
377 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
435 for (size_t i = 0; i < dep->sources().size(); i++) { 378 for (size_t i = 0; i < dep->sources().size(); i++) {
436 SourceFileType input_file_type = GetSourceFileType(dep->sources()[i]); 379 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
437 if (input_file_type != SOURCE_UNKNOWN && 380 if (GetOutputFilesForSource(dep, dep->sources()[i], &tool_type,
438 input_file_type != SOURCE_H) { 381 &tool_outputs)) {
439 // Note we need to specify the target as the source_set target 382 // Only link the first output if there are more than one.
440 // itself, since this is used to prefix the object file name. 383 extra_object_files->push_back(tool_outputs[0]);
441 extra_object_files->push_back(helper_.GetOutputFileForSource(
442 dep, dep->sources()[i], input_file_type));
443 } 384 }
444 } 385 }
445 } 386 }
446 } else if (can_link_libs && dep->IsLinkable()) { 387 } else if (can_link_libs && dep->IsLinkable()) {
447 linkable_deps->push_back(dep); 388 linkable_deps->push_back(dep);
448 } else { 389 } else {
449 non_linkable_deps->push_back(dep); 390 non_linkable_deps->push_back(dep);
450 } 391 }
451 } 392 }
452 393
453 void NinjaBinaryTargetWriter::WriteImplicitDependencies( 394 void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies(
454 const UniqueVector<const Target*>& non_linkable_deps) { 395 const UniqueVector<const Target*>& non_linkable_deps) {
455 const std::vector<SourceFile>& data = target_->data(); 396 const std::vector<SourceFile>& data = target_->data();
456 if (!non_linkable_deps.empty() || !data.empty()) { 397 if (!non_linkable_deps.empty() || !data.empty()) {
457 out_ << " ||"; 398 out_ << " ||";
458 399
459 // Non-linkable targets. 400 // Non-linkable targets.
460 for (size_t i = 0; i < non_linkable_deps.size(); i++) { 401 for (size_t i = 0; i < non_linkable_deps.size(); i++) {
461 out_ << " "; 402 out_ << " ";
462 path_output_.WriteFile(out_, 403 path_output_.WriteFile(
463 helper_.GetTargetOutputFile(non_linkable_deps[i])); 404 out_, non_linkable_deps[i]->dependency_output_file());
464 }
465
466 // Data files.
467 const std::vector<SourceFile>& data = target_->data();
468 for (size_t i = 0; i < data.size(); i++) {
469 out_ << " ";
470 path_output_.WriteFile(out_, data[i]);
471 } 405 }
472 } 406 }
473 } 407 }
408
409 bool NinjaBinaryTargetWriter::GetOutputFilesForSource(
410 const Target* target,
411 const SourceFile& source,
412 Toolchain::ToolType* computed_tool_type,
413 std::vector<OutputFile>* outputs) const {
414 outputs->clear();
415 *computed_tool_type = Toolchain::TYPE_NONE;
416
417 SourceFileType file_type = GetSourceFileType(source);
418 if (file_type == SOURCE_UNKNOWN)
419 return false;
420 if (file_type == SOURCE_O) {
421 // Object files just get passed to the output and not compiled.
422 outputs->push_back(OutputFile(settings_->build_settings(), source));
423 return true;
424 }
425
426 *computed_tool_type =
427 target->toolchain()->GetToolTypeForSourceType(file_type);
428 if (*computed_tool_type == Toolchain::TYPE_NONE)
429 return false; // No tool for this file (it's a header file or something).
430 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
431 if (!tool)
432 return false; // Tool does not apply for this toolchain.file.
433
434 // Figure out what output(s) this compiler produces.
435 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
436 target, source, tool->outputs(), outputs);
437 return !outputs->empty();
438 }
OLDNEW
« no previous file with comments | « tools/gn/ninja_binary_target_writer.h ('k') | tools/gn/ninja_binary_target_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698