| 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 |