Home | History | Annotate | Download | only in gn
      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 
     11 namespace {
     12 
     13 typedef 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.
     18 void 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.
     33 void 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 
     54 Target::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 
     61 Target::~Target() {
     62 }
     63 
     64 // static
     65 const 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 
     90 Target* Target::AsTarget() {
     91   return this;
     92 }
     93 
     94 const Target* Target::AsTarget() const {
     95   return this;
     96 }
     97 
     98 void 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 
    155 bool Target::IsLinkable() const {
    156   return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY;
    157 }
    158 
    159 void 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 
    189 void 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 
    210 void 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