diff options
author | Jaewoong Jung <jungjw@google.com> | 2020-06-01 10:45:49 -0700 |
---|---|---|
committer | Jaewoong Jung <jungjw@google.com> | 2020-06-02 14:35:04 -0700 |
commit | fccad6b09888792a0b156f9ff1b2558810006244 (patch) | |
tree | 73a558d74a22ead1dffb44e27f22e6a2ced1c69f /etc | |
parent | c344620ed669e8e98979a8ed882d7e1adce59b17 (diff) | |
download | build_soong-fccad6b09888792a0b156f9ff1b2558810006244.tar.gz build_soong-fccad6b09888792a0b156f9ff1b2558810006244.tar.bz2 build_soong-fccad6b09888792a0b156f9ff1b2558810006244.zip |
Soong package structure refactoring
Give prebuilt_etc and sh_binary their own packages and split the
gigantic main Android.bp up to small, per-package ones.
(This is a cherry-pick change.)
Test: m nothing, TreeHugger
Bug: 156980228
Change-Id: I7b00cd344b9f16861f1ff39edf0029f016b853d0
Merged-In: I7b00cd344b9f16861f1ff39edf0029f016b853d0
Diffstat (limited to 'etc')
-rw-r--r-- | etc/Android.bp | 16 | ||||
-rw-r--r-- | etc/prebuilt_etc.go | 289 | ||||
-rw-r--r-- | etc/prebuilt_etc_test.go | 283 |
3 files changed, 588 insertions, 0 deletions
diff --git a/etc/Android.bp b/etc/Android.bp new file mode 100644 index 00000000..cfd303ec --- /dev/null +++ b/etc/Android.bp @@ -0,0 +1,16 @@ +bootstrap_go_package { + name: "soong-etc", + pkgPath: "android/soong/etc", + deps: [ + "blueprint", + "soong", + "soong-android", + ], + srcs: [ + "prebuilt_etc.go", + ], + testSrcs: [ + "prebuilt_etc_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go new file mode 100644 index 00000000..842d9eec --- /dev/null +++ b/etc/prebuilt_etc.go @@ -0,0 +1,289 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// 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 etc + +import ( + "strconv" + + "github.com/google/blueprint/proptools" + + "android/soong/android" +) + +var pctx = android.NewPackageContext("android/soong/etc") + +// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file. + +func init() { + pctx.Import("android/soong/android") + + android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) + android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) + android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) + android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) + android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) + android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) +} + +type prebuiltEtcProperties struct { + // Source file of this prebuilt. + Src *string `android:"path,arch_variant"` + + // optional subdirectory under which this file is installed into + Sub_dir *string `android:"arch_variant"` + + // optional name for the installed file. If unspecified, name of the module is used as the file name + Filename *string `android:"arch_variant"` + + // when set to true, and filename property is not set, the name for the installed file + // is the same as the file name of the source file. + Filename_from_src *bool `android:"arch_variant"` + + // Make this module available when building for ramdisk. + Ramdisk_available *bool + + // Make this module available when building for recovery. + Recovery_available *bool + + // Whether this module is directly installable to one of the partitions. Default: true. + Installable *bool +} + +type PrebuiltEtcModule interface { + android.Module + SubDir() string + OutputFile() android.OutputPath +} + +type PrebuiltEtc struct { + android.ModuleBase + + properties prebuiltEtcProperties + + sourceFilePath android.Path + outputFilePath android.OutputPath + // The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share. + installDirBase string + // The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware. + socInstallDirBase string + installDirPath android.InstallPath + additionalDependencies *android.Paths +} + +func (p *PrebuiltEtc) inRamdisk() bool { + return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk() +} + +func (p *PrebuiltEtc) onlyInRamdisk() bool { + return p.ModuleBase.InstallInRamdisk() +} + +func (p *PrebuiltEtc) InstallInRamdisk() bool { + return p.inRamdisk() +} + +func (p *PrebuiltEtc) inRecovery() bool { + return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery() +} + +func (p *PrebuiltEtc) onlyInRecovery() bool { + return p.ModuleBase.InstallInRecovery() +} + +func (p *PrebuiltEtc) InstallInRecovery() bool { + return p.inRecovery() +} + +var _ android.ImageInterface = (*PrebuiltEtc)(nil) + +func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {} + +func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() +} + +func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk() +} + +func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery() +} + +func (p *PrebuiltEtc) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return nil +} + +func (p *PrebuiltEtc) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +} + +func (p *PrebuiltEtc) DepsMutator(ctx android.BottomUpMutatorContext) { + if p.properties.Src == nil { + ctx.PropertyErrorf("src", "missing prebuilt source file") + } +} + +func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path { + return android.PathForModuleSrc(ctx, android.String(p.properties.Src)) +} + +func (p *PrebuiltEtc) InstallDirPath() android.InstallPath { + return p.installDirPath +} + +// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform +// additional steps (like validating the src) before the file is installed. +func (p *PrebuiltEtc) SetAdditionalDependencies(paths android.Paths) { + p.additionalDependencies = &paths +} + +func (p *PrebuiltEtc) OutputFile() android.OutputPath { + return p.outputFilePath +} + +func (p *PrebuiltEtc) SubDir() string { + return android.String(p.properties.Sub_dir) +} + +func (p *PrebuiltEtc) Installable() bool { + return p.properties.Installable == nil || android.Bool(p.properties.Installable) +} + +func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { + p.sourceFilePath = android.PathForModuleSrc(ctx, android.String(p.properties.Src)) + filename := android.String(p.properties.Filename) + filename_from_src := android.Bool(p.properties.Filename_from_src) + if filename == "" { + if filename_from_src { + filename = p.sourceFilePath.Base() + } else { + filename = ctx.ModuleName() + } + } else if filename_from_src { + ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") + return + } + p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath + + // If soc install dir was specified and SOC specific is set, set the installDirPath to the specified + // socInstallDirBase. + installBaseDir := p.installDirBase + if ctx.SocSpecific() && p.socInstallDirBase != "" { + installBaseDir = p.socInstallDirBase + } + p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, proptools.String(p.properties.Sub_dir)) + + // This ensures that outputFilePath has the correct name for others to + // use, as the source file may have a different name. + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: p.outputFilePath, + Input: p.sourceFilePath, + }) +} + +func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries { + nameSuffix := "" + if p.inRamdisk() && !p.onlyInRamdisk() { + nameSuffix = ".ramdisk" + } + if p.inRecovery() && !p.onlyInRecovery() { + nameSuffix = ".recovery" + } + return []android.AndroidMkEntries{android.AndroidMkEntries{ + Class: "ETC", + SubName: nameSuffix, + OutputFile: android.OptionalPathForPath(p.outputFilePath), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_TAGS", "optional") + entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String()) + entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base()) + entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable())) + if p.additionalDependencies != nil { + for _, path := range *p.additionalDependencies { + entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String()) + } + } + }, + }, + }} +} + +func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) { + p.installDirBase = dirBase + p.AddProperties(&p.properties) +} + +// prebuilt_etc is for a prebuilt artifact that is installed in +// <partition>/etc/<sub_dir> directory. +func PrebuiltEtcFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "etc") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + return module +} + +// prebuilt_etc_host is for a host prebuilt artifact that is installed in +// $(HOST_OUT)/etc/<sub_dir> directory. +func PrebuiltEtcHostFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "etc") + // This module is host-only + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon) + return module +} + +// prebuilt_usr_share is for a prebuilt artifact that is installed in +// <partition>/usr/share/<sub_dir> directory. +func PrebuiltUserShareFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/share") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + return module +} + +// prebuild_usr_share_host is for a host prebuilt artifact that is installed in +// $(HOST_OUT)/usr/share/<sub_dir> directory. +func PrebuiltUserShareHostFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/share") + // This module is host-only + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon) + return module +} + +// prebuilt_font installs a font in <partition>/fonts directory. +func PrebuiltFontFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "fonts") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + return module +} + +// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system image. +// If soc_specific property is set to true, the firmware file is installed to the vendor <partition>/firmware +// directory for vendor image. +func PrebuiltFirmwareFactory() android.Module { + module := &PrebuiltEtc{} + module.socInstallDirBase = "firmware" + InitPrebuiltEtcModule(module, "etc/firmware") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + return module +} diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go new file mode 100644 index 00000000..e13cb3cb --- /dev/null +++ b/etc/prebuilt_etc_test.go @@ -0,0 +1,283 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// 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 etc + +import ( + "io/ioutil" + "os" + "path/filepath" + "reflect" + "testing" + + "android/soong/android" +) + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_etc_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) { + fs := map[string][]byte{ + "foo.conf": nil, + "bar.conf": nil, + "baz.conf": nil, + } + + config := android.TestArchConfig(buildDir, nil, bp, fs) + + ctx := android.NewTestArchContext() + ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) + ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) + ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) + ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) + ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) + ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) + ctx.Register(config) + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + return ctx, config +} + +func TestPrebuiltEtcVariants(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_etc { + name: "foo.conf", + src: "foo.conf", + } + prebuilt_etc { + name: "bar.conf", + src: "bar.conf", + recovery_available: true, + } + prebuilt_etc { + name: "baz.conf", + src: "baz.conf", + recovery: true, + } + `) + + foo_variants := ctx.ModuleVariantsForTests("foo.conf") + if len(foo_variants) != 1 { + t.Errorf("expected 1, got %#v", foo_variants) + } + + bar_variants := ctx.ModuleVariantsForTests("bar.conf") + if len(bar_variants) != 2 { + t.Errorf("expected 2, got %#v", bar_variants) + } + + baz_variants := ctx.ModuleVariantsForTests("baz.conf") + if len(baz_variants) != 1 { + t.Errorf("expected 1, got %#v", bar_variants) + } +} + +func TestPrebuiltEtcOutputPath(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_etc { + name: "foo.conf", + src: "foo.conf", + filename: "foo.installed.conf", + } + `) + + p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + if p.outputFilePath.Base() != "foo.installed.conf" { + t.Errorf("expected foo.installed.conf, got %q", p.outputFilePath.Base()) + } +} + +func TestPrebuiltEtcGlob(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_etc { + name: "my_foo", + src: "foo.*", + } + prebuilt_etc { + name: "my_bar", + src: "bar.*", + filename_from_src: true, + } + `) + + p := ctx.ModuleForTests("my_foo", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + if p.outputFilePath.Base() != "my_foo" { + t.Errorf("expected my_foo, got %q", p.outputFilePath.Base()) + } + + p = ctx.ModuleForTests("my_bar", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + if p.outputFilePath.Base() != "bar.conf" { + t.Errorf("expected bar.conf, got %q", p.outputFilePath.Base()) + } +} + +func TestPrebuiltEtcAndroidMk(t *testing.T) { + ctx, config := testPrebuiltEtc(t, ` + prebuilt_etc { + name: "foo", + src: "foo.conf", + owner: "abc", + filename_from_src: true, + required: ["modA", "moduleB"], + host_required: ["hostModA", "hostModB"], + target_required: ["targetModA"], + } + `) + + expected := map[string][]string{ + "LOCAL_MODULE": {"foo"}, + "LOCAL_MODULE_CLASS": {"ETC"}, + "LOCAL_MODULE_OWNER": {"abc"}, + "LOCAL_INSTALLED_MODULE_STEM": {"foo.conf"}, + "LOCAL_REQUIRED_MODULES": {"modA", "moduleB"}, + "LOCAL_HOST_REQUIRED_MODULES": {"hostModA", "hostModB"}, + "LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"}, + } + + mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + for k, expectedValue := range expected { + if value, ok := entries.EntryMap[k]; ok { + if !reflect.DeepEqual(value, expectedValue) { + t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue) + } + } else { + t.Errorf("No %s defined, saw %q", k, entries.EntryMap) + } + } +} + +func TestPrebuiltEtcHost(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_etc_host { + name: "foo.conf", + src: "foo.conf", + } + `) + + buildOS := android.BuildOs.String() + p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc) + if !p.Host() { + t.Errorf("host bit is not set for a prebuilt_etc_host module.") + } +} + +func TestPrebuiltUserShareInstallDirPath(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_usr_share { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + } + `) + + p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + expected := buildDir + "/target/product/test_device/system/usr/share/bar" + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) + } +} + +func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { + ctx, config := testPrebuiltEtc(t, ` + prebuilt_usr_share_host { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + } + `) + + buildOS := android.BuildOs.String() + p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc) + expected := filepath.Join(buildDir, "host", config.PrebuiltOS(), "usr", "share", "bar") + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) + } +} + +func TestPrebuiltFontInstallDirPath(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, ` + prebuilt_font { + name: "foo.conf", + src: "foo.conf", + } + `) + + p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + expected := buildDir + "/target/product/test_device/system/fonts" + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) + } +} + +func TestPrebuiltFirmwareDirPath(t *testing.T) { + targetPath := buildDir + "/target/product/test_device" + tests := []struct { + description string + config string + expectedPath string + }{{ + description: "prebuilt: system firmware", + config: ` + prebuilt_firmware { + name: "foo.conf", + src: "foo.conf", + }`, + expectedPath: filepath.Join(targetPath, "system/etc/firmware"), + }, { + description: "prebuilt: vendor firmware", + config: ` + prebuilt_firmware { + name: "foo.conf", + src: "foo.conf", + soc_specific: true, + sub_dir: "sub_dir", + }`, + expectedPath: filepath.Join(targetPath, "vendor/firmware/sub_dir"), + }} + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + ctx, _ := testPrebuiltEtc(t, tt.config) + p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + if p.installDirPath.String() != tt.expectedPath { + t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath) + } + }) + } +} |