• 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	BuildLinkerConfig(ctx, android.Paths{input}, nil, nil, output)
80
81	l.outputFilePath = output
82	l.installDirPath = android.PathForModuleInstall(ctx, "etc")
83	if !proptools.BoolDefault(l.properties.Installable, true) {
84		l.SkipInstall()
85	}
86	ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
87
88	ctx.SetOutputFiles(android.Paths{l.outputFilePath}, "")
89
90	etc.SetCommonPrebuiltEtcInfo(ctx, l)
91}
92
93func BuildLinkerConfig(
94	ctx android.ModuleContext,
95	inputs android.Paths,
96	provideModules []android.ModuleProxy,
97	requireModules []android.ModuleProxy,
98	output android.WritablePath,
99) {
100	// First, convert the input json to protobuf format
101	builder := android.NewRuleBuilder(pctx, ctx)
102	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
103	cmd := builder.Command().
104		BuiltTool("conv_linker_config").
105		Flag("proto").
106		Flag("--force")
107	for _, input := range inputs {
108		cmd.FlagWithInput("-s ", input)
109	}
110	cmd.FlagWithOutput("-o ", interimOutput)
111
112	// Secondly, if there's provideLibs gathered from provideModules, append them
113	var provideLibs []string
114	for _, m := range provideModules {
115		ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider)
116		if ok && (cc.IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider)) || ccInfo.HasLlndkStubs) {
117			for _, ps := range android.OtherModuleProviderOrDefault(
118				ctx, m, android.InstallFilesProvider).PackagingSpecs {
119				provideLibs = append(provideLibs, ps.FileName())
120			}
121		}
122	}
123	provideLibs = android.FirstUniqueStrings(provideLibs)
124	sort.Strings(provideLibs)
125
126	var requireLibs []string
127	for _, m := range requireModules {
128		if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok {
129			if android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider).HasStubsVariants &&
130				!android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider).Host {
131				name := ctx.OtherModuleName(m)
132				if ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok && ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.ImplementationModuleName != nil {
133					name = *ccInfo.LinkerInfo.ImplementationModuleName
134				}
135				requireLibs = append(requireLibs, name+".so")
136			}
137		}
138	}
139
140	requireLibs = android.FirstUniqueStrings(requireLibs)
141	sort.Strings(requireLibs)
142
143	if len(provideLibs) > 0 {
144		prevOutput := interimOutput
145		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
146		builder.Command().
147			BuiltTool("conv_linker_config").
148			Flag("append").
149			FlagWithInput("-s ", prevOutput).
150			FlagWithOutput("-o ", interimOutput).
151			FlagWithArg("--key ", "provideLibs").
152			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
153		builder.Temporary(prevOutput)
154	}
155	if len(requireLibs) > 0 {
156		prevOutput := interimOutput
157		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
158		builder.Command().
159			BuiltTool("conv_linker_config").
160			Flag("append").
161			FlagWithInput("-s ", prevOutput).
162			FlagWithOutput("-o ", interimOutput).
163			FlagWithArg("--key ", "requireLibs").
164			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
165		builder.Temporary(prevOutput)
166	}
167
168	// cp to the final output
169	builder.Command().Text("cp").Input(interimOutput).Output(output)
170
171	builder.Temporary(interimOutput)
172	builder.DeleteTemporaryFiles()
173	builder.Build("conv_linker_config_"+output.String(), "Generate linker config protobuf "+output.String())
174}
175
176// linker_config generates protobuf file from json file. This protobuf file will be used from
177// linkerconfig while generating ld.config.txt. Format of this file can be found from
178// https://android.googlesource.com/platform/system/linkerconfig/+/main/README.md
179func LinkerConfigFactory() android.Module {
180	m := &linkerConfig{}
181	m.AddProperties(&m.properties)
182	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
183	return m
184}
185
186func (l *linkerConfig) AndroidMkEntries() []android.AndroidMkEntries {
187	installable := proptools.BoolDefault(l.properties.Installable, true)
188	return []android.AndroidMkEntries{android.AndroidMkEntries{
189		Class:      "ETC",
190		OutputFile: android.OptionalPathForPath(l.outputFilePath),
191		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
192			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
193				entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.String())
194				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.outputFilePath.Base())
195				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !installable)
196			},
197		},
198	}}
199}
200