Merge "android_system_image that generates linker.config.pb" am: 08bd0dd8c5

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1679107

Change-Id: I7731388b1d0eee0a1319fe00c05d6b6c18870835
This commit is contained in:
Jiyong Park 2021-04-21 05:20:48 +00:00 committed by Automerger Merge Worker
commit f8fa18e066
7 changed files with 192 additions and 21 deletions

View File

@ -30,7 +30,7 @@ type stubLibraries struct {
}
// Check if the module defines stub, or itself is stub
func isStubTarget(m *Module) bool {
func IsStubTarget(m *Module) bool {
if m.IsStubs() || m.HasStubsVariants() {
return true
}
@ -61,7 +61,7 @@ func (s *stubLibraries) GenerateBuildActions(ctx android.SingletonContext) {
// Visit all generated soong modules and store stub library file names.
ctx.VisitAllModules(func(module android.Module) {
if m, ok := module.(*Module); ok {
if isStubTarget(m) {
if IsStubTarget(m) {
if name := getInstalledFileName(m); name != "" {
s.stubLibraryMap[name] = true
}

View File

@ -9,11 +9,13 @@ bootstrap_go_package {
"blueprint",
"soong",
"soong-android",
"soong-linkerconfig",
],
srcs: [
"bootimg.go",
"filesystem.go",
"logical_partition.go",
"system_image.go",
"vbmeta.go",
"testing.go",
],

View File

@ -31,6 +31,7 @@ func init() {
func registerBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_filesystem", filesystemFactory)
ctx.RegisterModuleType("android_system_image", systemImageFactory)
}
type filesystem struct {
@ -39,6 +40,9 @@ type filesystem struct {
properties filesystemProperties
// Function that builds extra files under the root directory and returns the files
buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
output android.OutputPath
installDir android.InstallPath
}
@ -87,10 +91,14 @@ type filesystemProperties struct {
// partitions like system.img. For example, cc_library modules are placed under ./lib[64] directory.
func filesystemFactory() android.Module {
module := &filesystem{}
initFilesystemModule(module)
return module
}
func initFilesystemModule(module *filesystem) {
module.AddProperties(&module.properties)
android.InitPackageModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
var dependencyTag = struct {
@ -148,7 +156,7 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
ctx.InstallFile(f.installDir, f.installFileName(), f.output)
}
// root zip will contain stuffs like dirs or symlinks.
// root zip will contain extra files/dirs that are not from the `deps` property.
func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath {
rootDir := android.PathForModuleGen(ctx, "root").OutputPath
builder := android.NewRuleBuilder(pctx, ctx)
@ -182,15 +190,34 @@ func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath
builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
}
zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
// create extra files if there's any
rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
var extraFiles android.OutputPaths
if f.buildExtraFiles != nil {
extraFiles = f.buildExtraFiles(ctx, rootForExtraFiles)
for _, f := range extraFiles {
rel, _ := filepath.Rel(rootForExtraFiles.String(), f.String())
if strings.HasPrefix(rel, "..") {
panic(fmt.Errorf("%q is not under %q\n", f, rootForExtraFiles))
}
}
}
builder.Command().
BuiltTool("soong_zip").
FlagWithOutput("-o ", zipOut).
// Zip them all
zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
zipCommand := builder.Command().BuiltTool("soong_zip")
zipCommand.FlagWithOutput("-o ", zipOut).
FlagWithArg("-C ", rootDir.String()).
Flag("-L 0"). // no compression because this will be unzipped soon
FlagWithArg("-D ", rootDir.String()).
Flag("-d") // include empty directories
if len(extraFiles) > 0 {
zipCommand.FlagWithArg("-C ", rootForExtraFiles.String())
for _, f := range extraFiles {
zipCommand.FlagWithInput("-f ", f)
}
}
builder.Command().Text("rm -rf").Text(rootDir.String())
builder.Build("zip_root", fmt.Sprintf("zipping root contents for %s", ctx.ModuleName()))

View File

@ -19,6 +19,7 @@ import (
"testing"
"android/soong/android"
"android/soong/cc"
)
func TestMain(m *testing.M) {
@ -27,6 +28,7 @@ func TestMain(m *testing.M) {
var fixture = android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
cc.PrepareForIntegrationTestWithCc,
PrepareForTestWithFilesystemBuildComponents,
)
@ -40,3 +42,35 @@ func TestFileSystemDeps(t *testing.T) {
// produces "myfilesystem.img"
result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
}
func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
result := fixture.RunTestWithBp(t, `
android_system_image {
name: "myfilesystem",
deps: [
"libfoo",
"libbar",
],
linker_config_src: "linker.config.json",
}
cc_library {
name: "libfoo",
stubs: {
symbol_file: "libfoo.map.txt",
},
}
cc_library {
name: "libbar",
}
`)
module := result.ModuleForTests("myfilesystem", "android_common")
output := module.Output("system/etc/linker.config.pb")
android.AssertStringDoesContain(t, "linker.config.pb should have libfoo",
output.RuleParams.Command, "libfoo.so")
android.AssertStringDoesNotContain(t, "linker.config.pb should not have libbar",
output.RuleParams.Command, "libbar.so")
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package filesystem
import (
"android/soong/android"
"android/soong/linkerconfig"
)
type systemImage struct {
filesystem
properties systemImageProperties
}
type systemImageProperties struct {
// Path to the input linker config json file.
Linker_config_src *string
}
// android_system_image is a specialization of android_filesystem for the 'system' partition.
// Currently, the only difference is the inclusion of linker.config.pb file which specifies
// the provided and the required libraries to and from APEXes.
func systemImageFactory() android.Module {
module := &systemImage{}
module.AddProperties(&module.properties)
module.filesystem.buildExtraFiles = module.buildExtraFiles
initFilesystemModule(&module.filesystem)
return module
}
func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
lc := s.buildLinkerConfigFile(ctx, root)
// Add more files if needed
return []android.OutputPath{lc}
}
func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root android.OutputPath) android.OutputPath {
input := android.PathForModuleSrc(ctx, android.String(s.properties.Linker_config_src))
output := root.Join(ctx, "system", "etc", "linker.config.pb")
var otherModules []android.Module
ctx.WalkDeps(func(child, parent android.Module) bool {
// Don't track direct dependencies that aren't not packaged
if parent == s {
if pi, ok := ctx.OtherModuleDependencyTag(child).(android.PackagingItem); !ok || !pi.IsPackagingItem() {
return false
}
}
otherModules = append(otherModules, child)
return true
})
builder := android.NewRuleBuilder(pctx, ctx)
linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
return output
}

View File

@ -9,6 +9,7 @@ bootstrap_go_package {
"blueprint",
"soong",
"soong-android",
"soong-cc",
"soong-etc",
],
srcs: [

View File

@ -15,11 +15,15 @@
package linkerconfig
import (
"android/soong/android"
"android/soong/etc"
"fmt"
"sort"
"strings"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/etc"
)
var (
@ -81,24 +85,59 @@ func (l *linkerConfig) OutputFiles(tag string) (android.Paths, error) {
}
func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
inputFile := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
l.outputFilePath = android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
l.installDirPath = android.PathForModuleInstall(ctx, "etc")
linkerConfigRule := android.NewRuleBuilder(pctx, ctx)
linkerConfigRule.Command().
BuiltTool("conv_linker_config").
Flag("proto").
FlagWithInput("-s ", inputFile).
FlagWithOutput("-o ", l.outputFilePath)
linkerConfigRule.Build("conv_linker_config",
"Generate linker config protobuf "+l.outputFilePath.String())
input := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
builder := android.NewRuleBuilder(pctx, ctx)
BuildLinkerConfig(ctx, builder, input, nil, output)
builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
l.outputFilePath = output
l.installDirPath = android.PathForModuleInstall(ctx, "etc")
if !proptools.BoolDefault(l.properties.Installable, true) {
l.SkipInstall()
}
ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
input android.Path, otherModules []android.Module, output android.OutputPath) {
// First, convert the input json to protobuf format
interimOutput := android.PathForModuleOut(ctx, "temp.pb")
builder.Command().
BuiltTool("conv_linker_config").
Flag("proto").
FlagWithInput("-s ", input).
FlagWithOutput("-o ", interimOutput)
// Secondly, if there's provideLibs gathered from otherModules, append them
var provideLibs []string
for _, m := range otherModules {
if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
for _, ps := range c.PackagingSpecs() {
provideLibs = append(provideLibs, ps.FileName())
}
}
}
provideLibs = android.FirstUniqueStrings(provideLibs)
sort.Strings(provideLibs)
if len(provideLibs) > 0 {
builder.Command().
BuiltTool("conv_linker_config").
Flag("append").
FlagWithInput("-s ", interimOutput).
FlagWithOutput("-o ", output).
FlagWithArg("--key ", "provideLibs").
FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
} else {
// If nothing to add, just cp to the final output
builder.Command().Text("cp").Input(interimOutput).Output(output)
}
builder.Temporary(interimOutput)
builder.DeleteTemporaryFiles()
}
// linker_config generates protobuf file from json file. This protobuf file will be used from
// linkerconfig while generating ld.config.txt. Format of this file can be found from
// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md