xref: /aosp_15_r20/system/linkerconfig/modules/section.cc (revision e5eeaa8e05bc25a862c0c861bda7c8a6bfb42dad)
1*e5eeaa8eSAndroid Build Coastguard Worker /*
2*e5eeaa8eSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*e5eeaa8eSAndroid Build Coastguard Worker  *
4*e5eeaa8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e5eeaa8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e5eeaa8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e5eeaa8eSAndroid Build Coastguard Worker  *
8*e5eeaa8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e5eeaa8eSAndroid Build Coastguard Worker  *
10*e5eeaa8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e5eeaa8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e5eeaa8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e5eeaa8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e5eeaa8eSAndroid Build Coastguard Worker  * limitations under the License.
15*e5eeaa8eSAndroid Build Coastguard Worker  */
16*e5eeaa8eSAndroid Build Coastguard Worker #include "linkerconfig/section.h"
17*e5eeaa8eSAndroid Build Coastguard Worker 
18*e5eeaa8eSAndroid Build Coastguard Worker #include <algorithm>
19*e5eeaa8eSAndroid Build Coastguard Worker #include <functional>
20*e5eeaa8eSAndroid Build Coastguard Worker #include <unordered_map>
21*e5eeaa8eSAndroid Build Coastguard Worker #include <utility>
22*e5eeaa8eSAndroid Build Coastguard Worker 
23*e5eeaa8eSAndroid Build Coastguard Worker #include <android-base/result.h>
24*e5eeaa8eSAndroid Build Coastguard Worker #include <android-base/strings.h>
25*e5eeaa8eSAndroid Build Coastguard Worker 
26*e5eeaa8eSAndroid Build Coastguard Worker #include "linkerconfig/environment.h"
27*e5eeaa8eSAndroid Build Coastguard Worker #include "linkerconfig/log.h"
28*e5eeaa8eSAndroid Build Coastguard Worker 
29*e5eeaa8eSAndroid Build Coastguard Worker using android::base::Join;
30*e5eeaa8eSAndroid Build Coastguard Worker using android::base::Result;
31*e5eeaa8eSAndroid Build Coastguard Worker 
32*e5eeaa8eSAndroid Build Coastguard Worker namespace android {
33*e5eeaa8eSAndroid Build Coastguard Worker namespace linkerconfig {
34*e5eeaa8eSAndroid Build Coastguard Worker namespace modules {
35*e5eeaa8eSAndroid Build Coastguard Worker 
WriteConfig(ConfigWriter & writer) const36*e5eeaa8eSAndroid Build Coastguard Worker void Section::WriteConfig(ConfigWriter& writer) const {
37*e5eeaa8eSAndroid Build Coastguard Worker   writer.WriteLine("[" + name_ + "]");
38*e5eeaa8eSAndroid Build Coastguard Worker 
39*e5eeaa8eSAndroid Build Coastguard Worker   if (namespaces_.size() > 1) {
40*e5eeaa8eSAndroid Build Coastguard Worker     std::vector<std::string> additional_namespaces;
41*e5eeaa8eSAndroid Build Coastguard Worker     for (const auto& ns : namespaces_) {
42*e5eeaa8eSAndroid Build Coastguard Worker       if (ns.GetName() != "default") {
43*e5eeaa8eSAndroid Build Coastguard Worker         additional_namespaces.push_back(ns.GetName());
44*e5eeaa8eSAndroid Build Coastguard Worker       }
45*e5eeaa8eSAndroid Build Coastguard Worker     }
46*e5eeaa8eSAndroid Build Coastguard Worker     writer.WriteLine("additional.namespaces = " +
47*e5eeaa8eSAndroid Build Coastguard Worker                      Join(additional_namespaces, ','));
48*e5eeaa8eSAndroid Build Coastguard Worker   }
49*e5eeaa8eSAndroid Build Coastguard Worker 
50*e5eeaa8eSAndroid Build Coastguard Worker   for (const auto& ns : namespaces_) {
51*e5eeaa8eSAndroid Build Coastguard Worker     ns.WriteConfig(writer);
52*e5eeaa8eSAndroid Build Coastguard Worker   }
53*e5eeaa8eSAndroid Build Coastguard Worker }
54*e5eeaa8eSAndroid Build Coastguard Worker 
ShouldFailOnMissingDeps(const BaseContext & ctx,const Namespace & ns)55*e5eeaa8eSAndroid Build Coastguard Worker static bool ShouldFailOnMissingDeps(const BaseContext& ctx,
56*e5eeaa8eSAndroid Build Coastguard Worker                                     const Namespace& ns) {
57*e5eeaa8eSAndroid Build Coastguard Worker   if (!ctx.IsStrictMode()) {
58*e5eeaa8eSAndroid Build Coastguard Worker     return false;
59*e5eeaa8eSAndroid Build Coastguard Worker   }
60*e5eeaa8eSAndroid Build Coastguard Worker   // When generating for a target apex, "--strict" is applied to only the namespace
61*e5eeaa8eSAndroid Build Coastguard Worker   // for the apex to avoid failing due to missing deps in other namespaces
62*e5eeaa8eSAndroid Build Coastguard Worker   if (!ctx.GetTargetApex().empty()) {
63*e5eeaa8eSAndroid Build Coastguard Worker     return ns.GetName() == "default" || ns.GetName() == ctx.GetTargetApex();
64*e5eeaa8eSAndroid Build Coastguard Worker   }
65*e5eeaa8eSAndroid Build Coastguard Worker   return true;
66*e5eeaa8eSAndroid Build Coastguard Worker }
67*e5eeaa8eSAndroid Build Coastguard Worker 
68*e5eeaa8eSAndroid Build Coastguard Worker // Resolve() resolves require/provide constraints between namespaces.
69*e5eeaa8eSAndroid Build Coastguard Worker // When foo.AddProvides({"libfoo.so"}) and bar.AddRequires({"libfoo.so"}),
70*e5eeaa8eSAndroid Build Coastguard Worker // then Resolve() creates a linke between foo and bar:
71*e5eeaa8eSAndroid Build Coastguard Worker //   foo.GetLink("bar").AddSharedLib({"libfoo.so"}).
72*e5eeaa8eSAndroid Build Coastguard Worker //
73*e5eeaa8eSAndroid Build Coastguard Worker // When a referenced lib is not provided by existing namespaces,
74*e5eeaa8eSAndroid Build Coastguard Worker // it searches the lib in available apexes <apex_providers>
75*e5eeaa8eSAndroid Build Coastguard Worker // and available aliases <lib_providers>, If found, new namespace is added.
Resolve(const BaseContext & ctx,const LibProviders & lib_providers)76*e5eeaa8eSAndroid Build Coastguard Worker void Section::Resolve(const BaseContext& ctx,
77*e5eeaa8eSAndroid Build Coastguard Worker                       const LibProviders& lib_providers) {
78*e5eeaa8eSAndroid Build Coastguard Worker   // libs provided by existing namespaces
79*e5eeaa8eSAndroid Build Coastguard Worker   std::unordered_map<std::string, std::string> providers;
80*e5eeaa8eSAndroid Build Coastguard Worker   for (auto& ns : namespaces_) {
81*e5eeaa8eSAndroid Build Coastguard Worker     for (const auto& lib : ns.GetProvides()) {
82*e5eeaa8eSAndroid Build Coastguard Worker       if (auto iter = providers.find(lib); iter != providers.end()) {
83*e5eeaa8eSAndroid Build Coastguard Worker         LOG(android::base::FATAL)
84*e5eeaa8eSAndroid Build Coastguard Worker             << fmt::format("duplicate: {} is provided by {} and {} in [{}]",
85*e5eeaa8eSAndroid Build Coastguard Worker                            lib,
86*e5eeaa8eSAndroid Build Coastguard Worker                            iter->second,
87*e5eeaa8eSAndroid Build Coastguard Worker                            ns.GetName(),
88*e5eeaa8eSAndroid Build Coastguard Worker                            name_);
89*e5eeaa8eSAndroid Build Coastguard Worker       } else {
90*e5eeaa8eSAndroid Build Coastguard Worker         providers[lib] = ns.GetName();
91*e5eeaa8eSAndroid Build Coastguard Worker       }
92*e5eeaa8eSAndroid Build Coastguard Worker     }
93*e5eeaa8eSAndroid Build Coastguard Worker   }
94*e5eeaa8eSAndroid Build Coastguard Worker 
95*e5eeaa8eSAndroid Build Coastguard Worker   // libs provided by apexes
96*e5eeaa8eSAndroid Build Coastguard Worker   const auto& apex_providers = ctx.GetApexModuleMap();
97*e5eeaa8eSAndroid Build Coastguard Worker 
98*e5eeaa8eSAndroid Build Coastguard Worker   // add a new namespace if not found
99*e5eeaa8eSAndroid Build Coastguard Worker   auto add_namespace = [&](auto name, auto builder) {
100*e5eeaa8eSAndroid Build Coastguard Worker     for (auto& ns : namespaces_) {
101*e5eeaa8eSAndroid Build Coastguard Worker       if (ns.GetName() == name) {
102*e5eeaa8eSAndroid Build Coastguard Worker         // it's there, we don't need to create a new one.
103*e5eeaa8eSAndroid Build Coastguard Worker         return;
104*e5eeaa8eSAndroid Build Coastguard Worker       }
105*e5eeaa8eSAndroid Build Coastguard Worker     }
106*e5eeaa8eSAndroid Build Coastguard Worker     auto new_ns = builder();
107*e5eeaa8eSAndroid Build Coastguard Worker     // Update providing library map from the new namespace
108*e5eeaa8eSAndroid Build Coastguard Worker     for (const auto& new_lib : new_ns.GetProvides()) {
109*e5eeaa8eSAndroid Build Coastguard Worker       if (providers.find(new_lib) == providers.end()) {
110*e5eeaa8eSAndroid Build Coastguard Worker         providers[new_lib] = new_ns.GetName();
111*e5eeaa8eSAndroid Build Coastguard Worker       }
112*e5eeaa8eSAndroid Build Coastguard Worker     }
113*e5eeaa8eSAndroid Build Coastguard Worker     namespaces_.push_back(std::move(new_ns));
114*e5eeaa8eSAndroid Build Coastguard Worker   };
115*e5eeaa8eSAndroid Build Coastguard Worker 
116*e5eeaa8eSAndroid Build Coastguard Worker   // Reserve enough space for namespace vector which can be increased maximum as
117*e5eeaa8eSAndroid Build Coastguard Worker   // much as potential providers. Appending new namespaces without reserving
118*e5eeaa8eSAndroid Build Coastguard Worker   // enough space from iteration can crash the process.
119*e5eeaa8eSAndroid Build Coastguard Worker   namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size() +
120*e5eeaa8eSAndroid Build Coastguard Worker                       lib_providers.size());
121*e5eeaa8eSAndroid Build Coastguard Worker 
122*e5eeaa8eSAndroid Build Coastguard Worker   auto iter = namespaces_.begin();
123*e5eeaa8eSAndroid Build Coastguard Worker   do {
124*e5eeaa8eSAndroid Build Coastguard Worker     auto& ns = *iter;
125*e5eeaa8eSAndroid Build Coastguard Worker     for (const auto& lib : ns.GetRequires()) {
126*e5eeaa8eSAndroid Build Coastguard Worker       // Search the required library in existing namespaces first <providers>,
127*e5eeaa8eSAndroid Build Coastguard Worker       // then the available apexes <apex_providers>,
128*e5eeaa8eSAndroid Build Coastguard Worker       // then the available aliases <lib_providers>
129*e5eeaa8eSAndroid Build Coastguard Worker       if (auto it = providers.find(lib); it != providers.end()) {
130*e5eeaa8eSAndroid Build Coastguard Worker         ns.GetLink(it->second).AddSharedLib(lib);
131*e5eeaa8eSAndroid Build Coastguard Worker       } else if (auto it = apex_providers.find(lib); it != apex_providers.end()) {
132*e5eeaa8eSAndroid Build Coastguard Worker         const auto& apex_info = it->second.get();
133*e5eeaa8eSAndroid Build Coastguard Worker         ns.GetLink(apex_info.namespace_name).AddSharedLib(lib);
134*e5eeaa8eSAndroid Build Coastguard Worker         // Add a new namespace for the apex
135*e5eeaa8eSAndroid Build Coastguard Worker         add_namespace(apex_info.namespace_name, [&]() {
136*e5eeaa8eSAndroid Build Coastguard Worker           return ctx.BuildApexNamespace(apex_info, false);
137*e5eeaa8eSAndroid Build Coastguard Worker         });
138*e5eeaa8eSAndroid Build Coastguard Worker       } else if (auto it = lib_providers.find(lib); it != lib_providers.end()) {
139*e5eeaa8eSAndroid Build Coastguard Worker         for (const auto& provider : it->second) {
140*e5eeaa8eSAndroid Build Coastguard Worker           // Alias is expanded to <shared_libs>.
141*e5eeaa8eSAndroid Build Coastguard Worker           // For example, ":vndk" is expanded to the list of VNDK-Core/VNDK-Sp libraries
142*e5eeaa8eSAndroid Build Coastguard Worker           std::visit([&](auto&& mod) { mod.Apply(ns.GetLink(provider.ns)); },
143*e5eeaa8eSAndroid Build Coastguard Worker                      provider.link_modifier);
144*e5eeaa8eSAndroid Build Coastguard Worker           // Add a new namespace for the alias
145*e5eeaa8eSAndroid Build Coastguard Worker           add_namespace(provider.ns, provider.ns_builder);
146*e5eeaa8eSAndroid Build Coastguard Worker         }
147*e5eeaa8eSAndroid Build Coastguard Worker       } else if (ShouldFailOnMissingDeps(ctx, ns)) {
148*e5eeaa8eSAndroid Build Coastguard Worker         LOG(FATAL) << fmt::format(
149*e5eeaa8eSAndroid Build Coastguard Worker             "not found: {} is required by {} in [{}]", lib, ns.GetName(), name_);
150*e5eeaa8eSAndroid Build Coastguard Worker       }
151*e5eeaa8eSAndroid Build Coastguard Worker     }
152*e5eeaa8eSAndroid Build Coastguard Worker     iter++;
153*e5eeaa8eSAndroid Build Coastguard Worker   } while (iter != namespaces_.end());
154*e5eeaa8eSAndroid Build Coastguard Worker 
155*e5eeaa8eSAndroid Build Coastguard Worker   std::sort(namespaces_.begin(),
156*e5eeaa8eSAndroid Build Coastguard Worker             namespaces_.end(),
157*e5eeaa8eSAndroid Build Coastguard Worker             [](const auto& lhs, const auto& rhs) -> bool {
158*e5eeaa8eSAndroid Build Coastguard Worker               // make "default" a smallest one
159*e5eeaa8eSAndroid Build Coastguard Worker               if (lhs.GetName() == "default") return true;
160*e5eeaa8eSAndroid Build Coastguard Worker               if (rhs.GetName() == "default") return false;
161*e5eeaa8eSAndroid Build Coastguard Worker               return lhs.GetName() < rhs.GetName();
162*e5eeaa8eSAndroid Build Coastguard Worker             });
163*e5eeaa8eSAndroid Build Coastguard Worker }
164*e5eeaa8eSAndroid Build Coastguard Worker 
GetNamespace(const std::string & namespace_name)165*e5eeaa8eSAndroid Build Coastguard Worker Namespace* Section::GetNamespace(const std::string& namespace_name) {
166*e5eeaa8eSAndroid Build Coastguard Worker   for (auto& ns : namespaces_) {
167*e5eeaa8eSAndroid Build Coastguard Worker     if (ns.GetName() == namespace_name) {
168*e5eeaa8eSAndroid Build Coastguard Worker       return &ns;
169*e5eeaa8eSAndroid Build Coastguard Worker     }
170*e5eeaa8eSAndroid Build Coastguard Worker   }
171*e5eeaa8eSAndroid Build Coastguard Worker 
172*e5eeaa8eSAndroid Build Coastguard Worker   return nullptr;
173*e5eeaa8eSAndroid Build Coastguard Worker }
174*e5eeaa8eSAndroid Build Coastguard Worker 
GetName()175*e5eeaa8eSAndroid Build Coastguard Worker std::string Section::GetName() {
176*e5eeaa8eSAndroid Build Coastguard Worker   return name_;
177*e5eeaa8eSAndroid Build Coastguard Worker }
178*e5eeaa8eSAndroid Build Coastguard Worker }  // namespace modules
179*e5eeaa8eSAndroid Build Coastguard Worker }  // namespace linkerconfig
180*e5eeaa8eSAndroid Build Coastguard Worker }  // namespace android
181