Chromium Code Reviews| 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/target.h" | 5 #include "tools/gn/target.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/strings/string_util.h" | |
| 8 #include "tools/gn/config_values_extractors.h" | 9 #include "tools/gn/config_values_extractors.h" |
| 10 #include "tools/gn/filesystem_utils.h" | |
| 9 #include "tools/gn/scheduler.h" | 11 #include "tools/gn/scheduler.h" |
| 12 #include "tools/gn/substitution_writer.h" | |
| 10 | 13 |
| 11 namespace { | 14 namespace { |
| 12 | 15 |
| 13 typedef std::set<const Config*> ConfigSet; | 16 typedef std::set<const Config*> ConfigSet; |
| 14 | 17 |
| 15 // Merges the dependent configs from the given target to the given config list. | 18 // Merges the dependent configs from the given target to the given config list. |
| 16 void MergeDirectDependentConfigsFrom(const Target* from_target, | 19 void MergeDirectDependentConfigsFrom(const Target* from_target, |
| 17 UniqueVector<LabelConfigPair>* dest) { | 20 UniqueVector<LabelConfigPair>* dest) { |
| 18 const UniqueVector<LabelConfigPair>& direct = | 21 const UniqueVector<LabelConfigPair>& direct = |
| 19 from_target->direct_dependent_configs(); | 22 from_target->direct_dependent_configs(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 34 dest->push_back(all[i]); | 37 dest->push_back(all[i]); |
| 35 } | 38 } |
| 36 } | 39 } |
| 37 | 40 |
| 38 } // namespace | 41 } // namespace |
| 39 | 42 |
| 40 Target::Target(const Settings* settings, const Label& label) | 43 Target::Target(const Settings* settings, const Label& label) |
| 41 : Item(settings, label), | 44 : Item(settings, label), |
| 42 output_type_(UNKNOWN), | 45 output_type_(UNKNOWN), |
| 43 all_headers_public_(true), | 46 all_headers_public_(true), |
| 44 hard_dep_(false) { | 47 hard_dep_(false), |
| 48 toolchain_(NULL) { | |
| 45 } | 49 } |
| 46 | 50 |
| 47 Target::~Target() { | 51 Target::~Target() { |
| 48 } | 52 } |
| 49 | 53 |
| 50 // static | 54 // static |
| 51 const char* Target::GetStringForOutputType(OutputType type) { | 55 const char* Target::GetStringForOutputType(OutputType type) { |
| 52 switch (type) { | 56 switch (type) { |
| 53 case UNKNOWN: | 57 case UNKNOWN: |
| 54 return "Unknown"; | 58 return "Unknown"; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 76 Target* Target::AsTarget() { | 80 Target* Target::AsTarget() { |
| 77 return this; | 81 return this; |
| 78 } | 82 } |
| 79 | 83 |
| 80 const Target* Target::AsTarget() const { | 84 const Target* Target::AsTarget() const { |
| 81 return this; | 85 return this; |
| 82 } | 86 } |
| 83 | 87 |
| 84 void Target::OnResolved() { | 88 void Target::OnResolved() { |
| 85 DCHECK(output_type_ != UNKNOWN); | 89 DCHECK(output_type_ != UNKNOWN); |
| 90 DCHECK(toolchain_) << "Toolchain should have been set before resolving."; | |
| 86 | 91 |
| 87 // Convert any groups we depend on to just direct dependencies on that | 92 // Convert any groups we depend on to just direct dependencies on that |
| 88 // group's deps. We insert the new deps immediately after the group so that | 93 // group's deps. We insert the new deps immediately after the group so that |
| 89 // the ordering is preserved. We need to keep the original group so that any | 94 // the ordering is preserved. We need to keep the original group so that any |
| 90 // flags, etc. that it specifies itself are applied to us. | 95 // flags, etc. that it specifies itself are applied to us. |
| 91 for (size_t i = 0; i < deps_.size(); i++) { | 96 for (size_t i = 0; i < deps_.size(); i++) { |
| 92 const Target* dep = deps_[i].ptr; | 97 const Target* dep = deps_[i].ptr; |
| 93 if (dep->output_type_ == GROUP) { | 98 if (dep->output_type_ == GROUP) { |
| 99 // TODO(brettw) bug 403488 this should also handle datadeps. | |
| 94 deps_.insert(deps_.begin() + i + 1, dep->deps_.begin(), dep->deps_.end()); | 100 deps_.insert(deps_.begin() + i + 1, dep->deps_.begin(), dep->deps_.end()); |
| 95 i += dep->deps_.size(); | 101 i += dep->deps_.size(); |
| 96 } | 102 } |
| 97 } | 103 } |
| 98 | 104 |
| 99 // Copy our own dependent configs to the list of configs applying to us. | 105 // Copy our own dependent configs to the list of configs applying to us. |
| 100 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end()); | 106 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end()); |
| 101 configs_.Append(direct_dependent_configs_.begin(), | 107 configs_.Append(direct_dependent_configs_.begin(), |
| 102 direct_dependent_configs_.end()); | 108 direct_dependent_configs_.end()); |
| 103 | 109 |
| 104 // Copy our own libs and lib_dirs to the final set. This will be from our | 110 // Copy our own libs and lib_dirs to the final set. This will be from our |
| 105 // target and all of our configs. We do this specially since these must be | 111 // target and all of our configs. We do this specially since these must be |
| 106 // inherited through the dependency tree (other flags don't work this way). | 112 // inherited through the dependency tree (other flags don't work this way). |
| 107 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { | 113 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { |
| 108 const ConfigValues& cur = iter.cur(); | 114 const ConfigValues& cur = iter.cur(); |
| 109 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); | 115 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); |
| 110 all_libs_.append(cur.libs().begin(), cur.libs().end()); | 116 all_libs_.append(cur.libs().begin(), cur.libs().end()); |
| 111 } | 117 } |
| 112 | 118 |
| 113 if (output_type_ != GROUP) { | 119 if (output_type_ != GROUP) { |
| 114 // Don't pull target info like libraries and configs from dependencies into | 120 // Don't pull target info like libraries and configs from dependencies into |
| 115 // a group target. When A depends on a group G, the G's dependents will | 121 // a group target. When A depends on a group G, the G's dependents will |
| 116 // be treated as direct dependencies of A, so this is unnecessary and will | 122 // be treated as direct dependencies of A, so this is unnecessary and will |
| 117 // actually result in duplicated settings (since settings will also be | 123 // actually result in duplicated settings (since settings will also be |
| 118 // pulled from G to A in case G has configs directly on it). | 124 // pulled from G to A in case G has configs directly on it). |
| 119 PullDependentTargetInfo(); | 125 PullDependentTargetInfo(); |
| 120 } | 126 } |
| 121 PullForwardedDependentConfigs(); | 127 PullForwardedDependentConfigs(); |
| 122 PullRecursiveHardDeps(); | 128 PullRecursiveHardDeps(); |
| 129 | |
| 130 FillOutputFiles(); | |
| 123 } | 131 } |
| 124 | 132 |
| 125 bool Target::IsLinkable() const { | 133 bool Target::IsLinkable() const { |
| 126 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; | 134 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
| 127 } | 135 } |
| 128 | 136 |
| 137 std::string Target::GetComputedOutputName(bool include_prefix) const { | |
| 138 DCHECK(toolchain_) | |
| 139 << "Toolchain must be specified before getting the computed output name."; | |
| 140 | |
| 141 const std::string& name = output_name_.empty() ? label().name() | |
| 142 : output_name_; | |
| 143 | |
| 144 std::string result; | |
| 145 if (include_prefix) { | |
| 146 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); | |
| 147 const std::string& prefix = tool->output_prefix(); | |
| 148 // Only add the prefix if the name doesn't already have it. | |
| 149 if (!StartsWithASCII(name, prefix, true)) | |
| 150 result = prefix; | |
| 151 } | |
| 152 | |
| 153 result.append(name); | |
| 154 return result; | |
| 155 } | |
| 156 | |
| 157 bool Target::SetToolchain(const Toolchain* toolchain, Err* err) { | |
| 158 DCHECK(!toolchain_); | |
| 159 DCHECK(output_type_ != UNKNOWN); | |
|
jamesr
2014/08/19 19:30:42
DCHECK_NE will give better output on failure
| |
| 160 toolchain_ = toolchain; | |
| 161 | |
| 162 const Tool* tool = toolchain->GetToolForTargetFinalOutput(this); | |
| 163 if (tool) | |
| 164 return true; | |
| 165 | |
| 166 // Tool not specified for this target type. | |
| 167 if (err) { | |
| 168 *err = Err(defined_from(), "This target uses an undefined tool.", | |
| 169 "The target " + label().GetUserVisibleName(false) + | |
|
jamesr
2014/08/19 19:30:42
this could use some stringprintf, imo. it's really
| |
| 170 "\nof type \"" + GetStringForOutputType(output_type_) + | |
| 171 "\"\nuses toolchain " + | |
| 172 label().GetToolchainLabel().GetUserVisibleName(false) + | |
| 173 "\nwhich doesn't have the tool \"" + | |
| 174 Toolchain::ToolTypeToName( | |
| 175 toolchain->GetToolTypeForTargetFinalOutput(this)) + | |
| 176 "\" defined.\n\nAlas, I can not continue."); | |
| 177 } | |
| 178 return false; | |
| 179 } | |
| 180 | |
| 129 void Target::PullDependentTargetInfo() { | 181 void Target::PullDependentTargetInfo() { |
| 130 // Gather info from our dependents we need. | 182 // Gather info from our dependents we need. |
| 131 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) { | 183 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) { |
| 132 const Target* dep = deps_[dep_i].ptr; | 184 const Target* dep = deps_[dep_i].ptr; |
| 133 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); | 185 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); |
| 134 MergeDirectDependentConfigsFrom(dep, &configs_); | 186 MergeDirectDependentConfigsFrom(dep, &configs_); |
| 135 | 187 |
| 136 // Direct dependent libraries. | 188 // Direct dependent libraries. |
| 137 if (dep->output_type() == STATIC_LIBRARY || | 189 if (dep->output_type() == STATIC_LIBRARY || |
| 138 dep->output_type() == SHARED_LIBRARY || | 190 dep->output_type() == SHARED_LIBRARY || |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 183 | 235 |
| 184 // Android STL doesn't like insert(begin, end) so do it manually. | 236 // Android STL doesn't like insert(begin, end) so do it manually. |
| 185 // TODO(brettw) this can be changed to insert(dep->begin(), dep->end()) when | 237 // TODO(brettw) this can be changed to insert(dep->begin(), dep->end()) when |
| 186 // Android uses a better STL. | 238 // Android uses a better STL. |
| 187 for (std::set<const Target*>::const_iterator cur = | 239 for (std::set<const Target*>::const_iterator cur = |
| 188 dep->recursive_hard_deps().begin(); | 240 dep->recursive_hard_deps().begin(); |
| 189 cur != dep->recursive_hard_deps().end(); ++cur) | 241 cur != dep->recursive_hard_deps().end(); ++cur) |
| 190 recursive_hard_deps_.insert(*cur); | 242 recursive_hard_deps_.insert(*cur); |
| 191 } | 243 } |
| 192 } | 244 } |
| 245 | |
| 246 void Target::FillOutputFiles() { | |
| 247 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); | |
| 248 switch (output_type_) { | |
| 249 case GROUP: | |
| 250 case SOURCE_SET: | |
| 251 case COPY_FILES: | |
| 252 case ACTION: | |
| 253 case ACTION_FOREACH: { | |
| 254 // These don't get linked to and use stamps which should be the first | |
| 255 // entry in the outputs. These stamps are named | |
| 256 // "<target_out_dir>/<targetname>.stamp". | |
| 257 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this); | |
| 258 dependency_output_file_.value().append(GetComputedOutputName(true)); | |
| 259 dependency_output_file_.value().append(".stamp"); | |
| 260 break; | |
| 261 } | |
| 262 case EXECUTABLE: | |
| 263 // Executables don't get linked to, but the first output is used for | |
| 264 // dependency management. | |
| 265 CHECK(tool->outputs().list().size() >= 1); | |
|
jamesr
2014/08/19 19:30:42
CHECK_GE produces slightly better output on failur
| |
| 266 dependency_output_file_ = | |
| 267 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | |
| 268 this, tool, tool->outputs().list()[0]); | |
| 269 break; | |
| 270 case STATIC_LIBRARY: | |
| 271 // Static libraries both have dependencies and linking going off of the | |
| 272 // first output. | |
| 273 CHECK(tool->outputs().list().size() >= 1); | |
| 274 link_output_file_ = dependency_output_file_ = | |
| 275 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | |
| 276 this, tool, tool->outputs().list()[0]); | |
| 277 break; | |
| 278 case SHARED_LIBRARY: | |
| 279 CHECK(tool->outputs().list().size() >= 1); | |
| 280 if (tool->link_output().empty() && tool->depend_output().empty()) { | |
| 281 // Default behavior, use the first output file for both. | |
| 282 link_output_file_ = dependency_output_file_ = | |
| 283 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | |
| 284 this, tool, tool->outputs().list()[0]); | |
| 285 } else { | |
| 286 // Use the tool-specified ones. | |
| 287 if (!tool->link_output().empty()) { | |
| 288 link_output_file_ = | |
| 289 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | |
| 290 this, tool, tool->link_output()); | |
| 291 } | |
| 292 if (!tool->depend_output().empty()) { | |
| 293 dependency_output_file_ = | |
| 294 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | |
| 295 this, tool, tool->link_output()); | |
| 296 } | |
| 297 } | |
| 298 break; | |
| 299 case UNKNOWN: | |
| 300 default: | |
| 301 NOTREACHED(); | |
| 302 } | |
| 303 } | |
| OLD | NEW |