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