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