1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "tools/gn/ninja_binary_target_writer.h" 6 7 #include <set> 8 #include <sstream> 9 10 #include "base/strings/string_util.h" 11 #include "tools/gn/config_values_extractors.h" 12 #include "tools/gn/deps_iterator.h" 13 #include "tools/gn/err.h" 14 #include "tools/gn/escape.h" 15 #include "tools/gn/ninja_utils.h" 16 #include "tools/gn/settings.h" 17 #include "tools/gn/string_utils.h" 18 #include "tools/gn/substitution_writer.h" 19 #include "tools/gn/target.h" 20 21 namespace { 22 23 // Returns the proper escape options for writing compiler and linker flags. 24 EscapeOptions GetFlagOptions() { 25 EscapeOptions opts; 26 opts.mode = ESCAPE_NINJA_COMMAND; 27 28 // Some flag strings are actually multiple flags that expect to be just 29 // added to the command line. We assume that quoting is done by the 30 // buildfiles if it wants such things quoted. 31 opts.inhibit_quoting = true; 32 33 return opts; 34 } 35 36 struct DefineWriter { 37 DefineWriter() { 38 options.mode = ESCAPE_NINJA_COMMAND; 39 } 40 41 void operator()(const std::string& s, std::ostream& out) const { 42 out << " -D"; 43 EscapeStringToStream(out, s, options); 44 } 45 46 EscapeOptions options; 47 }; 48 49 struct IncludeWriter { 50 IncludeWriter(PathOutput& path_output) : path_output_(path_output) { 51 } 52 ~IncludeWriter() { 53 } 54 55 void operator()(const SourceDir& d, std::ostream& out) const { 56 std::ostringstream path_out; 57 path_output_.WriteDir(path_out, d, PathOutput::DIR_NO_LAST_SLASH); 58 const std::string& path = path_out.str(); 59 if (path[0] == '"') 60 out << " \"-I" << path.substr(1); 61 else 62 out << " -I" << path; 63 } 64 65 PathOutput& path_output_; 66 }; 67 68 } // namespace 69 70 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, 71 std::ostream& out) 72 : NinjaTargetWriter(target, out), 73 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) { 74 } 75 76 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { 77 } 78 79 void NinjaBinaryTargetWriter::Run() { 80 WriteCompilerVars(); 81 82 std::vector<OutputFile> obj_files; 83 WriteSources(&obj_files); 84 85 if (target_->output_type() == Target::SOURCE_SET) 86 WriteSourceSetStamp(obj_files); 87 else 88 WriteLinkerStuff(obj_files); 89 } 90 91 void NinjaBinaryTargetWriter::WriteCompilerVars() { 92 const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); 93 94 // Defines. 95 if (subst.used[SUBSTITUTION_DEFINES]) { 96 out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " ="; 97 RecursiveTargetConfigToStream<std::string>( 98 target_, &ConfigValues::defines, DefineWriter(), out_); 99 out_ << std::endl; 100 } 101 102 // Include directories. 103 if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) { 104 out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " ="; 105 PathOutput include_path_output(path_output_.current_dir(), 106 ESCAPE_NINJA_COMMAND); 107 RecursiveTargetConfigToStream<SourceDir>( 108 target_, &ConfigValues::include_dirs, 109 IncludeWriter(include_path_output), out_); 110 out_ << std::endl; 111 } 112 113 // C flags and friends. 114 EscapeOptions flag_escape_options = GetFlagOptions(); 115 #define WRITE_FLAGS(name, subst_enum) \ 116 if (subst.used[subst_enum]) { \ 117 out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \ 118 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \ 119 flag_escape_options, out_); \ 120 out_ << std::endl; \ 121 } 122 123 WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS) 124 WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C) 125 WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC) 126 WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC) 127 WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC) 128 129 #undef WRITE_FLAGS 130 131 WriteSharedVars(subst); 132 } 133 134 void NinjaBinaryTargetWriter::WriteSources( 135 std::vector<OutputFile>* object_files) { 136 const Target::FileList& sources = target_->sources(); 137 object_files->reserve(sources.size()); 138 139 OutputFile input_dep = 140 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); 141 142 std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_); 143 144 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. 145 for (size_t i = 0; i < sources.size(); i++) { 146 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 147 if (!GetOutputFilesForSource(target_, sources[i], 148 &tool_type, &tool_outputs)) 149 continue; // No output for this source. 150 151 if (tool_type != Toolchain::TYPE_NONE) { 152 out_ << "build"; 153 path_output_.WriteFiles(out_, tool_outputs); 154 out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type); 155 out_ << " "; 156 path_output_.WriteFile(out_, sources[i]); 157 if (!input_dep.value().empty()) { 158 // Write out the input dependencies as an order-only dependency. This 159 // will cause Ninja to make sure the inputs are up-to-date before 160 // compiling this source, but changes in the inputs deps won't cause 161 // the file to be recompiled. 162 // 163 // This is important to prevent changes in unrelated actions that 164 // are upstream of this target from causing everything to be recompiled. 165 // 166 // Why can we get away with this rather than using implicit deps ("|", 167 // which will force rebuilds when the inputs change)? For source code, 168 // the computed dependencies of all headers will be computed by the 169 // compiler, which will cause source rebuilds if any "real" upstream 170 // dependencies change. 171 // 172 // If a .cc file is generated by an input dependency, Ninja will see 173 // the input to the build rule doesn't exist, and that it is an output 174 // from a previous step, and build the previous step first. This is a 175 // "real" dependency and doesn't need | or || to express. 176 // 177 // The only case where this rule matters is for the first build where 178 // no .d files exist, and Ninja doesn't know what that source file 179 // depends on. In this case it's sufficient to ensure that the upstream 180 // dependencies are built first. This is exactly what Ninja's order- 181 // only dependencies expresses. 182 out_ << " || "; 183 path_output_.WriteFile(out_, input_dep); 184 } 185 out_ << std::endl; 186 } 187 188 // It's theoretically possible for a compiler to produce more than one 189 // output, but we'll only link to the first output. 190 object_files->push_back(tool_outputs[0]); 191 } 192 out_ << std::endl; 193 } 194 195 void NinjaBinaryTargetWriter::WriteLinkerStuff( 196 const std::vector<OutputFile>& object_files) { 197 std::vector<OutputFile> output_files; 198 SubstitutionWriter::ApplyListToLinkerAsOutputFile( 199 target_, tool_, tool_->outputs(), &output_files); 200 201 out_ << "build"; 202 path_output_.WriteFiles(out_, output_files); 203 204 out_ << ": " 205 << GetNinjaRulePrefixForToolchain(settings_) 206 << Toolchain::ToolTypeToName( 207 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_)); 208 209 UniqueVector<OutputFile> extra_object_files; 210 UniqueVector<const Target*> linkable_deps; 211 UniqueVector<const Target*> non_linkable_deps; 212 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); 213 214 // Object files. 215 for (size_t i = 0; i < object_files.size(); i++) { 216 out_ << " "; 217 path_output_.WriteFile(out_, object_files[i]); 218 } 219 for (size_t i = 0; i < extra_object_files.size(); i++) { 220 out_ << " "; 221 path_output_.WriteFile(out_, extra_object_files[i]); 222 } 223 224 std::vector<OutputFile> implicit_deps; 225 std::vector<OutputFile> solibs; 226 227 for (size_t i = 0; i < linkable_deps.size(); i++) { 228 const Target* cur = linkable_deps[i]; 229 230 // All linkable deps should have a link output file. 231 DCHECK(!cur->link_output_file().value().empty()) 232 << "No link output file for " 233 << target_->label().GetUserVisibleName(false); 234 235 if (cur->dependency_output_file().value() != 236 cur->link_output_file().value()) { 237 // This is a shared library with separate link and deps files. Save for 238 // later. 239 implicit_deps.push_back(cur->dependency_output_file()); 240 solibs.push_back(cur->link_output_file()); 241 } else { 242 // Normal case, just link to this target. 243 out_ << " "; 244 path_output_.WriteFile(out_, cur->link_output_file()); 245 } 246 } 247 248 // Append implicit dependencies collected above. 249 if (!implicit_deps.empty()) { 250 out_ << " |"; 251 path_output_.WriteFiles(out_, implicit_deps); 252 } 253 254 // Append data dependencies as order-only dependencies. 255 // 256 // This will include data dependencies and input dependencies (like when 257 // this target depends on an action). Having the data dependencies in this 258 // list ensures that the data is available at runtime when the user builds 259 // this target. 260 // 261 // The action dependencies are not strictly necessary in this case. They 262 // should also have been collected via the input deps stamp that each source 263 // file has for an order-only dependency, and since this target depends on 264 // the sources, there is already an implicit order-only dependency. However, 265 // it's extra work to separate these out and there's no disadvantage to 266 // listing them again. 267 WriteOrderOnlyDependencies(non_linkable_deps); 268 269 // End of the link "build" line. 270 out_ << std::endl; 271 272 // These go in the inner scope of the link line. 273 WriteLinkerFlags(); 274 WriteLibs(); 275 WriteOutputExtension(); 276 WriteSolibs(solibs); 277 } 278 279 void NinjaBinaryTargetWriter::WriteLinkerFlags() { 280 out_ << " ldflags ="; 281 282 // First the ldflags from the target and its config. 283 EscapeOptions flag_options = GetFlagOptions(); 284 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, 285 flag_options, out_); 286 287 // Followed by library search paths that have been recursively pushed 288 // through the dependency tree. 289 const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs(); 290 if (!all_lib_dirs.empty()) { 291 // Since we're passing these on the command line to the linker and not 292 // to Ninja, we need to do shell escaping. 293 PathOutput lib_path_output(path_output_.current_dir(), 294 ESCAPE_NINJA_COMMAND); 295 for (size_t i = 0; i < all_lib_dirs.size(); i++) { 296 out_ << " " << tool_->lib_dir_switch(); 297 lib_path_output.WriteDir(out_, all_lib_dirs[i], 298 PathOutput::DIR_NO_LAST_SLASH); 299 } 300 } 301 out_ << std::endl; 302 } 303 304 void NinjaBinaryTargetWriter::WriteLibs() { 305 out_ << " libs ="; 306 307 // Libraries that have been recursively pushed through the dependency tree. 308 EscapeOptions lib_escape_opts; 309 lib_escape_opts.mode = ESCAPE_NINJA_COMMAND; 310 const OrderedSet<std::string> all_libs = target_->all_libs(); 311 const std::string framework_ending(".framework"); 312 for (size_t i = 0; i < all_libs.size(); i++) { 313 if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) { 314 // Special-case libraries ending in ".framework" on Mac. Add the 315 // -framework switch and don't add the extension to the output. 316 out_ << " -framework "; 317 EscapeStringToStream(out_, 318 all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()), 319 lib_escape_opts); 320 } else { 321 out_ << " " << tool_->lib_switch(); 322 EscapeStringToStream(out_, all_libs[i], lib_escape_opts); 323 } 324 } 325 out_ << std::endl; 326 } 327 328 void NinjaBinaryTargetWriter::WriteOutputExtension() { 329 out_ << " output_extension = "; 330 if (target_->output_extension().empty()) { 331 // Use the default from the tool. 332 out_ << tool_->default_output_extension(); 333 } else { 334 // Use the one specified in the target. Note that the one in the target 335 // does not include the leading dot, so add that. 336 out_ << "." << target_->output_extension(); 337 } 338 out_ << std::endl; 339 } 340 341 void NinjaBinaryTargetWriter::WriteSolibs( 342 const std::vector<OutputFile>& solibs) { 343 if (solibs.empty()) 344 return; 345 346 out_ << " solibs ="; 347 path_output_.WriteFiles(out_, solibs); 348 out_ << std::endl; 349 } 350 351 void NinjaBinaryTargetWriter::WriteSourceSetStamp( 352 const std::vector<OutputFile>& object_files) { 353 // The stamp rule for source sets is generally not used, since targets that 354 // depend on this will reference the object files directly. However, writing 355 // this rule allows the user to type the name of the target and get a build 356 // which can be convenient for development. 357 UniqueVector<OutputFile> extra_object_files; 358 UniqueVector<const Target*> linkable_deps; 359 UniqueVector<const Target*> non_linkable_deps; 360 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); 361 362 // The classifier should never put extra object files in a source set: 363 // any source sets that we depend on should appear in our non-linkable 364 // deps instead. 365 DCHECK(extra_object_files.empty()); 366 367 std::vector<OutputFile> order_only_deps; 368 for (size_t i = 0; i < non_linkable_deps.size(); i++) 369 order_only_deps.push_back(non_linkable_deps[i]->dependency_output_file()); 370 371 WriteStampForTarget(object_files, order_only_deps); 372 } 373 374 void NinjaBinaryTargetWriter::GetDeps( 375 UniqueVector<OutputFile>* extra_object_files, 376 UniqueVector<const Target*>* linkable_deps, 377 UniqueVector<const Target*>* non_linkable_deps) const { 378 const UniqueVector<const Target*>& inherited = 379 target_->inherited_libraries(); 380 381 // Normal public/private deps. 382 for (DepsIterator iter(target_, DepsIterator::LINKED_ONLY); !iter.done(); 383 iter.Advance()) { 384 ClassifyDependency(iter.target(), extra_object_files, 385 linkable_deps, non_linkable_deps); 386 } 387 388 // Inherited libraries. 389 for (size_t i = 0; i < inherited.size(); i++) { 390 ClassifyDependency(inherited[i], extra_object_files, 391 linkable_deps, non_linkable_deps); 392 } 393 394 // Data deps. 395 const LabelTargetVector& data_deps = target_->data_deps(); 396 for (size_t i = 0; i < data_deps.size(); i++) 397 non_linkable_deps->push_back(data_deps[i].ptr); 398 } 399 400 void NinjaBinaryTargetWriter::ClassifyDependency( 401 const Target* dep, 402 UniqueVector<OutputFile>* extra_object_files, 403 UniqueVector<const Target*>* linkable_deps, 404 UniqueVector<const Target*>* non_linkable_deps) const { 405 // Only the following types of outputs have libraries linked into them: 406 // EXECUTABLE 407 // SHARED_LIBRARY 408 // _complete_ STATIC_LIBRARY 409 // 410 // Child deps of intermediate static libraries get pushed up the 411 // dependency tree until one of these is reached, and source sets 412 // don't link at all. 413 bool can_link_libs = target_->IsFinal(); 414 415 if (dep->output_type() == Target::SOURCE_SET) { 416 // Source sets have their object files linked into final targets 417 // (shared libraries, executables, and complete static 418 // libraries). Intermediate static libraries and other source sets 419 // just forward the dependency, otherwise the files in the source 420 // set can easily get linked more than once which will cause 421 // multiple definition errors. 422 if (can_link_libs) { 423 // Linking in a source set to an executable, shared library, or 424 // complete static library, so copy its object files. 425 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop. 426 for (size_t i = 0; i < dep->sources().size(); i++) { 427 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 428 if (GetOutputFilesForSource(dep, dep->sources()[i], &tool_type, 429 &tool_outputs)) { 430 // Only link the first output if there are more than one. 431 extra_object_files->push_back(tool_outputs[0]); 432 } 433 } 434 } 435 } else if (can_link_libs && dep->IsLinkable()) { 436 linkable_deps->push_back(dep); 437 } else { 438 non_linkable_deps->push_back(dep); 439 } 440 } 441 442 void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies( 443 const UniqueVector<const Target*>& non_linkable_deps) { 444 const std::vector<SourceFile>& data = target_->data(); 445 if (!non_linkable_deps.empty() || !data.empty()) { 446 out_ << " ||"; 447 448 // Non-linkable targets. 449 for (size_t i = 0; i < non_linkable_deps.size(); i++) { 450 out_ << " "; 451 path_output_.WriteFile( 452 out_, non_linkable_deps[i]->dependency_output_file()); 453 } 454 } 455 } 456 457 bool NinjaBinaryTargetWriter::GetOutputFilesForSource( 458 const Target* target, 459 const SourceFile& source, 460 Toolchain::ToolType* computed_tool_type, 461 std::vector<OutputFile>* outputs) const { 462 outputs->clear(); 463 *computed_tool_type = Toolchain::TYPE_NONE; 464 465 SourceFileType file_type = GetSourceFileType(source); 466 if (file_type == SOURCE_UNKNOWN) 467 return false; 468 if (file_type == SOURCE_O) { 469 // Object files just get passed to the output and not compiled. 470 outputs->push_back(OutputFile(settings_->build_settings(), source)); 471 return true; 472 } 473 474 *computed_tool_type = 475 target->toolchain()->GetToolTypeForSourceType(file_type); 476 if (*computed_tool_type == Toolchain::TYPE_NONE) 477 return false; // No tool for this file (it's a header file or something). 478 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type); 479 if (!tool) 480 return false; // Tool does not apply for this toolchain.file. 481 482 // Figure out what output(s) this compiler produces. 483 SubstitutionWriter::ApplyListToCompilerAsOutputFile( 484 target, source, tool->outputs(), outputs); 485 return !outputs->empty(); 486 } 487