• 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	"fmt"
19	"sort"
20	"strings"
21
22	"github.com/google/blueprint/proptools"
23
24	"android/soong/android"
25	"android/soong/bazel"
26	"android/soong/cc"
27	"android/soong/etc"
28)
29
30var (
31	pctx = android.NewPackageContext("android/soong/linkerconfig")
32)
33
34func init() {
35	pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
36	registerLinkerConfigBuildComponent(android.InitRegistrationContext)
37}
38
39func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) {
40	ctx.RegisterModuleType("linker_config", LinkerConfigFactory)
41}
42
43type linkerConfigProperties struct {
44	// source linker configuration property file
45	Src *string `android:"path"`
46
47	// If set to true, allow module to be installed to one of the partitions.
48	// Default value is true.
49	// Installable should be marked as false for APEX configuration to avoid
50	// conflicts of configuration on /system/etc directory.
51	Installable *bool
52}
53
54type linkerConfig struct {
55	android.ModuleBase
56	android.BazelModuleBase
57	properties linkerConfigProperties
58
59	outputFilePath android.OutputPath
60	installDirPath android.InstallPath
61}
62
63// Implement PrebuiltEtcModule interface to fit in APEX prebuilt list.
64var _ etc.PrebuiltEtcModule = (*linkerConfig)(nil)
65
66func (l *linkerConfig) BaseDir() string {
67	return "etc"
68}
69
70func (l *linkerConfig) SubDir() string {
71	return ""
72}
73
74func (l *linkerConfig) OutputFile() android.OutputPath {
75	return l.outputFilePath
76}
77
78var _ android.OutputFileProducer = (*linkerConfig)(nil)
79
80func (l *linkerConfig) OutputFiles(tag string) (android.Paths, error) {
81	switch tag {
82	case "":
83		return android.Paths{l.outputFilePath}, nil
84	default:
85		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
86	}
87}
88
89func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
90	input := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
91	output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
92
93	builder := android.NewRuleBuilder(pctx, ctx)
94	BuildLinkerConfig(ctx, builder, input, nil, output)
95	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
96
97	l.outputFilePath = output
98	l.installDirPath = android.PathForModuleInstall(ctx, "etc")
99	if !proptools.BoolDefault(l.properties.Installable, true) {
100		l.SkipInstall()
101	}
102	ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
103}
104
105type linkerConfigAttributes struct {
106	Src bazel.LabelAttribute
107}
108
109func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
110	if l.properties.Src == nil {
111		ctx.PropertyErrorf("src", "empty src is not supported")
112		return
113	}
114	src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src)
115	targetModuleProperties := bazel.BazelTargetModuleProperties{
116		Rule_class:        "linker_config",
117		Bzl_load_location: "//build/bazel/rules:linker_config.bzl",
118	}
119	ctx.CreateBazelTargetModule(
120		targetModuleProperties,
121		android.CommonAttributes{Name: l.Name()},
122		&linkerConfigAttributes{
123			Src: bazel.LabelAttribute{Value: &src},
124		})
125}
126
127func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
128	input android.Path, otherModules []android.Module, output android.OutputPath) {
129
130	// First, convert the input json to protobuf format
131	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
132	builder.Command().
133		BuiltTool("conv_linker_config").
134		Flag("proto").
135		FlagWithInput("-s ", input).
136		FlagWithOutput("-o ", interimOutput)
137
138	// Secondly, if there's provideLibs gathered from otherModules, append them
139	var provideLibs []string
140	for _, m := range otherModules {
141		if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
142			for _, ps := range c.PackagingSpecs() {
143				provideLibs = append(provideLibs, ps.FileName())
144			}
145		}
146	}
147	provideLibs = android.FirstUniqueStrings(provideLibs)
148	sort.Strings(provideLibs)
149	if len(provideLibs) > 0 {
150		builder.Command().
151			BuiltTool("conv_linker_config").
152			Flag("append").
153			FlagWithInput("-s ", interimOutput).
154			FlagWithOutput("-o ", output).
155			FlagWithArg("--key ", "provideLibs").
156			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
157	} else {
158		// If nothing to add, just cp to the final output
159		builder.Command().Text("cp").Input(interimOutput).Output(output)
160	}
161	builder.Temporary(interimOutput)
162	builder.DeleteTemporaryFiles()
163}
164
165// linker_config generates protobuf file from json file. This protobuf file will be used from
166// linkerconfig while generating ld.config.txt. Format of this file can be found from
167// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
168func LinkerConfigFactory() android.Module {
169	m := &linkerConfig{}
170	m.AddProperties(&m.properties)
171	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
172	android.InitBazelModule(m)
173	return m
174}
175
176func (l *linkerConfig) AndroidMkEntries() []android.AndroidMkEntries {
177	installable := proptools.BoolDefault(l.properties.Installable, true)
178	return []android.AndroidMkEntries{android.AndroidMkEntries{
179		Class:      "ETC",
180		OutputFile: android.OptionalPathForPath(l.outputFilePath),
181		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
182			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
183				entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.String())
184				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.outputFilePath.Base())
185				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !installable)
186			},
187		},
188	}}
189}
190