• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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	input android.Path, 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	builder.Command().
99		BuiltTool("conv_linker_config").
100		Flag("proto").
101		FlagWithInput("-s ", input).
102		FlagWithOutput("-o ", interimOutput)
103
104	// Secondly, if there's provideLibs gathered from provideModules, append them
105	var provideLibs []string
106	for _, m := range provideModules {
107		if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
108			for _, ps := range c.PackagingSpecs() {
109				provideLibs = append(provideLibs, ps.FileName())
110			}
111		}
112	}
113	provideLibs = android.FirstUniqueStrings(provideLibs)
114	sort.Strings(provideLibs)
115
116	var requireLibs []string
117	for _, m := range requireModules {
118		if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
119			requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
120		}
121	}
122
123	requireLibs = android.FirstUniqueStrings(requireLibs)
124	sort.Strings(requireLibs)
125
126	if len(provideLibs) > 0 {
127		prevOutput := interimOutput
128		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
129		builder.Command().
130			BuiltTool("conv_linker_config").
131			Flag("append").
132			FlagWithInput("-s ", prevOutput).
133			FlagWithOutput("-o ", interimOutput).
134			FlagWithArg("--key ", "provideLibs").
135			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
136		builder.Temporary(prevOutput)
137	}
138	if len(requireLibs) > 0 {
139		prevOutput := interimOutput
140		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
141		builder.Command().
142			BuiltTool("conv_linker_config").
143			Flag("append").
144			FlagWithInput("-s ", prevOutput).
145			FlagWithOutput("-o ", interimOutput).
146			FlagWithArg("--key ", "requireLibs").
147			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
148		builder.Temporary(prevOutput)
149	}
150
151	// cp to the final output
152	builder.Command().Text("cp").Input(interimOutput).Output(output)
153
154	builder.Temporary(interimOutput)
155	builder.DeleteTemporaryFiles()
156}
157
158// linker_config generates protobuf file from json file. This protobuf file will be used from
159// linkerconfig while generating ld.config.txt. Format of this file can be found from
160// https://android.googlesource.com/platform/system/linkerconfig/+/main/README.md
161func LinkerConfigFactory() android.Module {
162	m := &linkerConfig{}
163	m.AddProperties(&m.properties)
164	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
165	return m
166}
167
168func (l *linkerConfig) AndroidMkEntries() []android.AndroidMkEntries {
169	installable := proptools.BoolDefault(l.properties.Installable, true)
170	return []android.AndroidMkEntries{android.AndroidMkEntries{
171		Class:      "ETC",
172		OutputFile: android.OptionalPathForPath(l.outputFilePath),
173		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
174			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
175				entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.String())
176				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.outputFilePath.Base())
177				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !installable)
178			},
179		},
180	}}
181}
182