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" |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 | 72 |
73 Toolchain::ToolType GetToolTypeForTarget(const Target* target) { | 73 Toolchain::ToolType GetToolTypeForTarget(const Target* target) { |
74 switch (target->output_type()) { | 74 switch (target->output_type()) { |
75 case Target::STATIC_LIBRARY: | 75 case Target::STATIC_LIBRARY: |
76 return Toolchain::TYPE_ALINK; | 76 return Toolchain::TYPE_ALINK; |
77 case Target::SHARED_LIBRARY: | 77 case Target::SHARED_LIBRARY: |
78 return Toolchain::TYPE_SOLINK; | 78 return Toolchain::TYPE_SOLINK; |
79 case Target::EXECUTABLE: | 79 case Target::EXECUTABLE: |
80 return Toolchain::TYPE_LINK; | 80 return Toolchain::TYPE_LINK; |
81 default: | 81 default: |
82 NOTREACHED(); | |
83 return Toolchain::TYPE_NONE; | 82 return Toolchain::TYPE_NONE; |
84 } | 83 } |
85 } | 84 } |
86 | 85 |
87 } // namespace | 86 } // namespace |
88 | 87 |
89 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, | 88 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, |
90 std::ostream& out) | 89 std::ostream& out) |
91 : NinjaTargetWriter(target, out), | 90 : NinjaTargetWriter(target, out), |
92 tool_type_(GetToolTypeForTarget(target)){ | 91 tool_type_(GetToolTypeForTarget(target)){ |
93 } | 92 } |
94 | 93 |
95 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { | 94 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { |
96 } | 95 } |
97 | 96 |
98 void NinjaBinaryTargetWriter::Run() { | 97 void NinjaBinaryTargetWriter::Run() { |
99 WriteEnvironment(); | 98 WriteEnvironment(); |
100 | 99 |
101 WriteCompilerVars(); | 100 WriteCompilerVars(); |
102 | 101 |
103 std::vector<OutputFile> obj_files; | 102 std::vector<OutputFile> obj_files; |
104 WriteSources(&obj_files); | 103 WriteSources(&obj_files); |
105 | 104 |
106 WriteLinkerStuff(obj_files); | 105 if (target_->output_type() == Target::SOURCE_SET) |
| 106 WriteSourceSetStamp(obj_files); |
| 107 else |
| 108 WriteLinkerStuff(obj_files); |
107 } | 109 } |
108 | 110 |
109 void NinjaBinaryTargetWriter::WriteCompilerVars() { | 111 void NinjaBinaryTargetWriter::WriteCompilerVars() { |
110 // Defines. | 112 // Defines. |
111 out_ << "defines ="; | 113 out_ << "defines ="; |
112 RecursiveTargetConfigToStream<std::string>(target_, &ConfigValues::defines, | 114 RecursiveTargetConfigToStream<std::string>(target_, &ConfigValues::defines, |
113 DefineWriter(), out_); | 115 DefineWriter(), out_); |
114 out_ << std::endl; | 116 out_ << std::endl; |
115 | 117 |
116 // Include directories. | 118 // Include directories. |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 out_ << "build "; | 304 out_ << "build "; |
303 path_output_.WriteFile(out_, internal_output_file); | 305 path_output_.WriteFile(out_, internal_output_file); |
304 if (external_output_file != internal_output_file) { | 306 if (external_output_file != internal_output_file) { |
305 out_ << " "; | 307 out_ << " "; |
306 path_output_.WriteFile(out_, external_output_file); | 308 path_output_.WriteFile(out_, external_output_file); |
307 } | 309 } |
308 out_ << ": " | 310 out_ << ": " |
309 << helper_.GetRulePrefix(GetToolchain()) | 311 << helper_.GetRulePrefix(GetToolchain()) |
310 << Toolchain::ToolTypeToName(tool_type_); | 312 << Toolchain::ToolTypeToName(tool_type_); |
311 | 313 |
| 314 std::set<OutputFile> extra_object_files; |
| 315 std::vector<const Target*> linkable_deps; |
| 316 std::vector<const Target*> non_linkable_deps; |
| 317 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); |
| 318 |
312 // Object files. | 319 // Object files. |
313 for (size_t i = 0; i < object_files.size(); i++) { | 320 for (size_t i = 0; i < object_files.size(); i++) { |
314 out_ << " "; | 321 out_ << " "; |
315 path_output_.WriteFile(out_, object_files[i]); | 322 path_output_.WriteFile(out_, object_files[i]); |
316 } | 323 } |
| 324 for (std::set<OutputFile>::iterator i = extra_object_files.begin(); |
| 325 i != extra_object_files.end(); ++i) { |
| 326 out_ << " "; |
| 327 path_output_.WriteFile(out_, *i); |
| 328 } |
317 | 329 |
318 // Library inputs (deps and inherited static libraries). | 330 // Libs. |
319 // | 331 for (size_t i = 0; i < linkable_deps.size(); i++) { |
320 // Static libraries since they're just a collection of the object files so | 332 out_ << " "; |
321 // don't need libraries linked with them, but we still need to go through | 333 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(linkable_deps[i])); |
322 // the list and find non-linkable data deps in the "deps" section. We'll | |
323 // collect all non-linkable deps and put it in the implicit deps below. | |
324 std::vector<const Target*> extra_data_deps; | |
325 const std::vector<const Target*>& deps = target_->deps(); | |
326 const std::set<const Target*>& inherited = target_->inherited_libraries(); | |
327 for (size_t i = 0; i < deps.size(); i++) { | |
328 if (inherited.find(deps[i]) != inherited.end()) | |
329 continue; | |
330 if (target_->output_type() != Target::STATIC_LIBRARY && | |
331 deps[i]->IsLinkable()) { | |
332 out_ << " "; | |
333 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(deps[i])); | |
334 } else { | |
335 extra_data_deps.push_back(deps[i]); | |
336 } | |
337 } | |
338 for (std::set<const Target*>::const_iterator i = inherited.begin(); | |
339 i != inherited.end(); ++i) { | |
340 if (target_->output_type() == Target::STATIC_LIBRARY) { | |
341 extra_data_deps.push_back(*i); | |
342 } else { | |
343 out_ << " "; | |
344 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i)); | |
345 } | |
346 } | 334 } |
347 | 335 |
348 // External link deps from GYP. This is indexed by a label with no toolchain. | 336 // External link deps from GYP. This is indexed by a label with no toolchain. |
349 typedef BuildSettings::AdditionalLibsMap LibsMap; | 337 typedef BuildSettings::AdditionalLibsMap LibsMap; |
350 const LibsMap& libs = settings_->build_settings()->external_link_deps(); | 338 const LibsMap& libs = settings_->build_settings()->external_link_deps(); |
351 Label libs_key(target_->label().dir(), target_->label().name()); | 339 Label libs_key(target_->label().dir(), target_->label().name()); |
352 LibsMap::const_iterator libs_end = libs.upper_bound(libs_key); | 340 LibsMap::const_iterator libs_end = libs.upper_bound(libs_key); |
353 for (LibsMap::const_iterator i = libs.lower_bound(libs_key); | 341 for (LibsMap::const_iterator i = libs.lower_bound(libs_key); |
354 i != libs_end; ++i) { | 342 i != libs_end; ++i) { |
355 out_ << " "; | 343 out_ << " "; |
356 path_output_.WriteFile(out_, i->second); | 344 path_output_.WriteFile(out_, i->second); |
357 } | 345 } |
358 | 346 |
359 // Append data dependencies as implicit dependencies. | 347 // Append data dependencies as implicit dependencies. |
| 348 WriteImplicitDependencies(non_linkable_deps); |
| 349 |
| 350 out_ << std::endl; |
| 351 } |
| 352 |
| 353 void NinjaBinaryTargetWriter::WriteSourceSetStamp( |
| 354 const std::vector<OutputFile>& object_files) { |
| 355 // The stamp rule for source sets is generally not used, since targets that |
| 356 // depend on this will reference the object files directly. However, writing |
| 357 // this rule allows the user to type the name of the target and get a build |
| 358 // which can be convenient for development. |
| 359 out_ << "build "; |
| 360 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); |
| 361 out_ << ": " |
| 362 << helper_.GetRulePrefix(target_->settings()->toolchain()) |
| 363 << "stamp"; |
| 364 |
| 365 std::set<OutputFile> extra_object_files; |
| 366 std::vector<const Target*> linkable_deps; |
| 367 std::vector<const Target*> non_linkable_deps; |
| 368 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); |
| 369 |
| 370 // The classifier should never put extra object files in a source set: |
| 371 // any source sets that we depend on should appear in our non-linkable |
| 372 // deps instead. |
| 373 DCHECK(extra_object_files.empty()); |
| 374 |
| 375 for (size_t i = 0; i < object_files.size(); i++) { |
| 376 out_ << " "; |
| 377 path_output_.WriteFile(out_, object_files[i]); |
| 378 } |
| 379 |
| 380 // Append data dependencies as implicit dependencies. |
| 381 WriteImplicitDependencies(non_linkable_deps); |
| 382 |
| 383 out_ << std::endl; |
| 384 } |
| 385 |
| 386 void NinjaBinaryTargetWriter::GetDeps( |
| 387 std::set<OutputFile>* extra_object_files, |
| 388 std::vector<const Target*>* linkable_deps, |
| 389 std::vector<const Target*>* non_linkable_deps) const { |
| 390 const std::vector<const Target*>& deps = target_->deps(); |
| 391 const std::set<const Target*>& inherited = target_->inherited_libraries(); |
| 392 |
| 393 // Normal deps. |
| 394 for (size_t i = 0; i < deps.size(); i++) { |
| 395 if (inherited.find(deps[i]) != inherited.end()) |
| 396 continue; // Don't add dupes. |
| 397 ClassifyDependency(deps[i], extra_object_files, |
| 398 linkable_deps, non_linkable_deps); |
| 399 } |
| 400 |
| 401 // Inherited libraries. |
| 402 for (std::set<const Target*>::const_iterator i = inherited.begin(); |
| 403 i != inherited.end(); ++i) { |
| 404 ClassifyDependency(*i, extra_object_files, |
| 405 linkable_deps, non_linkable_deps); |
| 406 } |
| 407 |
| 408 // Data deps. |
360 const std::vector<const Target*>& datadeps = target_->datadeps(); | 409 const std::vector<const Target*>& datadeps = target_->datadeps(); |
| 410 for (size_t i = 0; i < datadeps.size(); i++) |
| 411 non_linkable_deps->push_back(datadeps[i]); |
| 412 } |
| 413 |
| 414 void NinjaBinaryTargetWriter::ClassifyDependency( |
| 415 const Target* dep, |
| 416 std::set<OutputFile>* extra_object_files, |
| 417 std::vector<const Target*>* linkable_deps, |
| 418 std::vector<const Target*>* non_linkable_deps) const { |
| 419 // Only these types of outputs have libraries linked into them. Child deps of |
| 420 // static libraries get pushed up the dependency tree until one of these is |
| 421 // reached, and source sets don't link at all. |
| 422 bool can_link_libs = |
| 423 (target_->output_type() == Target::EXECUTABLE || |
| 424 target_->output_type() == Target::SHARED_LIBRARY); |
| 425 |
| 426 if (dep->output_type() == Target::SOURCE_SET) { |
| 427 if (target_->output_type() == Target::SOURCE_SET) { |
| 428 // When a source set depends on another source set, add it as a data |
| 429 // dependency so if the user says "ninja second_source_set" it will |
| 430 // also compile the first (what you would expect) even though we'll |
| 431 // never do anything with the first one's files. |
| 432 non_linkable_deps->push_back(dep); |
| 433 } else { |
| 434 // Linking in a source set, copy its object files. |
| 435 for (size_t i = 0; i < dep->sources().size(); i++) { |
| 436 SourceFileType input_file_type = GetSourceFileType( |
| 437 dep->sources()[i], dep->settings()->target_os()); |
| 438 if (input_file_type != SOURCE_UNKNOWN && |
| 439 input_file_type != SOURCE_H) { |
| 440 // Note we need to specify the target as the source_set target |
| 441 // itself, since this is used to prefix the object file name. |
| 442 extra_object_files->insert(helper_.GetOutputFileForSource( |
| 443 dep, dep->sources()[i], input_file_type)); |
| 444 } |
| 445 } |
| 446 } |
| 447 } else if (can_link_libs && dep->IsLinkable()) { |
| 448 linkable_deps->push_back(dep); |
| 449 } else { |
| 450 non_linkable_deps->push_back(dep); |
| 451 } |
| 452 } |
| 453 |
| 454 void NinjaBinaryTargetWriter::WriteImplicitDependencies( |
| 455 const std::vector<const Target*>& non_linkable_deps) { |
361 const std::vector<SourceFile>& data = target_->data(); | 456 const std::vector<SourceFile>& data = target_->data(); |
362 if (!extra_data_deps.empty() || !datadeps.empty() || !data.empty()) { | 457 if (!non_linkable_deps.empty() || !data.empty()) { |
363 out_ << " ||"; | 458 out_ << " ||"; |
364 | 459 |
365 // Non-linkable deps in the deps section above. | 460 // Non-linkable targets. |
366 for (size_t i = 0; i < extra_data_deps.size(); i++) { | 461 for (size_t i = 0; i < non_linkable_deps.size(); i++) { |
367 out_ << " "; | 462 out_ << " "; |
368 path_output_.WriteFile(out_, | 463 path_output_.WriteFile(out_, |
369 helper_.GetTargetOutputFile(extra_data_deps[i])); | 464 helper_.GetTargetOutputFile(non_linkable_deps[i])); |
370 } | |
371 | |
372 // Data deps. | |
373 for (size_t i = 0; i < datadeps.size(); i++) { | |
374 out_ << " "; | |
375 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(datadeps[i])); | |
376 } | 465 } |
377 | 466 |
378 // Data files. | 467 // Data files. |
379 const std::vector<SourceFile>& data = target_->data(); | 468 const std::vector<SourceFile>& data = target_->data(); |
380 for (size_t i = 0; i < data.size(); i++) { | 469 for (size_t i = 0; i < data.size(); i++) { |
381 out_ << " "; | 470 out_ << " "; |
382 path_output_.WriteFile(out_, data[i]); | 471 path_output_.WriteFile(out_, data[i]); |
383 } | 472 } |
384 } | 473 } |
385 | |
386 out_ << std::endl; | |
387 } | 474 } |
OLD | NEW |