• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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 
GetTargetInfo(const Target * target) const9 ResolvedTargetData::TargetInfo* ResolvedTargetData::GetTargetInfo(
10     const Target* target) const {
11   auto ret = targets_.PushBackWithIndex(target);
12   if (ret.first) {
13     infos_.push_back(std::make_unique<TargetInfo>(target));
14   }
15   return infos_[ret.second].get();
16 }
17 
ComputeLibInfo(TargetInfo * info) const18 void ResolvedTargetData::ComputeLibInfo(TargetInfo* info) const {
19   UniqueVector<SourceDir> all_lib_dirs;
20   UniqueVector<LibFile> all_libs;
21 
22   for (ConfigValuesIterator iter(info->target); !iter.done(); iter.Next()) {
23     const ConfigValues& cur = iter.cur();
24     all_lib_dirs.Append(cur.lib_dirs());
25     all_libs.Append(cur.libs());
26   }
27   for (const Target* dep : info->deps.linked_deps()) {
28     if (!dep->IsFinal() || dep->output_type() == Target::STATIC_LIBRARY) {
29       const TargetInfo* dep_info = GetTargetLibInfo(dep);
30       all_lib_dirs.Append(dep_info->lib_dirs);
31       all_libs.Append(dep_info->libs);
32     }
33   }
34 
35   info->lib_dirs = all_lib_dirs.release();
36   info->libs = all_libs.release();
37   info->has_lib_info = true;
38 }
39 
ComputeFrameworkInfo(TargetInfo * info) const40 void ResolvedTargetData::ComputeFrameworkInfo(TargetInfo* info) const {
41   UniqueVector<SourceDir> all_framework_dirs;
42   UniqueVector<std::string> all_frameworks;
43   UniqueVector<std::string> all_weak_frameworks;
44 
45   for (ConfigValuesIterator iter(info->target); !iter.done(); iter.Next()) {
46     const ConfigValues& cur = iter.cur();
47     all_framework_dirs.Append(cur.framework_dirs());
48     all_frameworks.Append(cur.frameworks());
49     all_weak_frameworks.Append(cur.weak_frameworks());
50   }
51   for (const Target* dep : info->deps.linked_deps()) {
52     if (!dep->IsFinal() || dep->output_type() == Target::STATIC_LIBRARY) {
53       const TargetInfo* dep_info = GetTargetFrameworkInfo(dep);
54       all_framework_dirs.Append(dep_info->framework_dirs);
55       all_frameworks.Append(dep_info->frameworks);
56       all_weak_frameworks.Append(dep_info->weak_frameworks);
57     }
58   }
59 
60   info->framework_dirs = all_framework_dirs.release();
61   info->frameworks = all_frameworks.release();
62   info->weak_frameworks = all_weak_frameworks.release();
63   info->has_framework_info = true;
64 }
65 
ComputeHardDeps(TargetInfo * info) const66 void ResolvedTargetData::ComputeHardDeps(TargetInfo* info) const {
67   TargetSet all_hard_deps;
68   for (const Target* dep : info->deps.linked_deps()) {
69     // Direct hard dependencies
70     if (info->target->hard_dep() || dep->hard_dep()) {
71       all_hard_deps.insert(dep);
72       continue;
73     }
74     // If |dep| is binary target and |dep| has no public header,
75     // |this| target does not need to have |dep|'s hard_deps as its
76     // hard_deps to start compiles earlier. Unless the target compiles a
77     // Swift module (since they also generate a header that can be used
78     // by the current target).
79     if (dep->IsBinary() && !dep->all_headers_public() &&
80         dep->public_headers().empty() && !dep->builds_swift_module()) {
81       continue;
82     }
83 
84     // Recursive hard dependencies of all dependencies.
85     const TargetInfo* dep_info = GetTargetHardDeps(dep);
86     all_hard_deps.insert(dep_info->hard_deps);
87   }
88   info->hard_deps = std::move(all_hard_deps);
89   info->has_hard_deps = true;
90 }
91 
ComputeInheritedLibs(TargetInfo * info) const92 void ResolvedTargetData::ComputeInheritedLibs(TargetInfo* info) const {
93   TargetPublicPairListBuilder inherited_libraries;
94 
95   ComputeInheritedLibsFor(info->deps.public_deps(), true, &inherited_libraries);
96   ComputeInheritedLibsFor(info->deps.private_deps(), false,
97                           &inherited_libraries);
98 
99   info->inherited_libs = inherited_libraries.Build();
100   info->has_inherited_libs = true;
101 }
102 
ComputeInheritedLibsFor(base::span<const Target * > deps,bool is_public,TargetPublicPairListBuilder * inherited_libraries) const103 void ResolvedTargetData::ComputeInheritedLibsFor(
104     base::span<const Target*> deps,
105     bool is_public,
106     TargetPublicPairListBuilder* inherited_libraries) const {
107   for (const Target* dep : deps) {
108     // Direct dependent libraries.
109     if (dep->output_type() == Target::STATIC_LIBRARY ||
110         dep->output_type() == Target::SHARED_LIBRARY ||
111         dep->output_type() == Target::RUST_LIBRARY ||
112         dep->output_type() == Target::SOURCE_SET ||
113         (dep->output_type() == Target::CREATE_BUNDLE &&
114          dep->bundle_data().is_framework())) {
115       inherited_libraries->Append(dep, is_public);
116     }
117     if (dep->output_type() == Target::SHARED_LIBRARY) {
118       // Shared library dependendencies are inherited across public shared
119       // library boundaries.
120       //
121       // In this case:
122       //   EXE -> INTERMEDIATE_SHLIB --[public]--> FINAL_SHLIB
123       // The EXE will also link to to FINAL_SHLIB. The public dependency means
124       // that the EXE can use the headers in FINAL_SHLIB so the FINAL_SHLIB
125       // will need to appear on EXE's link line.
126       //
127       // However, if the dependency is private:
128       //   EXE -> INTERMEDIATE_SHLIB --[private]--> FINAL_SHLIB
129       // the dependency will not be propagated because INTERMEDIATE_SHLIB is
130       // not granting permission to call functions from FINAL_SHLIB. If EXE
131       // wants to use functions (and link to) FINAL_SHLIB, it will need to do
132       // so explicitly.
133       //
134       // Static libraries and source sets aren't inherited across shared
135       // library boundaries because they will be linked into the shared
136       // library. Rust dylib deps are handled above and transitive deps are
137       // resolved by the compiler.
138       const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
139       for (const auto& pair : dep_info->inherited_libs) {
140         if (pair.target()->output_type() == Target::SHARED_LIBRARY &&
141             pair.is_public()) {
142           inherited_libraries->Append(pair.target(), is_public);
143         }
144       }
145     } else if (!dep->IsFinal()) {
146       // The current target isn't linked, so propagate linked deps and
147       // libraries up the dependency tree.
148       const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
149       for (const auto& pair : dep_info->inherited_libs) {
150         // Proc macros are not linked into targets that depend on them, so do
151         // not get inherited; they are consumed by the Rust compiler and only
152         // need to be specified in --extern.
153         if (pair.target()->output_type() != Target::RUST_PROC_MACRO)
154           inherited_libraries->Append(pair.target(),
155                                       is_public && pair.is_public());
156       }
157     } else if (dep->complete_static_lib()) {
158       // Inherit only final targets through _complete_ static libraries.
159       //
160       // Inherited final libraries aren't linked into complete static
161       // libraries. They are forwarded here so that targets that depend on
162       // complete static libraries can link them in. Conversely, since
163       // complete static libraries link in non-final targets, they shouldn't be
164       // inherited.
165       const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
166       for (const auto& pair : dep_info->inherited_libs) {
167         if (pair.target()->IsFinal())
168           inherited_libraries->Append(pair.target(),
169                                       is_public && pair.is_public());
170       }
171     }
172   }
173 }
174 
ComputeRustLibs(TargetInfo * info) const175 void ResolvedTargetData::ComputeRustLibs(TargetInfo* info) const {
176   RustLibsBuilder rust_libs;
177 
178   ComputeRustLibsFor(info->deps.public_deps(), true, &rust_libs);
179   ComputeRustLibsFor(info->deps.private_deps(), false, &rust_libs);
180 
181   info->rust_inherited_libs = rust_libs.inherited.Build();
182   info->rust_inheritable_libs = rust_libs.inheritable.Build();
183   info->has_rust_libs = true;
184 }
185 
ComputeRustLibsFor(base::span<const Target * > deps,bool is_public,RustLibsBuilder * rust_libs) const186 void ResolvedTargetData::ComputeRustLibsFor(base::span<const Target*> deps,
187                                             bool is_public,
188                                             RustLibsBuilder* rust_libs) const {
189   for (const Target* dep : deps) {
190     // Collect Rust libraries that are accessible from the current target, or
191     // transitively part of the current target.
192     if (dep->output_type() == Target::STATIC_LIBRARY ||
193         dep->output_type() == Target::SHARED_LIBRARY ||
194         dep->output_type() == Target::SOURCE_SET ||
195         dep->output_type() == Target::RUST_LIBRARY ||
196         dep->output_type() == Target::GROUP || dep->copy_linkable_file()) {
197       // Here we have: `this` --[depends-on]--> `dep`
198       //
199       // The `this` target has direct access to `dep` since its a direct
200       // dependency, regardless of the edge being a public_dep or not, so we
201       // pass true for public-ness. Whereas, anything depending on `this` can
202       // only gain direct access to `dep` if the edge between `this` and `dep`
203       // is public, so we pass `is_public`.
204       //
205       // TODO(danakj): We should only need to track Rust rlibs or dylibs here,
206       // as it's used for passing to rustc with --extern. We currently track
207       // everything then drop non-Rust libs in
208       // ninja_rust_binary_target_writer.cc.
209       rust_libs->inherited.Append(dep, true);
210       rust_libs->inheritable.Append(dep, is_public);
211 
212       const TargetInfo* dep_info = GetTargetRustLibs(dep);
213       rust_libs->inherited.AppendInherited(dep_info->rust_inheritable_libs,
214                                            true);
215       rust_libs->inheritable.AppendInherited(dep_info->rust_inheritable_libs,
216                                              is_public);
217     } else if (dep->output_type() == Target::RUST_PROC_MACRO) {
218       // Proc-macros are inherited as a transitive dependency, but the things
219       // they depend on can't be used elsewhere, as the proc macro is not
220       // linked into the target (as it's only used during compilation).
221       rust_libs->inherited.Append(dep, true);
222       rust_libs->inheritable.Append(dep, is_public);
223     }
224   }
225 }
226 
ComputeSwiftValues(TargetInfo * info) const227 void ResolvedTargetData::ComputeSwiftValues(TargetInfo* info) const {
228   UniqueVector<const Target*> modules;
229   UniqueVector<const Target*> public_modules;
230   const Target* target = info->target;
231 
232   for (const Target* dep : info->deps.public_deps()) {
233     if (dep->toolchain() != target->toolchain() &&
234         !dep->toolchain()->propagates_configs()) {
235       continue;
236     }
237 
238     const TargetInfo* dep_info = GetTargetSwiftValues(dep);
239     if (dep_info->swift_values.get()) {
240       const auto& public_deps = dep_info->swift_values->public_modules;
241       modules.Append(public_deps);
242       public_modules.Append(public_deps);
243     }
244   }
245 
246   for (const Target* dep : info->deps.private_deps()) {
247     if (dep->toolchain() != target->toolchain() &&
248         !dep->toolchain()->propagates_configs()) {
249       continue;
250     }
251     const TargetInfo* dep_info = GetTargetSwiftValues(dep);
252     if (dep_info->swift_values.get()) {
253       modules.Append(dep_info->swift_values->public_modules);
254     }
255   }
256 
257   if (target->builds_swift_module())
258     public_modules.push_back(target);
259 
260   if (!modules.empty() || !public_modules.empty()) {
261     info->swift_values = std::make_unique<TargetInfo::SwiftValues>(
262         modules.release(), public_modules.release());
263   }
264   info->has_swift_values = true;
265 }
266