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.
4
5#include "tools/gn/target.h"
6
7#include "base/bind.h"
8#include "tools/gn/config_values_extractors.h"
9#include "tools/gn/scheduler.h"
10
11namespace {
12
13typedef std::set<const Config*> ConfigSet;
14
15// Merges the dependent configs from the given target to the given config list.
16// The unique_configs list is used for de-duping so values already added will
17// not be added again.
18void MergeDirectDependentConfigsFrom(const Target* from_target,
19                                     ConfigSet* unique_configs,
20                                     LabelConfigVector* dest) {
21  const LabelConfigVector& direct = from_target->direct_dependent_configs();
22  for (size_t i = 0; i < direct.size(); i++) {
23    if (unique_configs->find(direct[i].ptr) == unique_configs->end()) {
24      unique_configs->insert(direct[i].ptr);
25      dest->push_back(direct[i]);
26    }
27  }
28}
29
30// Like MergeDirectDependentConfigsFrom above except does the "all dependent"
31// ones. This additionally adds all configs to the all_dependent_configs_ of
32// the dest target given in *all_dest.
33void MergeAllDependentConfigsFrom(const Target* from_target,
34                                  ConfigSet* unique_configs,
35                                  LabelConfigVector* dest,
36                                  LabelConfigVector* all_dest) {
37  const LabelConfigVector& all = from_target->all_dependent_configs();
38  for (size_t i = 0; i < all.size(); i++) {
39    // Always add it to all_dependent_configs_ since it might not be in that
40    // list even if we've seen it applied to this target before. This may
41    // introduce some duplicates in all_dependent_configs_, but those will
42    // we removed when they're actually applied to a target.
43    all_dest->push_back(all[i]);
44    if (unique_configs->find(all[i].ptr) == unique_configs->end()) {
45      // One we haven't seen yet, also apply it to ourselves.
46      dest->push_back(all[i]);
47      unique_configs->insert(all[i].ptr);
48    }
49  }
50}
51
52}  // namespace
53
54Target::Target(const Settings* settings, const Label& label)
55    : Item(settings, label),
56      output_type_(UNKNOWN),
57      all_headers_public_(true),
58      hard_dep_(false) {
59}
60
61Target::~Target() {
62}
63
64// static
65const char* Target::GetStringForOutputType(OutputType type) {
66  switch (type) {
67    case UNKNOWN:
68      return "Unknown";
69    case GROUP:
70      return "Group";
71    case EXECUTABLE:
72      return "Executable";
73    case SHARED_LIBRARY:
74      return "Shared library";
75    case STATIC_LIBRARY:
76      return "Static library";
77    case SOURCE_SET:
78      return "Source set";
79    case COPY_FILES:
80      return "Copy";
81    case ACTION:
82      return "Action";
83    case ACTION_FOREACH:
84      return "ActionForEach";
85    default:
86      return "";
87  }
88}
89
90Target* Target::AsTarget() {
91  return this;
92}
93
94const Target* Target::AsTarget() const {
95  return this;
96}
97
98void Target::OnResolved() {
99  DCHECK(output_type_ != UNKNOWN);
100
101  // Convert any groups we depend on to just direct dependencies on that
102  // group's deps. We insert the new deps immediately after the group so that
103  // the ordering is preserved. We need to keep the original group so that any
104  // flags, etc. that it specifies itself are applied to us.
105  for (size_t i = 0; i < deps_.size(); i++) {
106    const Target* dep = deps_[i].ptr;
107    if (dep->output_type_ == GROUP) {
108      deps_.insert(deps_.begin() + i + 1, dep->deps_.begin(), dep->deps_.end());
109      i += dep->deps_.size();
110    }
111  }
112
113  // Only add each config once. First remember the target's configs.
114  ConfigSet unique_configs;
115  for (size_t i = 0; i < configs_.size(); i++)
116    unique_configs.insert(configs_[i].ptr);
117
118  // Copy our own dependent configs to the list of configs applying to us.
119  for (size_t i = 0; i < all_dependent_configs_.size(); i++) {
120    if (unique_configs.find(all_dependent_configs_[i].ptr) ==
121        unique_configs.end()) {
122      unique_configs.insert(all_dependent_configs_[i].ptr);
123      configs_.push_back(all_dependent_configs_[i]);
124    }
125  }
126  for (size_t i = 0; i < direct_dependent_configs_.size(); i++) {
127    if (unique_configs.find(direct_dependent_configs_[i].ptr) ==
128        unique_configs.end()) {
129      unique_configs.insert(direct_dependent_configs_[i].ptr);
130      configs_.push_back(direct_dependent_configs_[i]);
131    }
132  }
133
134  // Copy our own libs and lib_dirs to the final set. This will be from our
135  // target and all of our configs. We do this specially since these must be
136  // inherited through the dependency tree (other flags don't work this way).
137  for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) {
138    const ConfigValues& cur = iter.cur();
139    all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end());
140    all_libs_.append(cur.libs().begin(), cur.libs().end());
141  }
142
143  if (output_type_ != GROUP) {
144    // Don't pull target info like libraries and configs from dependencies into
145    // a group target. When A depends on a group G, the G's dependents will
146    // be treated as direct dependencies of A, so this is unnecessary and will
147    // actually result in duplicated settings (since settings will also be
148    // pulled from G to A in case G has configs directly on it).
149    PullDependentTargetInfo(&unique_configs);
150  }
151  PullForwardedDependentConfigs();
152  PullRecursiveHardDeps();
153}
154
155bool Target::IsLinkable() const {
156  return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY;
157}
158
159void Target::PullDependentTargetInfo(std::set<const Config*>* unique_configs) {
160  // Gather info from our dependents we need.
161  for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) {
162    const Target* dep = deps_[dep_i].ptr;
163    MergeAllDependentConfigsFrom(dep, unique_configs, &configs_,
164                                 &all_dependent_configs_);
165    MergeDirectDependentConfigsFrom(dep, unique_configs, &configs_);
166
167    // Direct dependent libraries.
168    if (dep->output_type() == STATIC_LIBRARY ||
169        dep->output_type() == SHARED_LIBRARY ||
170        dep->output_type() == SOURCE_SET)
171      inherited_libraries_.insert(dep);
172
173    // Inherited libraries and flags are inherited across static library
174    // boundaries.
175    if (dep->output_type() != SHARED_LIBRARY &&
176        dep->output_type() != EXECUTABLE) {
177      const std::set<const Target*> inherited = dep->inherited_libraries();
178      for (std::set<const Target*>::const_iterator i = inherited.begin();
179           i != inherited.end(); ++i)
180        inherited_libraries_.insert(*i);
181
182      // Inherited library settings.
183      all_lib_dirs_.append(dep->all_lib_dirs());
184      all_libs_.append(dep->all_libs());
185    }
186  }
187}
188
189void Target::PullForwardedDependentConfigs() {
190  // Groups implicitly forward all if its dependency's configs.
191  if (output_type() == GROUP)
192    forward_dependent_configs_ = deps_;
193
194  // Forward direct dependent configs if requested.
195  for (size_t dep = 0; dep < forward_dependent_configs_.size(); dep++) {
196    const Target* from_target = forward_dependent_configs_[dep].ptr;
197
198    // The forward_dependent_configs_ must be in the deps already, so we
199    // don't need to bother copying to our configs, only forwarding.
200    DCHECK(std::find_if(deps_.begin(), deps_.end(),
201                        LabelPtrPtrEquals<Target>(from_target)) !=
202           deps_.end());
203    direct_dependent_configs_.insert(
204        direct_dependent_configs_.end(),
205        from_target->direct_dependent_configs().begin(),
206        from_target->direct_dependent_configs().end());
207  }
208}
209
210void Target::PullRecursiveHardDeps() {
211  for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) {
212    const Target* dep = deps_[dep_i].ptr;
213    if (dep->hard_dep())
214      recursive_hard_deps_.insert(dep);
215
216    // Android STL doesn't like insert(begin, end) so do it manually.
217    // TODO(brettw) this can be changed to insert(dep->begin(), dep->end()) when
218    // Android uses a better STL.
219    for (std::set<const Target*>::const_iterator cur =
220             dep->recursive_hard_deps().begin();
221         cur != dep->recursive_hard_deps().end(); ++cur)
222      recursive_hard_deps_.insert(*cur);
223  }
224}
225