1 // Copyright 2022 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 "gn/resolved_target_data.h"
6
7 #include "gn/config_values_extractors.h"
8 #include "gn/resolved_target_deps.h"
9
10 using LibInfo = ResolvedTargetData::LibInfo;
11 using FrameworkInfo = ResolvedTargetData::FrameworkInfo;
12
13 namespace {
14
15 struct TargetInfo {
16 TargetInfo() = default;
17
TargetInfo__anon4253cfb90111::TargetInfo18 TargetInfo(const Target* target)
19 : target(target),
20 deps(target->public_deps(),
21 target->private_deps(),
22 target->data_deps()) {}
23
24 const Target* target = nullptr;
25 ResolvedTargetDeps deps;
26
27 bool has_lib_info = false;
28 bool has_framework_info = false;
29 bool has_hard_deps = false;
30 bool has_inherited_libs = false;
31 bool has_rust_libs = false;
32
33 // Only valid if |has_lib_info|.
34 ImmutableVector<SourceDir> lib_dirs;
35 ImmutableVector<LibFile> libs;
36
37 // Only valid if |has_framework_info|.
38 ImmutableVector<SourceDir> framework_dirs;
39 ImmutableVector<std::string> frameworks;
40 ImmutableVector<std::string> weak_frameworks;
41
42 // Only valid if |has_hard_deps|.
43 ImmutableVector<const Target*> hard_deps;
44
45 // Only valid if |has_inherited_libs|.
46 ImmutableVector<TargetPublicPair> inherited_libs;
47
48 // Only valid if |has_rust_libs|.
49 ImmutableVector<TargetPublicPair> rust_inherited_libs;
50 ImmutableVector<TargetPublicPair> rust_inheritable_libs;
51 };
52
53 } // namespace
54
55 // Implementation class for ResolvedTargetData.
56 class ResolvedTargetData::Impl {
57 public:
GetLibInfo(const Target * target) const58 LibInfo GetLibInfo(const Target* target) const {
59 const TargetInfo* info = GetRecursiveTargetLibInfo(target);
60 DCHECK(info->has_lib_info);
61 return LibInfo{
62 info->lib_dirs,
63 info->libs,
64 };
65 }
66
all_lib_dirs(const Target * target) const67 ImmutableVectorView<SourceDir> all_lib_dirs(const Target* target) const {
68 const TargetInfo* info = GetRecursiveTargetLibInfo(target);
69 DCHECK(info->has_lib_info);
70 return info->lib_dirs;
71 }
72
all_libs(const Target * target) const73 ImmutableVectorView<LibFile> all_libs(const Target* target) const {
74 const TargetInfo* info = GetRecursiveTargetLibInfo(target);
75 DCHECK(info->has_lib_info);
76 return info->libs;
77 }
78
GetFrameworkInfo(const Target * target) const79 FrameworkInfo GetFrameworkInfo(const Target* target) const {
80 const TargetInfo* info = GetRecursiveTargetFrameworkInfo(target);
81 DCHECK(info->has_framework_info);
82 return FrameworkInfo{
83 info->framework_dirs,
84 info->frameworks,
85 info->weak_frameworks,
86 };
87 }
88
all_framework_dirs(const Target * target) const89 ImmutableVectorView<SourceDir> all_framework_dirs(
90 const Target* target) const {
91 const TargetInfo* info = GetRecursiveTargetFrameworkInfo(target);
92 DCHECK(info->has_framework_info);
93 return info->framework_dirs;
94 }
95
all_frameworks(const Target * target) const96 ImmutableVectorView<std::string> all_frameworks(const Target* target) const {
97 const TargetInfo* info = GetRecursiveTargetFrameworkInfo(target);
98 DCHECK(info->has_framework_info);
99 return info->frameworks;
100 }
101
all_weak_frameworks(const Target * target) const102 ImmutableVectorView<std::string> all_weak_frameworks(
103 const Target* target) const {
104 const TargetInfo* info = GetRecursiveTargetFrameworkInfo(target);
105 DCHECK(info->has_framework_info);
106 return info->weak_frameworks;
107 }
108
recursive_hard_deps(const Target * target) const109 TargetSet recursive_hard_deps(const Target* target) const {
110 TargetInfo* info = GetInfo(target);
111 DCHECK(info->has_hard_deps);
112 if (!info->has_hard_deps)
113 ComputeHardDeps(info);
114
115 return TargetSet(info->hard_deps.begin(), info->hard_deps.end());
116 }
117
inherited_libraries(const Target * target) const118 ImmutableVectorView<TargetPublicPair> inherited_libraries(
119 const Target* target) const {
120 const TargetInfo* info = GetRecursiveTargetInheritedLibs(target);
121 DCHECK(info->has_inherited_libs);
122 return info->inherited_libs;
123 }
124
rust_transitive_inherited_libs(const Target * target) const125 ImmutableVectorView<TargetPublicPair> rust_transitive_inherited_libs(
126 const Target* target) const {
127 const TargetInfo* info = GetRecursiveTargetRustLibs(target);
128 DCHECK(info->has_rust_libs);
129 return info->rust_inherited_libs;
130 }
131
132 private:
GetRecursiveTargetLibInfo(const Target * target) const133 const TargetInfo* GetRecursiveTargetLibInfo(const Target* target) const {
134 TargetInfo* info = GetInfo(target);
135 if (!info->has_lib_info)
136 ComputeLibInfo(info);
137 return info;
138 }
139
ComputeLibInfo(TargetInfo * info) const140 void ComputeLibInfo(TargetInfo* info) const {
141 UniqueVector<SourceDir> all_lib_dirs;
142 UniqueVector<LibFile> all_libs;
143
144 for (ConfigValuesIterator iter(info->target); !iter.done(); iter.Next()) {
145 const ConfigValues& cur = iter.cur();
146 all_lib_dirs.Append(cur.lib_dirs());
147 all_libs.Append(cur.libs());
148 }
149 for (const Target* dep : info->deps.linked_deps()) {
150 if (!dep->IsFinal() || dep->output_type() == Target::STATIC_LIBRARY) {
151 const TargetInfo* dep_info = GetRecursiveTargetLibInfo(dep);
152 all_lib_dirs.Append(dep_info->lib_dirs);
153 all_libs.Append(dep_info->libs);
154 }
155 }
156
157 info->lib_dirs = ImmutableVector<SourceDir>(all_lib_dirs.release());
158 info->libs = ImmutableVector<LibFile>(all_libs.release());
159 info->has_lib_info = true;
160 }
161
GetRecursiveTargetFrameworkInfo(const Target * target) const162 const TargetInfo* GetRecursiveTargetFrameworkInfo(
163 const Target* target) const {
164 TargetInfo* info = GetInfo(target);
165 if (!info->has_framework_info)
166 ComputeFrameworkInfo(info);
167 return info;
168 }
169
ComputeFrameworkInfo(TargetInfo * info) const170 void ComputeFrameworkInfo(TargetInfo* info) const {
171 UniqueVector<SourceDir> all_framework_dirs;
172 UniqueVector<std::string> all_frameworks;
173 UniqueVector<std::string> all_weak_frameworks;
174
175 for (ConfigValuesIterator iter(info->target); !iter.done(); iter.Next()) {
176 const ConfigValues& cur = iter.cur();
177 all_framework_dirs.Append(cur.framework_dirs());
178 all_frameworks.Append(cur.frameworks());
179 all_weak_frameworks.Append(cur.weak_frameworks());
180 }
181 for (const Target* dep : info->deps.linked_deps()) {
182 if (!dep->IsFinal() || dep->output_type() == Target::STATIC_LIBRARY) {
183 const TargetInfo* dep_info = GetRecursiveTargetLibInfo(dep);
184 all_framework_dirs.Append(dep_info->framework_dirs);
185 all_frameworks.Append(dep_info->frameworks);
186 all_weak_frameworks.Append(dep_info->weak_frameworks);
187 }
188 }
189
190 info->framework_dirs = ImmutableVector<SourceDir>(all_framework_dirs);
191 info->frameworks = ImmutableVector<std::string>(all_frameworks);
192 info->weak_frameworks = ImmutableVector<std::string>(all_weak_frameworks);
193 info->has_framework_info = true;
194 }
195
GetRecursiveTargetHardDeps(const Target * target) const196 const TargetInfo* GetRecursiveTargetHardDeps(const Target* target) const {
197 TargetInfo* info = GetInfo(target);
198 if (!info->has_hard_deps)
199 ComputeHardDeps(info);
200 return info;
201 }
202
ComputeHardDeps(TargetInfo * info) const203 void ComputeHardDeps(TargetInfo* info) const {
204 TargetSet all_hard_deps;
205 for (const Target* dep : info->deps.linked_deps()) {
206 // Direct hard dependencies
207 if (info->target->hard_dep() || dep->hard_dep()) {
208 all_hard_deps.insert(dep);
209 continue;
210 }
211 // If |dep| is binary target and |dep| has no public header,
212 // |this| target does not need to have |dep|'s hard_deps as its
213 // hard_deps to start compiles earlier. Unless the target compiles a
214 // Swift module (since they also generate a header that can be used
215 // by the current target).
216 if (dep->IsBinary() && !dep->all_headers_public() &&
217 dep->public_headers().empty() && !dep->builds_swift_module()) {
218 continue;
219 }
220
221 // Recursive hard dependencies of all dependencies.
222 const TargetInfo* dep_info = GetRecursiveTargetHardDeps(dep);
223 all_hard_deps.insert(dep_info->hard_deps.begin(),
224 dep_info->hard_deps.end());
225 }
226 info->hard_deps = ImmutableVector<const Target*>(all_hard_deps);
227 info->has_hard_deps = true;
228 }
229
GetRecursiveTargetInheritedLibs(const Target * target) const230 const TargetInfo* GetRecursiveTargetInheritedLibs(
231 const Target* target) const {
232 TargetInfo* info = GetInfo(target);
233 if (!info->has_inherited_libs)
234 ComputeInheritedLibs(info);
235 return info;
236 }
237
ComputeInheritedLibs(TargetInfo * info) const238 void ComputeInheritedLibs(TargetInfo* info) const {
239 TargetPublicPairListBuilder inherited_libraries;
240
241 ComputeInheritedLibsFor(info->deps.public_deps(), true,
242 &inherited_libraries);
243 ComputeInheritedLibsFor(info->deps.private_deps(), false,
244 &inherited_libraries);
245
246 info->has_inherited_libs = true;
247 info->inherited_libs = inherited_libraries.Build();
248 }
249
ComputeInheritedLibsFor(base::span<const Target * > deps,bool is_public,TargetPublicPairListBuilder * inherited_libraries) const250 void ComputeInheritedLibsFor(
251 base::span<const Target*> deps,
252 bool is_public,
253 TargetPublicPairListBuilder* inherited_libraries) const {
254 for (const Target* dep : deps) {
255 // Direct dependent libraries.
256 if (dep->output_type() == Target::STATIC_LIBRARY ||
257 dep->output_type() == Target::SHARED_LIBRARY ||
258 dep->output_type() == Target::RUST_LIBRARY ||
259 dep->output_type() == Target::SOURCE_SET ||
260 (dep->output_type() == Target::CREATE_BUNDLE &&
261 dep->bundle_data().is_framework())) {
262 inherited_libraries->Append(dep, is_public);
263 }
264 if (dep->output_type() == Target::SHARED_LIBRARY) {
265 // Shared library dependendencies are inherited across public shared
266 // library boundaries.
267 //
268 // In this case:
269 // EXE -> INTERMEDIATE_SHLIB --[public]--> FINAL_SHLIB
270 // The EXE will also link to to FINAL_SHLIB. The public dependency means
271 // that the EXE can use the headers in FINAL_SHLIB so the FINAL_SHLIB
272 // will need to appear on EXE's link line.
273 //
274 // However, if the dependency is private:
275 // EXE -> INTERMEDIATE_SHLIB --[private]--> FINAL_SHLIB
276 // the dependency will not be propagated because INTERMEDIATE_SHLIB is
277 // not granting permission to call functions from FINAL_SHLIB. If EXE
278 // wants to use functions (and link to) FINAL_SHLIB, it will need to do
279 // so explicitly.
280 //
281 // Static libraries and source sets aren't inherited across shared
282 // library boundaries because they will be linked into the shared
283 // library. Rust dylib deps are handled above and transitive deps are
284 // resolved by the compiler.
285 const TargetInfo* dep_info = GetRecursiveTargetInheritedLibs(dep);
286 for (const auto& pair : dep_info->inherited_libs) {
287 if (pair.target()->output_type() == Target::SHARED_LIBRARY &&
288 pair.is_public()) {
289 inherited_libraries->Append(pair.target(), is_public);
290 }
291 }
292 } else if (!dep->IsFinal()) {
293 // The current target isn't linked, so propagate linked deps and
294 // libraries up the dependency tree.
295 const TargetInfo* dep_info = GetRecursiveTargetInheritedLibs(dep);
296 for (const auto& pair : dep_info->inherited_libs) {
297 // Proc macros are not linked into targets that depend on them, so do
298 // not get inherited; they are consumed by the Rust compiler and only
299 // need to be specified in --extern.
300 if (pair.target()->output_type() != Target::RUST_PROC_MACRO)
301 inherited_libraries->Append(pair.target(),
302 is_public && pair.is_public());
303 }
304 } else if (dep->complete_static_lib()) {
305 // Inherit only final targets through _complete_ static libraries.
306 //
307 // Inherited final libraries aren't linked into complete static
308 // libraries. They are forwarded here so that targets that depend on
309 // complete static libraries can link them in. Conversely, since
310 // complete static libraries link in non-final targets they shouldn't be
311 // inherited.
312 const TargetInfo* dep_info = GetRecursiveTargetInheritedLibs(dep);
313 for (const auto& pair : dep_info->inherited_libs) {
314 if (pair.target()->IsFinal())
315 inherited_libraries->Append(pair.target(),
316 is_public && pair.is_public());
317 }
318 }
319 }
320 }
321
GetRecursiveTargetRustLibs(const Target * target) const322 const TargetInfo* GetRecursiveTargetRustLibs(const Target* target) const {
323 TargetInfo* info = GetInfo(target);
324 if (!info->has_rust_libs)
325 ComputeRustLibs(info);
326 return info;
327 }
328
329 struct RustLibsBuilder {
330 TargetPublicPairListBuilder inherited;
331 TargetPublicPairListBuilder inheritable;
332 };
333
ComputeRustLibs(TargetInfo * info) const334 void ComputeRustLibs(TargetInfo* info) const {
335 RustLibsBuilder rust_libs;
336
337 ComputeRustLibsFor(info->deps.public_deps(), true, &rust_libs);
338 ComputeRustLibsFor(info->deps.private_deps(), false, &rust_libs);
339
340 info->has_rust_libs = true;
341 info->rust_inherited_libs = rust_libs.inherited.Build();
342 info->rust_inheritable_libs = rust_libs.inheritable.Build();
343 }
344
ComputeRustLibsFor(base::span<const Target * > deps,bool is_public,RustLibsBuilder * rust_libs) const345 void ComputeRustLibsFor(base::span<const Target*> deps,
346 bool is_public,
347 RustLibsBuilder* rust_libs) const {
348 for (const Target* dep : deps) {
349 // Collect Rust libraries that are accessible from the current target, or
350 // transitively part of the current target.
351 if (dep->output_type() == Target::STATIC_LIBRARY ||
352 dep->output_type() == Target::SHARED_LIBRARY ||
353 dep->output_type() == Target::SOURCE_SET ||
354 dep->output_type() == Target::RUST_LIBRARY ||
355 dep->output_type() == Target::GROUP) {
356 // Here we have: `this` --[depends-on]--> `dep`
357 //
358 // The `this` target has direct access to `dep` since its a direct
359 // dependency, regardless of the edge being a public_dep or not, so we
360 // pass true for public-ness. Whereas, anything depending on `this` can
361 // only gain direct access to `dep` if the edge between `this` and `dep`
362 // is public, so we pass `is_public`.
363 //
364 // TODO(danakj): We should only need to track Rust rlibs or dylibs here,
365 // as it's used for passing to rustc with --extern. We currently track
366 // everything then drop non-Rust libs in
367 // ninja_rust_binary_target_writer.cc.
368 rust_libs->inherited.Append(dep, true);
369 rust_libs->inheritable.Append(dep, is_public);
370
371 const TargetInfo* dep_info = GetRecursiveTargetRustLibs(dep);
372 rust_libs->inherited.AppendInherited(dep_info->rust_inheritable_libs,
373 true);
374 rust_libs->inheritable.AppendInherited(dep_info->rust_inheritable_libs,
375 is_public);
376 } else if (dep->output_type() == Target::RUST_PROC_MACRO) {
377 // Proc-macros are inherited as a transitive dependency, but the things
378 // they depend on can't be used elsewhere, as the proc macro is not
379 // linked into the target (as it's only used during compilation).
380 rust_libs->inherited.Append(dep, true);
381 rust_libs->inheritable.Append(dep, is_public);
382 }
383 }
384 }
385
GetInfo(const Target * target) const386 TargetInfo* GetInfo(const Target* target) const {
387 auto ret = targets_.PushBackWithIndex(target);
388 if (!ret.first)
389 return infos_[ret.second].get();
390
391 infos_.push_back(std::make_unique<TargetInfo>(target));
392 return infos_.back().get();
393 }
394
395 // A { target -> TargetInfo } map that will create entries
396 // on demand. Implemented with a UniqueVector<> and a parallel
397 // vector of unique TargetInfo instances for best performance.
398 mutable UniqueVector<const Target*> targets_;
399 mutable std::vector<std::unique_ptr<TargetInfo>> infos_;
400 };
401
402 ResolvedTargetData::ResolvedTargetData() = default;
403
404 ResolvedTargetData::~ResolvedTargetData() = default;
405
406 ResolvedTargetData::ResolvedTargetData(ResolvedTargetData&&) noexcept = default;
407 ResolvedTargetData& ResolvedTargetData::operator=(ResolvedTargetData&&) =
408 default;
409
GetImpl() const410 ResolvedTargetData::Impl* ResolvedTargetData::GetImpl() const {
411 if (!impl_)
412 impl_ = std::make_unique<ResolvedTargetData::Impl>();
413 return impl_.get();
414 }
415
GetLibInfo(const Target * target) const416 LibInfo ResolvedTargetData::GetLibInfo(const Target* target) const {
417 return GetImpl()->GetLibInfo(target);
418 }
419
all_lib_dirs(const Target * target) const420 ImmutableVectorView<SourceDir> ResolvedTargetData::all_lib_dirs(
421 const Target* target) const {
422 return GetImpl()->all_lib_dirs(target);
423 }
424
all_libs(const Target * target) const425 ImmutableVectorView<LibFile> ResolvedTargetData::all_libs(
426 const Target* target) const {
427 return GetImpl()->all_libs(target);
428 }
429
GetFrameworkInfo(const Target * target) const430 FrameworkInfo ResolvedTargetData::GetFrameworkInfo(const Target* target) const {
431 return GetImpl()->GetFrameworkInfo(target);
432 }
433
all_framework_dirs(const Target * target) const434 ImmutableVectorView<SourceDir> ResolvedTargetData::all_framework_dirs(
435 const Target* target) const {
436 return GetImpl()->all_framework_dirs(target);
437 }
438
all_frameworks(const Target * target) const439 ImmutableVectorView<std::string> ResolvedTargetData::all_frameworks(
440 const Target* target) const {
441 return GetImpl()->all_frameworks(target);
442 }
443
all_weak_frameworks(const Target * target) const444 ImmutableVectorView<std::string> ResolvedTargetData::all_weak_frameworks(
445 const Target* target) const {
446 return GetImpl()->all_weak_frameworks(target);
447 }
448
recursive_hard_deps(const Target * target) const449 TargetSet ResolvedTargetData::recursive_hard_deps(const Target* target) const {
450 return GetImpl()->recursive_hard_deps(target);
451 }
452
inherited_libraries(const Target * target) const453 TargetPublicPairList ResolvedTargetData::inherited_libraries(
454 const Target* target) const {
455 return GetImpl()->inherited_libraries(target);
456 }
457
rust_transitive_inherited_libs(const Target * target) const458 TargetPublicPairList ResolvedTargetData::rust_transitive_inherited_libs(
459 const Target* target) const {
460 return GetImpl()->rust_transitive_inherited_libs(target);
461 }
462