Index: tools/gn/target.cc |
diff --git a/tools/gn/target.cc b/tools/gn/target.cc |
index 1983374cf998084bc1a69c03066a86efe1f4da74..f5bdd585cd09bdd5c97c28f4313b1c9e6c4f1985 100644 |
--- a/tools/gn/target.cc |
+++ b/tools/gn/target.cc |
@@ -5,8 +5,12 @@ |
#include "tools/gn/target.h" |
#include "base/bind.h" |
+#include "base/strings/string_util.h" |
+#include "base/strings/stringprintf.h" |
#include "tools/gn/config_values_extractors.h" |
+#include "tools/gn/filesystem_utils.h" |
#include "tools/gn/scheduler.h" |
+#include "tools/gn/substitution_writer.h" |
namespace { |
@@ -41,7 +45,8 @@ Target::Target(const Settings* settings, const Label& label) |
: Item(settings, label), |
output_type_(UNKNOWN), |
all_headers_public_(true), |
- hard_dep_(false) { |
+ hard_dep_(false), |
+ toolchain_(NULL) { |
} |
Target::~Target() { |
@@ -83,6 +88,7 @@ const Target* Target::AsTarget() const { |
void Target::OnResolved() { |
DCHECK(output_type_ != UNKNOWN); |
+ DCHECK(toolchain_) << "Toolchain should have been set before resolving."; |
// Convert any groups we depend on to just direct dependencies on that |
// group's deps. We insert the new deps immediately after the group so that |
@@ -91,6 +97,7 @@ void Target::OnResolved() { |
for (size_t i = 0; i < deps_.size(); i++) { |
const Target* dep = deps_[i].ptr; |
if (dep->output_type_ == GROUP) { |
+ // TODO(brettw) bug 403488 this should also handle datadeps. |
deps_.insert(deps_.begin() + i + 1, dep->deps_.begin(), dep->deps_.end()); |
i += dep->deps_.size(); |
} |
@@ -120,12 +127,61 @@ void Target::OnResolved() { |
} |
PullForwardedDependentConfigs(); |
PullRecursiveHardDeps(); |
+ |
+ FillOutputFiles(); |
} |
bool Target::IsLinkable() const { |
return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
} |
+std::string Target::GetComputedOutputName(bool include_prefix) const { |
+ DCHECK(toolchain_) |
+ << "Toolchain must be specified before getting the computed output name."; |
+ |
+ const std::string& name = output_name_.empty() ? label().name() |
+ : output_name_; |
+ |
+ std::string result; |
+ if (include_prefix) { |
+ const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); |
+ const std::string& prefix = tool->output_prefix(); |
+ // Only add the prefix if the name doesn't already have it. |
+ if (!StartsWithASCII(name, prefix, true)) |
+ result = prefix; |
+ } |
+ |
+ result.append(name); |
+ return result; |
+} |
+ |
+bool Target::SetToolchain(const Toolchain* toolchain, Err* err) { |
+ DCHECK(!toolchain_); |
+ DCHECK_NE(UNKNOWN, output_type_); |
+ toolchain_ = toolchain; |
+ |
+ const Tool* tool = toolchain->GetToolForTargetFinalOutput(this); |
+ if (tool) |
+ return true; |
+ |
+ // Tool not specified for this target type. |
+ if (err) { |
+ *err = Err(defined_from(), "This target uses an undefined tool.", |
+ base::StringPrintf( |
+ "The target %s\n" |
+ "of type \"%s\"\n" |
+ "uses toolchain %s\n" |
+ "which doesn't have the tool \"%s\" defined.\n\n" |
+ "Alas, I can not continue.", |
+ label().GetUserVisibleName(false).c_str(), |
+ GetStringForOutputType(output_type_), |
+ label().GetToolchainLabel().GetUserVisibleName(false).c_str(), |
+ Toolchain::ToolTypeToName( |
+ toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); |
+ } |
+ return false; |
+} |
+ |
void Target::PullDependentTargetInfo() { |
// Gather info from our dependents we need. |
for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) { |
@@ -190,3 +246,62 @@ void Target::PullRecursiveHardDeps() { |
recursive_hard_deps_.insert(*cur); |
} |
} |
+ |
+void Target::FillOutputFiles() { |
+ const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); |
+ switch (output_type_) { |
+ case GROUP: |
+ case SOURCE_SET: |
+ case COPY_FILES: |
+ case ACTION: |
+ case ACTION_FOREACH: { |
+ // These don't get linked to and use stamps which should be the first |
+ // entry in the outputs. These stamps are named |
+ // "<target_out_dir>/<targetname>.stamp". |
+ dependency_output_file_ = GetTargetOutputDirAsOutputFile(this); |
+ dependency_output_file_.value().append(GetComputedOutputName(true)); |
+ dependency_output_file_.value().append(".stamp"); |
+ break; |
+ } |
+ case EXECUTABLE: |
+ // Executables don't get linked to, but the first output is used for |
+ // dependency management. |
+ CHECK_GE(tool->outputs().list().size(), 1u); |
+ dependency_output_file_ = |
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
+ this, tool, tool->outputs().list()[0]); |
+ break; |
+ case STATIC_LIBRARY: |
+ // Static libraries both have dependencies and linking going off of the |
+ // first output. |
+ CHECK(tool->outputs().list().size() >= 1); |
+ link_output_file_ = dependency_output_file_ = |
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
+ this, tool, tool->outputs().list()[0]); |
+ break; |
+ case SHARED_LIBRARY: |
+ CHECK(tool->outputs().list().size() >= 1); |
+ if (tool->link_output().empty() && tool->depend_output().empty()) { |
+ // Default behavior, use the first output file for both. |
+ link_output_file_ = dependency_output_file_ = |
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
+ this, tool, tool->outputs().list()[0]); |
+ } else { |
+ // Use the tool-specified ones. |
+ if (!tool->link_output().empty()) { |
+ link_output_file_ = |
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
+ this, tool, tool->link_output()); |
+ } |
+ if (!tool->depend_output().empty()) { |
+ dependency_output_file_ = |
+ SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
+ this, tool, tool->link_output()); |
+ } |
+ } |
+ break; |
+ case UNKNOWN: |
+ default: |
+ NOTREACHED(); |
+ } |
+} |