GN: Add notion of 'complete' static libraries, akin to GYP.
[chromium-blink-merge.git] / tools / gn / target.cc
blobba1e4b780610c995e49be094804a1d665c20290c
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/filesystem_utils.h"
12 #include "tools/gn/scheduler.h"
13 #include "tools/gn/substitution_writer.h"
15 namespace {
17 typedef std::set<const Config*> ConfigSet;
19 // Merges the dependent configs from the given target to the given config list.
20 void MergeDirectDependentConfigsFrom(const Target* from_target,
21 UniqueVector<LabelConfigPair>* dest) {
22 const UniqueVector<LabelConfigPair>& direct =
23 from_target->direct_dependent_configs();
24 for (size_t i = 0; i < direct.size(); i++)
25 dest->push_back(direct[i]);
28 // Like MergeDirectDependentConfigsFrom above except does the "all dependent"
29 // ones. This additionally adds all configs to the all_dependent_configs_ of
30 // the dest target given in *all_dest.
31 void MergeAllDependentConfigsFrom(const Target* from_target,
32 UniqueVector<LabelConfigPair>* dest,
33 UniqueVector<LabelConfigPair>* all_dest) {
34 const UniqueVector<LabelConfigPair>& all =
35 from_target->all_dependent_configs();
36 for (size_t i = 0; i < all.size(); i++) {
37 all_dest->push_back(all[i]);
38 dest->push_back(all[i]);
42 Err MakeTestOnlyError(const Target* from, const Target* to) {
43 return Err(from->defined_from(), "Test-only dependency not allowed.",
44 from->label().GetUserVisibleName(false) + "\n"
45 "which is NOT marked testonly can't depend on\n" +
46 to->label().GetUserVisibleName(false) + "\n"
47 "which is marked testonly. Only targets with \"testonly = true\"\n"
48 "can depend on other test-only targets.\n"
49 "\n"
50 "Either mark it test-only or don't do this dependency.");
53 // Inserts the given groups dependencies, starting at the given index of the
54 // given vector. Returns the number of items inserted.
55 size_t InsertGroupDeps(LabelTargetVector* vector,
56 size_t insert_at,
57 const Target* group) {
58 const LabelTargetVector& deps = group->deps();
59 vector->insert(vector->begin() + insert_at, deps.begin(), deps.end());
61 // Clear the origin of each of the insertions. This marks these dependencies
62 // as internally generated.
63 for (size_t i = insert_at; i < deps.size() + insert_at; i++)
64 (*vector)[i].origin = NULL;
66 return deps.size();
69 } // namespace
71 Target::Target(const Settings* settings, const Label& label)
72 : Item(settings, label),
73 output_type_(UNKNOWN),
74 all_headers_public_(true),
75 check_includes_(true),
76 complete_static_lib_(false),
77 testonly_(false),
78 hard_dep_(false),
79 toolchain_(NULL) {
82 Target::~Target() {
85 // static
86 const char* Target::GetStringForOutputType(OutputType type) {
87 switch (type) {
88 case UNKNOWN:
89 return "Unknown";
90 case GROUP:
91 return "Group";
92 case EXECUTABLE:
93 return "Executable";
94 case SHARED_LIBRARY:
95 return "Shared library";
96 case STATIC_LIBRARY:
97 return "Static library";
98 case SOURCE_SET:
99 return "Source set";
100 case COPY_FILES:
101 return "Copy";
102 case ACTION:
103 return "Action";
104 case ACTION_FOREACH:
105 return "ActionForEach";
106 default:
107 return "";
111 Target* Target::AsTarget() {
112 return this;
115 const Target* Target::AsTarget() const {
116 return this;
119 bool Target::OnResolved(Err* err) {
120 DCHECK(output_type_ != UNKNOWN);
121 DCHECK(toolchain_) << "Toolchain should have been set before resolving.";
123 ExpandGroups();
125 // Copy our own dependent configs to the list of configs applying to us.
126 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end());
127 configs_.Append(direct_dependent_configs_.begin(),
128 direct_dependent_configs_.end());
130 // Copy our own libs and lib_dirs to the final set. This will be from our
131 // target and all of our configs. We do this specially since these must be
132 // inherited through the dependency tree (other flags don't work this way).
133 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) {
134 const ConfigValues& cur = iter.cur();
135 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end());
136 all_libs_.append(cur.libs().begin(), cur.libs().end());
139 if (output_type_ != GROUP) {
140 // Don't pull target info like libraries and configs from dependencies into
141 // a group target. When A depends on a group G, the G's dependents will
142 // be treated as direct dependencies of A, so this is unnecessary and will
143 // actually result in duplicated settings (since settings will also be
144 // pulled from G to A in case G has configs directly on it).
145 PullDependentTargetInfo();
147 PullForwardedDependentConfigs();
148 PullRecursiveHardDeps();
150 FillOutputFiles();
152 if (!CheckVisibility(err))
153 return false;
154 if (!CheckTestonly(err))
155 return false;
157 return true;
160 bool Target::IsLinkable() const {
161 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY;
164 bool Target::IsFinal() const {
165 return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY ||
166 (output_type_ == STATIC_LIBRARY && complete_static_lib_);
169 std::string Target::GetComputedOutputName(bool include_prefix) const {
170 DCHECK(toolchain_)
171 << "Toolchain must be specified before getting the computed output name.";
173 const std::string& name = output_name_.empty() ? label().name()
174 : output_name_;
176 std::string result;
177 if (include_prefix) {
178 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
179 const std::string& prefix = tool->output_prefix();
180 // Only add the prefix if the name doesn't already have it.
181 if (!StartsWithASCII(name, prefix, true))
182 result = prefix;
185 result.append(name);
186 return result;
189 bool Target::SetToolchain(const Toolchain* toolchain, Err* err) {
190 DCHECK(!toolchain_);
191 DCHECK_NE(UNKNOWN, output_type_);
192 toolchain_ = toolchain;
194 const Tool* tool = toolchain->GetToolForTargetFinalOutput(this);
195 if (tool)
196 return true;
198 // Tool not specified for this target type.
199 if (err) {
200 *err = Err(defined_from(), "This target uses an undefined tool.",
201 base::StringPrintf(
202 "The target %s\n"
203 "of type \"%s\"\n"
204 "uses toolchain %s\n"
205 "which doesn't have the tool \"%s\" defined.\n\n"
206 "Alas, I can not continue.",
207 label().GetUserVisibleName(false).c_str(),
208 GetStringForOutputType(output_type_),
209 label().GetToolchainLabel().GetUserVisibleName(false).c_str(),
210 Toolchain::ToolTypeToName(
211 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str()));
213 return false;
216 void Target::ExpandGroups() {
217 // Convert any groups we depend on to just direct dependencies on that
218 // group's deps. We insert the new deps immediately after the group so that
219 // the ordering is preserved. We need to keep the original group so that any
220 // flags, etc. that it specifies itself are applied to us.
221 // TODO(brettw) bug 403488 this should also handle datadeps.
222 for (size_t i = 0; i < deps_.size(); i++) {
223 const Target* dep = deps_[i].ptr;
224 if (dep->output_type_ == GROUP)
225 i += InsertGroupDeps(&deps_, i + 1, dep);
229 void Target::PullDependentTargetInfo() {
230 // Gather info from our dependents we need.
231 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) {
232 const Target* dep = deps_[dep_i].ptr;
233 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_);
234 MergeDirectDependentConfigsFrom(dep, &configs_);
236 // Direct dependent libraries.
237 if (dep->output_type() == STATIC_LIBRARY ||
238 dep->output_type() == SHARED_LIBRARY ||
239 dep->output_type() == SOURCE_SET)
240 inherited_libraries_.push_back(dep);
242 // Inherited libraries and flags are inherited across static library
243 // boundaries.
244 if (!dep->IsFinal()) {
245 inherited_libraries_.Append(dep->inherited_libraries().begin(),
246 dep->inherited_libraries().end());
248 // Inherited library settings.
249 all_lib_dirs_.append(dep->all_lib_dirs());
250 all_libs_.append(dep->all_libs());
255 void Target::PullForwardedDependentConfigs() {
256 // Groups implicitly forward all if its dependency's configs.
257 if (output_type() == GROUP) {
258 for (size_t i = 0; i < deps_.size(); i++)
259 forward_dependent_configs_.push_back(deps_[i]);
262 // Forward direct dependent configs if requested.
263 for (size_t dep = 0; dep < forward_dependent_configs_.size(); dep++) {
264 const Target* from_target = forward_dependent_configs_[dep].ptr;
266 // The forward_dependent_configs_ must be in the deps already, so we
267 // don't need to bother copying to our configs, only forwarding.
268 DCHECK(std::find_if(deps_.begin(), deps_.end(),
269 LabelPtrPtrEquals<Target>(from_target)) !=
270 deps_.end());
271 direct_dependent_configs_.Append(
272 from_target->direct_dependent_configs().begin(),
273 from_target->direct_dependent_configs().end());
277 void Target::PullRecursiveHardDeps() {
278 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) {
279 const Target* dep = deps_[dep_i].ptr;
280 if (dep->hard_dep())
281 recursive_hard_deps_.insert(dep);
283 // Android STL doesn't like insert(begin, end) so do it manually.
284 // TODO(brettw) this can be changed to insert(dep->begin(), dep->end()) when
285 // Android uses a better STL.
286 for (std::set<const Target*>::const_iterator cur =
287 dep->recursive_hard_deps().begin();
288 cur != dep->recursive_hard_deps().end(); ++cur)
289 recursive_hard_deps_.insert(*cur);
293 void Target::FillOutputFiles() {
294 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
295 switch (output_type_) {
296 case GROUP:
297 case SOURCE_SET:
298 case COPY_FILES:
299 case ACTION:
300 case ACTION_FOREACH: {
301 // These don't get linked to and use stamps which should be the first
302 // entry in the outputs. These stamps are named
303 // "<target_out_dir>/<targetname>.stamp".
304 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this);
305 dependency_output_file_.value().append(GetComputedOutputName(true));
306 dependency_output_file_.value().append(".stamp");
307 break;
309 case EXECUTABLE:
310 // Executables don't get linked to, but the first output is used for
311 // dependency management.
312 CHECK_GE(tool->outputs().list().size(), 1u);
313 dependency_output_file_ =
314 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
315 this, tool, tool->outputs().list()[0]);
316 break;
317 case STATIC_LIBRARY:
318 // Static libraries both have dependencies and linking going off of the
319 // first output.
320 CHECK(tool->outputs().list().size() >= 1);
321 link_output_file_ = dependency_output_file_ =
322 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
323 this, tool, tool->outputs().list()[0]);
324 break;
325 case SHARED_LIBRARY:
326 CHECK(tool->outputs().list().size() >= 1);
327 if (tool->link_output().empty() && tool->depend_output().empty()) {
328 // Default behavior, use the first output file for both.
329 link_output_file_ = dependency_output_file_ =
330 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
331 this, tool, tool->outputs().list()[0]);
332 } else {
333 // Use the tool-specified ones.
334 if (!tool->link_output().empty()) {
335 link_output_file_ =
336 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
337 this, tool, tool->link_output());
339 if (!tool->depend_output().empty()) {
340 dependency_output_file_ =
341 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
342 this, tool, tool->link_output());
345 break;
346 case UNKNOWN:
347 default:
348 NOTREACHED();
352 bool Target::CheckVisibility(Err* err) const {
353 // Only check visibility when the origin of the dependency is non-null. These
354 // are dependencies added by the GN files. Internally added dependencies
355 // (expanded groups) will have a null origin. We don't want to check
356 // visibility for these, since the point of a group would often be to
357 // forward visibility.
358 for (size_t i = 0; i < deps_.size(); i++) {
359 if (deps_[i].origin &&
360 !Visibility::CheckItemVisibility(this, deps_[i].ptr, err))
361 return false;
364 for (size_t i = 0; i < datadeps_.size(); i++) {
365 if (deps_[i].origin &&
366 !Visibility::CheckItemVisibility(this, datadeps_[i].ptr, err))
367 return false;
370 return true;
373 bool Target::CheckTestonly(Err* err) const {
374 // If there current target is marked testonly, it can include both testonly
375 // and non-testonly targets, so there's nothing to check.
376 if (testonly())
377 return true;
379 // Verify no deps have "testonly" set.
380 for (size_t i = 0; i < deps_.size(); i++) {
381 if (deps_[i].ptr->testonly()) {
382 *err = MakeTestOnlyError(this, deps_[i].ptr);
383 return false;
387 for (size_t i = 0; i < datadeps_.size(); i++) {
388 if (datadeps_[i].ptr->testonly()) {
389 *err = MakeTestOnlyError(this, datadeps_[i].ptr);
390 return false;
394 return true;