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 |