• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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