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