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 "base/strings/string_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "tools/gn/config_values_extractors.h" | 10 #include "tools/gn/config_values_extractors.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 UniqueVector<LabelConfigPair>* dest, | 32 UniqueVector<LabelConfigPair>* dest, |
33 UniqueVector<LabelConfigPair>* all_dest) { | 33 UniqueVector<LabelConfigPair>* all_dest) { |
34 const UniqueVector<LabelConfigPair>& all = | 34 const UniqueVector<LabelConfigPair>& all = |
35 from_target->all_dependent_configs(); | 35 from_target->all_dependent_configs(); |
36 for (size_t i = 0; i < all.size(); i++) { | 36 for (size_t i = 0; i < all.size(); i++) { |
37 all_dest->push_back(all[i]); | 37 all_dest->push_back(all[i]); |
38 dest->push_back(all[i]); | 38 dest->push_back(all[i]); |
39 } | 39 } |
40 } | 40 } |
41 | 41 |
| 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."); |
| 51 } |
| 52 |
| 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()); |
| 60 |
| 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; |
| 65 |
| 66 return deps.size(); |
| 67 } |
| 68 |
42 } // namespace | 69 } // namespace |
43 | 70 |
44 Target::Target(const Settings* settings, const Label& label) | 71 Target::Target(const Settings* settings, const Label& label) |
45 : Item(settings, label), | 72 : Item(settings, label), |
46 output_type_(UNKNOWN), | 73 output_type_(UNKNOWN), |
47 all_headers_public_(true), | 74 all_headers_public_(true), |
| 75 testonly_(false), |
48 hard_dep_(false), | 76 hard_dep_(false), |
49 toolchain_(NULL) { | 77 toolchain_(NULL) { |
50 } | 78 } |
51 | 79 |
52 Target::~Target() { | 80 Target::~Target() { |
53 } | 81 } |
54 | 82 |
55 // static | 83 // static |
56 const char* Target::GetStringForOutputType(OutputType type) { | 84 const char* Target::GetStringForOutputType(OutputType type) { |
57 switch (type) { | 85 switch (type) { |
(...skipping 21 matching lines...) Expand all Loading... |
79 } | 107 } |
80 | 108 |
81 Target* Target::AsTarget() { | 109 Target* Target::AsTarget() { |
82 return this; | 110 return this; |
83 } | 111 } |
84 | 112 |
85 const Target* Target::AsTarget() const { | 113 const Target* Target::AsTarget() const { |
86 return this; | 114 return this; |
87 } | 115 } |
88 | 116 |
89 void Target::OnResolved() { | 117 bool Target::OnResolved(Err* err) { |
90 DCHECK(output_type_ != UNKNOWN); | 118 DCHECK(output_type_ != UNKNOWN); |
91 DCHECK(toolchain_) << "Toolchain should have been set before resolving."; | 119 DCHECK(toolchain_) << "Toolchain should have been set before resolving."; |
92 | 120 |
93 // Convert any groups we depend on to just direct dependencies on that | 121 ExpandGroups(); |
94 // group's deps. We insert the new deps immediately after the group so that | |
95 // the ordering is preserved. We need to keep the original group so that any | |
96 // flags, etc. that it specifies itself are applied to us. | |
97 for (size_t i = 0; i < deps_.size(); i++) { | |
98 const Target* dep = deps_[i].ptr; | |
99 if (dep->output_type_ == GROUP) { | |
100 // TODO(brettw) bug 403488 this should also handle datadeps. | |
101 deps_.insert(deps_.begin() + i + 1, dep->deps_.begin(), dep->deps_.end()); | |
102 i += dep->deps_.size(); | |
103 } | |
104 } | |
105 | 122 |
106 // Copy our own dependent configs to the list of configs applying to us. | 123 // Copy our own dependent configs to the list of configs applying to us. |
107 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end()); | 124 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end()); |
108 configs_.Append(direct_dependent_configs_.begin(), | 125 configs_.Append(direct_dependent_configs_.begin(), |
109 direct_dependent_configs_.end()); | 126 direct_dependent_configs_.end()); |
110 | 127 |
111 // Copy our own libs and lib_dirs to the final set. This will be from our | 128 // Copy our own libs and lib_dirs to the final set. This will be from our |
112 // target and all of our configs. We do this specially since these must be | 129 // target and all of our configs. We do this specially since these must be |
113 // inherited through the dependency tree (other flags don't work this way). | 130 // inherited through the dependency tree (other flags don't work this way). |
114 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { | 131 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { |
115 const ConfigValues& cur = iter.cur(); | 132 const ConfigValues& cur = iter.cur(); |
116 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); | 133 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); |
117 all_libs_.append(cur.libs().begin(), cur.libs().end()); | 134 all_libs_.append(cur.libs().begin(), cur.libs().end()); |
118 } | 135 } |
119 | 136 |
120 if (output_type_ != GROUP) { | 137 if (output_type_ != GROUP) { |
121 // Don't pull target info like libraries and configs from dependencies into | 138 // Don't pull target info like libraries and configs from dependencies into |
122 // a group target. When A depends on a group G, the G's dependents will | 139 // a group target. When A depends on a group G, the G's dependents will |
123 // be treated as direct dependencies of A, so this is unnecessary and will | 140 // be treated as direct dependencies of A, so this is unnecessary and will |
124 // actually result in duplicated settings (since settings will also be | 141 // actually result in duplicated settings (since settings will also be |
125 // pulled from G to A in case G has configs directly on it). | 142 // pulled from G to A in case G has configs directly on it). |
126 PullDependentTargetInfo(); | 143 PullDependentTargetInfo(); |
127 } | 144 } |
128 PullForwardedDependentConfigs(); | 145 PullForwardedDependentConfigs(); |
129 PullRecursiveHardDeps(); | 146 PullRecursiveHardDeps(); |
130 | 147 |
131 FillOutputFiles(); | 148 FillOutputFiles(); |
| 149 |
| 150 if (!CheckVisibility(err)) |
| 151 return false; |
| 152 if (!CheckTestonly(err)) |
| 153 return false; |
| 154 |
| 155 return true; |
132 } | 156 } |
133 | 157 |
134 bool Target::IsLinkable() const { | 158 bool Target::IsLinkable() const { |
135 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; | 159 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
136 } | 160 } |
137 | 161 |
138 std::string Target::GetComputedOutputName(bool include_prefix) const { | 162 std::string Target::GetComputedOutputName(bool include_prefix) const { |
139 DCHECK(toolchain_) | 163 DCHECK(toolchain_) |
140 << "Toolchain must be specified before getting the computed output name."; | 164 << "Toolchain must be specified before getting the computed output name."; |
141 | 165 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 "Alas, I can not continue.", | 199 "Alas, I can not continue.", |
176 label().GetUserVisibleName(false).c_str(), | 200 label().GetUserVisibleName(false).c_str(), |
177 GetStringForOutputType(output_type_), | 201 GetStringForOutputType(output_type_), |
178 label().GetToolchainLabel().GetUserVisibleName(false).c_str(), | 202 label().GetToolchainLabel().GetUserVisibleName(false).c_str(), |
179 Toolchain::ToolTypeToName( | 203 Toolchain::ToolTypeToName( |
180 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); | 204 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); |
181 } | 205 } |
182 return false; | 206 return false; |
183 } | 207 } |
184 | 208 |
| 209 void Target::ExpandGroups() { |
| 210 // Convert any groups we depend on to just direct dependencies on that |
| 211 // group's deps. We insert the new deps immediately after the group so that |
| 212 // the ordering is preserved. We need to keep the original group so that any |
| 213 // flags, etc. that it specifies itself are applied to us. |
| 214 // TODO(brettw) bug 403488 this should also handle datadeps. |
| 215 for (size_t i = 0; i < deps_.size(); i++) { |
| 216 const Target* dep = deps_[i].ptr; |
| 217 if (dep->output_type_ == GROUP) |
| 218 i += InsertGroupDeps(&deps_, i + 1, dep); |
| 219 } |
| 220 } |
| 221 |
185 void Target::PullDependentTargetInfo() { | 222 void Target::PullDependentTargetInfo() { |
186 // Gather info from our dependents we need. | 223 // Gather info from our dependents we need. |
187 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) { | 224 for (size_t dep_i = 0; dep_i < deps_.size(); dep_i++) { |
188 const Target* dep = deps_[dep_i].ptr; | 225 const Target* dep = deps_[dep_i].ptr; |
189 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); | 226 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); |
190 MergeDirectDependentConfigsFrom(dep, &configs_); | 227 MergeDirectDependentConfigsFrom(dep, &configs_); |
191 | 228 |
192 // Direct dependent libraries. | 229 // Direct dependent libraries. |
193 if (dep->output_type() == STATIC_LIBRARY || | 230 if (dep->output_type() == STATIC_LIBRARY || |
194 dep->output_type() == SHARED_LIBRARY || | 231 dep->output_type() == SHARED_LIBRARY || |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 335 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
299 this, tool, tool->link_output()); | 336 this, tool, tool->link_output()); |
300 } | 337 } |
301 } | 338 } |
302 break; | 339 break; |
303 case UNKNOWN: | 340 case UNKNOWN: |
304 default: | 341 default: |
305 NOTREACHED(); | 342 NOTREACHED(); |
306 } | 343 } |
307 } | 344 } |
| 345 |
| 346 bool Target::CheckVisibility(Err* err) const { |
| 347 // Only check visibility when the origin of the dependency is non-null. These |
| 348 // are dependencies added by the GN files. Internally added dependencies |
| 349 // (expanded groups) will have a null origin. We don't want to check |
| 350 // visibility for these, since the point of a group would often be to |
| 351 // forward visibility. |
| 352 for (size_t i = 0; i < deps_.size(); i++) { |
| 353 if (deps_[i].origin && |
| 354 !Visibility::CheckItemVisibility(this, deps_[i].ptr, err)) |
| 355 return false; |
| 356 } |
| 357 |
| 358 for (size_t i = 0; i < datadeps_.size(); i++) { |
| 359 if (deps_[i].origin && |
| 360 !Visibility::CheckItemVisibility(this, datadeps_[i].ptr, err)) |
| 361 return false; |
| 362 } |
| 363 |
| 364 return true; |
| 365 } |
| 366 |
| 367 bool Target::CheckTestonly(Err* err) const { |
| 368 // If there current target is marked testonly, it can include both testonly |
| 369 // and non-testonly targets, so there's nothing to check. |
| 370 if (testonly()) |
| 371 return true; |
| 372 |
| 373 // Verify no deps have "testonly" set. |
| 374 for (size_t i = 0; i < deps_.size(); i++) { |
| 375 if (deps_[i].ptr->testonly()) { |
| 376 *err = MakeTestOnlyError(this, deps_[i].ptr); |
| 377 return false; |
| 378 } |
| 379 } |
| 380 |
| 381 for (size_t i = 0; i < datadeps_.size(); i++) { |
| 382 if (datadeps_[i].ptr->testonly()) { |
| 383 *err = MakeTestOnlyError(this, datadeps_[i].ptr); |
| 384 return false; |
| 385 } |
| 386 } |
| 387 |
| 388 return true; |
| 389 } |
OLD | NEW |