Material throbber: use in tabstrip
[chromium-blink-merge.git] / tools / gn / target.cc
blob40c8a21e2adf743d0b0de24edcfee564f6559b3e
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.
5 #include "tools/gn/target.h"
7 #include "base/bind.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "tools/gn/config_values_extractors.h"
11 #include "tools/gn/deps_iterator.h"
12 #include "tools/gn/filesystem_utils.h"
13 #include "tools/gn/scheduler.h"
14 #include "tools/gn/substitution_writer.h"
16 namespace {
18 typedef std::set<const Config*> ConfigSet;
20 // Merges the public configs from the given target to the given config list.
21 void MergePublicConfigsFrom(const Target* from_target,
22 UniqueVector<LabelConfigPair>* dest) {
23 const UniqueVector<LabelConfigPair>& pub = from_target->public_configs();
24 dest->Append(pub.begin(), pub.end());
27 // Like MergePublicConfigsFrom above except does the "all dependent" ones. This
28 // additionally adds all configs to the all_dependent_configs_ of the dest
29 // target given in *all_dest.
30 void MergeAllDependentConfigsFrom(const Target* from_target,
31 UniqueVector<LabelConfigPair>* dest,
32 UniqueVector<LabelConfigPair>* all_dest) {
33 for (const auto& pair : from_target->all_dependent_configs()) {
34 all_dest->push_back(pair);
35 dest->push_back(pair);
39 Err MakeTestOnlyError(const Target* from, const Target* to) {
40 return Err(from->defined_from(), "Test-only dependency not allowed.",
41 from->label().GetUserVisibleName(false) + "\n"
42 "which is NOT marked testonly can't depend on\n" +
43 to->label().GetUserVisibleName(false) + "\n"
44 "which is marked testonly. Only targets with \"testonly = true\"\n"
45 "can depend on other test-only targets.\n"
46 "\n"
47 "Either mark it test-only or don't do this dependency.");
50 Err MakeStaticLibDepsError(const Target* from, const Target* to) {
51 return Err(from->defined_from(),
52 "Complete static libraries can't depend on static libraries.",
53 from->label().GetUserVisibleName(false) +
54 "\n"
55 "which is a complete static library can't depend on\n" +
56 to->label().GetUserVisibleName(false) +
57 "\n"
58 "which is a static library.\n"
59 "\n"
60 "Use source sets for intermediate targets instead.");
63 } // namespace
65 Target::Target(const Settings* settings, const Label& label)
66 : Item(settings, label),
67 output_type_(UNKNOWN),
68 all_headers_public_(true),
69 check_includes_(true),
70 complete_static_lib_(false),
71 testonly_(false),
72 toolchain_(nullptr) {
75 Target::~Target() {
78 // static
79 const char* Target::GetStringForOutputType(OutputType type) {
80 switch (type) {
81 case UNKNOWN:
82 return "Unknown";
83 case GROUP:
84 return "Group";
85 case EXECUTABLE:
86 return "Executable";
87 case SHARED_LIBRARY:
88 return "Shared library";
89 case STATIC_LIBRARY:
90 return "Static library";
91 case SOURCE_SET:
92 return "Source set";
93 case COPY_FILES:
94 return "Copy";
95 case ACTION:
96 return "Action";
97 case ACTION_FOREACH:
98 return "ActionForEach";
99 default:
100 return "";
104 Target* Target::AsTarget() {
105 return this;
108 const Target* Target::AsTarget() const {
109 return this;
112 bool Target::OnResolved(Err* err) {
113 DCHECK(output_type_ != UNKNOWN);
114 DCHECK(toolchain_) << "Toolchain should have been set before resolving.";
116 // Copy our own dependent configs to the list of configs applying to us.
117 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end());
118 MergePublicConfigsFrom(this, &configs_);
120 // Copy our own libs and lib_dirs to the final set. This will be from our
121 // target and all of our configs. We do this specially since these must be
122 // inherited through the dependency tree (other flags don't work this way).
123 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) {
124 const ConfigValues& cur = iter.cur();
125 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end());
126 all_libs_.append(cur.libs().begin(), cur.libs().end());
129 PullDependentTargets();
130 PullForwardedDependentConfigs();
131 PullRecursiveHardDeps();
133 FillOutputFiles();
135 if (!CheckVisibility(err))
136 return false;
137 if (!CheckTestonly(err))
138 return false;
139 if (!CheckNoNestedStaticLibs(err))
140 return false;
142 return true;
145 bool Target::IsLinkable() const {
146 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY;
149 bool Target::IsFinal() const {
150 return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY ||
151 (output_type_ == STATIC_LIBRARY && complete_static_lib_);
154 DepsIteratorRange Target::GetDeps(DepsIterationType type) const {
155 if (type == DEPS_LINKED) {
156 return DepsIteratorRange(DepsIterator(
157 &public_deps_, &private_deps_, nullptr));
159 // All deps.
160 return DepsIteratorRange(DepsIterator(
161 &public_deps_, &private_deps_, &data_deps_));
164 std::string Target::GetComputedOutputName(bool include_prefix) const {
165 DCHECK(toolchain_)
166 << "Toolchain must be specified before getting the computed output name.";
168 const std::string& name = output_name_.empty() ? label().name()
169 : output_name_;
171 std::string result;
172 if (include_prefix) {
173 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
174 const std::string& prefix = tool->output_prefix();
175 // Only add the prefix if the name doesn't already have it.
176 if (!StartsWithASCII(name, prefix, true))
177 result = prefix;
180 result.append(name);
181 return result;
184 bool Target::SetToolchain(const Toolchain* toolchain, Err* err) {
185 DCHECK(!toolchain_);
186 DCHECK_NE(UNKNOWN, output_type_);
187 toolchain_ = toolchain;
189 const Tool* tool = toolchain->GetToolForTargetFinalOutput(this);
190 if (tool)
191 return true;
193 // Tool not specified for this target type.
194 if (err) {
195 *err = Err(defined_from(), "This target uses an undefined tool.",
196 base::StringPrintf(
197 "The target %s\n"
198 "of type \"%s\"\n"
199 "uses toolchain %s\n"
200 "which doesn't have the tool \"%s\" defined.\n\n"
201 "Alas, I can not continue.",
202 label().GetUserVisibleName(false).c_str(),
203 GetStringForOutputType(output_type_),
204 label().GetToolchainLabel().GetUserVisibleName(false).c_str(),
205 Toolchain::ToolTypeToName(
206 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str()));
208 return false;
211 void Target::PullDependentTarget(const Target* dep, bool is_public) {
212 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_);
213 MergePublicConfigsFrom(dep, &configs_);
215 // Direct dependent libraries.
216 if (dep->output_type() == STATIC_LIBRARY ||
217 dep->output_type() == SHARED_LIBRARY ||
218 dep->output_type() == SOURCE_SET)
219 inherited_libraries_.Append(dep, is_public);
221 if (dep->output_type() == SHARED_LIBRARY) {
222 // Shared library dependendencies are inherited across public shared
223 // library boundaries.
225 // In this case:
226 // EXE -> INTERMEDIATE_SHLIB --[public]--> FINAL_SHLIB
227 // The EXE will also link to to FINAL_SHLIB. The public dependeny means
228 // that the EXE can use the headers in FINAL_SHLIB so the FINAL_SHLIB
229 // will need to appear on EXE's link line.
231 // However, if the dependency is private:
232 // EXE -> INTERMEDIATE_SHLIB --[private]--> FINAL_SHLIB
233 // the dependency will not be propogated because INTERMEDIATE_SHLIB is
234 // not granting permission to call functiosn from FINAL_SHLIB. If EXE
235 // wants to use functions (and link to) FINAL_SHLIB, it will need to do
236 // so explicitly.
238 // Static libraries and source sets aren't inherited across shared
239 // library boundaries because they will be linked into the shared
240 // library.
241 inherited_libraries_.AppendPublicSharedLibraries(
242 dep->inherited_libraries(), is_public);
243 } else if (!dep->IsFinal()) {
244 // The current target isn't linked, so propogate linked deps and
245 // libraries up the dependency tree.
246 inherited_libraries_.AppendInherited(dep->inherited_libraries(), is_public);
248 // Inherited library settings.
249 all_lib_dirs_.append(dep->all_lib_dirs());
250 all_libs_.append(dep->all_libs());
254 void Target::PullDependentTargets() {
255 for (const auto& dep : public_deps_)
256 PullDependentTarget(dep.ptr, true);
257 for (const auto& dep : private_deps_)
258 PullDependentTarget(dep.ptr, false);
261 void Target::PullForwardedDependentConfigs() {
262 // Pull public configs from each of our dependency's public deps.
263 for (const auto& dep : public_deps_)
264 PullForwardedDependentConfigsFrom(dep.ptr);
266 // Forward public configs if explicitly requested.
267 for (const auto& dep : forward_dependent_configs_) {
268 const Target* from_target = dep.ptr;
270 // The forward_dependent_configs_ must be in the deps (public or private)
271 // already, so we don't need to bother copying to our configs, only
272 // forwarding.
273 DCHECK(std::find_if(private_deps_.begin(), private_deps_.end(),
274 LabelPtrPtrEquals<Target>(from_target)) !=
275 private_deps_.end() ||
276 std::find_if(public_deps_.begin(), public_deps_.end(),
277 LabelPtrPtrEquals<Target>(from_target)) !=
278 public_deps_.end());
280 PullForwardedDependentConfigsFrom(from_target);
284 void Target::PullForwardedDependentConfigsFrom(const Target* from) {
285 public_configs_.Append(from->public_configs().begin(),
286 from->public_configs().end());
289 void Target::PullRecursiveHardDeps() {
290 for (const auto& pair : GetDeps(DEPS_LINKED)) {
291 if (pair.ptr->hard_dep())
292 recursive_hard_deps_.insert(pair.ptr);
294 // Android STL doesn't like insert(begin, end) so do it manually.
295 // TODO(brettw) this can be changed to
296 // insert(iter.target()->begin(), iter.target()->end())
297 // when Android uses a better STL.
298 for (std::set<const Target*>::const_iterator cur =
299 pair.ptr->recursive_hard_deps().begin();
300 cur != pair.ptr->recursive_hard_deps().end(); ++cur)
301 recursive_hard_deps_.insert(*cur);
305 void Target::FillOutputFiles() {
306 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
307 switch (output_type_) {
308 case GROUP:
309 case SOURCE_SET:
310 case COPY_FILES:
311 case ACTION:
312 case ACTION_FOREACH: {
313 // These don't get linked to and use stamps which should be the first
314 // entry in the outputs. These stamps are named
315 // "<target_out_dir>/<targetname>.stamp".
316 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this);
317 dependency_output_file_.value().append(GetComputedOutputName(true));
318 dependency_output_file_.value().append(".stamp");
319 break;
321 case EXECUTABLE:
322 // Executables don't get linked to, but the first output is used for
323 // dependency management.
324 CHECK_GE(tool->outputs().list().size(), 1u);
325 dependency_output_file_ =
326 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
327 this, tool, tool->outputs().list()[0]);
328 break;
329 case STATIC_LIBRARY:
330 // Static libraries both have dependencies and linking going off of the
331 // first output.
332 CHECK(tool->outputs().list().size() >= 1);
333 link_output_file_ = dependency_output_file_ =
334 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
335 this, tool, tool->outputs().list()[0]);
336 break;
337 case SHARED_LIBRARY:
338 CHECK(tool->outputs().list().size() >= 1);
339 if (tool->link_output().empty() && tool->depend_output().empty()) {
340 // Default behavior, use the first output file for both.
341 link_output_file_ = dependency_output_file_ =
342 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
343 this, tool, tool->outputs().list()[0]);
344 } else {
345 // Use the tool-specified ones.
346 if (!tool->link_output().empty()) {
347 link_output_file_ =
348 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
349 this, tool, tool->link_output());
351 if (!tool->depend_output().empty()) {
352 dependency_output_file_ =
353 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
354 this, tool, tool->depend_output());
357 break;
358 case UNKNOWN:
359 default:
360 NOTREACHED();
364 bool Target::CheckVisibility(Err* err) const {
365 for (const auto& pair : GetDeps(DEPS_ALL)) {
366 if (!Visibility::CheckItemVisibility(this, pair.ptr, err))
367 return false;
369 return true;
372 bool Target::CheckTestonly(Err* err) const {
373 // If the current target is marked testonly, it can include both testonly
374 // and non-testonly targets, so there's nothing to check.
375 if (testonly())
376 return true;
378 // Verify no deps have "testonly" set.
379 for (const auto& pair : GetDeps(DEPS_ALL)) {
380 if (pair.ptr->testonly()) {
381 *err = MakeTestOnlyError(this, pair.ptr);
382 return false;
386 return true;
389 bool Target::CheckNoNestedStaticLibs(Err* err) const {
390 // If the current target is not a complete static library, it can depend on
391 // static library targets with no problem.
392 if (!(output_type() == Target::STATIC_LIBRARY && complete_static_lib()))
393 return true;
395 // Verify no deps are static libraries.
396 for (const auto& pair : GetDeps(DEPS_ALL)) {
397 if (pair.ptr->output_type() == Target::STATIC_LIBRARY) {
398 *err = MakeStaticLibDepsError(this, pair.ptr);
399 return false;
403 // Verify no inherited libraries are static libraries.
404 for (const auto& lib : inherited_libraries().GetOrdered()) {
405 if (lib->output_type() == Target::STATIC_LIBRARY) {
406 *err = MakeStaticLibDepsError(this, lib);
407 return false;
410 return true;