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 <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 Loading... |
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 Loading... |
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 } |
OLD | NEW |