xref: /aosp_15_r20/build/soong/linkerconfig/linkerconfig.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package linkerconfig
16
17import (
18	"sort"
19	"strings"
20
21	"github.com/google/blueprint/proptools"
22
23	"android/soong/android"
24	"android/soong/cc"
25	"android/soong/etc"
26)
27
28var (
29	pctx = android.NewPackageContext("android/soong/linkerconfig")
30)
31
32func init() {
33	pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
34	registerLinkerConfigBuildComponent(android.InitRegistrationContext)
35}
36
37func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) {
38	ctx.RegisterModuleType("linker_config", LinkerConfigFactory)
39}
40
41type linkerConfigProperties struct {
42	// source linker configuration property file
43	Src *string `android:"path"`
44
45	// If set to true, allow module to be installed to one of the partitions.
46	// Default value is true.
47	// Installable should be marked as false for APEX configuration to avoid
48	// conflicts of configuration on /system/etc directory.
49	Installable *bool
50}
51
52type linkerConfig struct {
53	android.ModuleBase
54	properties linkerConfigProperties
55
56	outputFilePath android.OutputPath
57	installDirPath android.InstallPath
58}
59
60// Implement PrebuiltEtcModule interface to fit in APEX prebuilt list.
61var _ etc.PrebuiltEtcModule = (*linkerConfig)(nil)
62
63func (l *linkerConfig) BaseDir() string {
64	return "etc"
65}
66
67func (l *linkerConfig) SubDir() string {
68	return ""
69}
70
71func (l *linkerConfig) OutputFile() android.OutputPath {
72	return l.outputFilePath
73}
74
75func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
76	input := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
77	output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
78
79	builder := android.NewRuleBuilder(pctx, ctx)
80	BuildLinkerConfig(ctx, builder, android.Paths{input}, nil, nil, output)
81	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
82
83	l.outputFilePath = output
84	l.installDirPath = android.PathForModuleInstall(ctx, "etc")
85	if !proptools.BoolDefault(l.properties.Installable, true) {
86		l.SkipInstall()
87	}
88	ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
89
90	ctx.SetOutputFiles(android.Paths{l.outputFilePath}, "")
91}
92
93func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
94	inputs android.Paths, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) {
95
96	// First, convert the input json to protobuf format
97	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
98	cmd := builder.Command().
99		BuiltTool("conv_linker_config").
100		Flag("proto").
101		Flag("--force")
102	for _, input := range inputs {
103		cmd.FlagWithInput("-s ", input)
104	}
105	cmd.FlagWithOutput("-o ", interimOutput)
106
107	// Secondly, if there's provideLibs gathered from provideModules, append them
108	var provideLibs []string
109	for _, m := range provideModules {
110		if c, ok := m.(*cc.Module); ok && (cc.IsStubTarget(c) || c.HasLlndkStubs()) {
111			for _, ps := range android.OtherModuleProviderOrDefault(
112				ctx, c, android.InstallFilesProvider).PackagingSpecs {
113				provideLibs = append(provideLibs, ps.FileName())
114			}
115		}
116	}
117	provideLibs = android.FirstUniqueStrings(provideLibs)
118	sort.Strings(provideLibs)
119
120	var requireLibs []string
121	for _, m := range requireModules {
122		if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
123			requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
124		}
125	}
126
127	requireLibs = android.FirstUniqueStrings(requireLibs)
128	sort.Strings(requireLibs)
129
130	if len(provideLibs) > 0 {
131		prevOutput := interimOutput
132		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
133		builder.Command().
134			BuiltTool("conv_linker_config").
135			Flag("append").
136			FlagWithInput("-s ", prevOutput).
137			FlagWithOutput("-o ", interimOutput).
138			FlagWithArg("--key ", "provideLibs").
139			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
140		builder.Temporary(prevOutput)
141	}
142	if len(requireLibs) > 0 {
143		prevOutput := interimOutput
144		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
145		builder.Command().
146			BuiltTool("conv_linker_config").
147			Flag("append").
148			FlagWithInput("-s ", prevOutput).
149			FlagWithOutput("-o ", interimOutput).
150			FlagWithArg("--key ", "requireLibs").
151			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
152		builder.Temporary(prevOutput)
153	}
154
155	// cp to the final output
156	builder.Command().Text("cp").Input(interimOutput).Output(output)
157
158	builder.Temporary(interimOutput)
159	builder.DeleteTemporaryFiles()
160}
161
162// linker_config generates protobuf file from json file. This protobuf file will be used from
163// linkerconfig while generating ld.config.txt. Format of this file can be found from
164// https://android.googlesource.com/platform/system/linkerconfig/+/main/README.md
165func LinkerConfigFactory() android.Module {
166	m := &linkerConfig{}
167	m.AddProperties(&m.properties)
168	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
169	return m
170}
171
172func (l *linkerConfig) AndroidMkEntries() []android.AndroidMkEntries {
173	installable := proptools.BoolDefault(l.properties.Installable, true)
174	return []android.AndroidMkEntries{android.AndroidMkEntries{
175		Class:      "ETC",
176		OutputFile: android.OptionalPathForPath(l.outputFilePath),
177		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
178			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
179				entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.String())
180				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.outputFilePath.Base())
181				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !installable)
182			},
183		},
184	}}
185}
186