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