diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index b0c87d4d1..88210c04f 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -46,19 +46,16 @@ var ( "bionic": Bp2BuildDefaultTrueRecursively, "bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue, - "build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively, - "build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively, - "build/bazel/examples/python": Bp2BuildDefaultTrueRecursively, - "build/bazel/examples/gensrcs": Bp2BuildDefaultTrueRecursively, - "build/make/target/product/security": Bp2BuildDefaultTrue, - "build/make/tools/signapk": Bp2BuildDefaultTrue, - "build/make/tools/zipalign": Bp2BuildDefaultTrueRecursively, - "build/soong": Bp2BuildDefaultTrue, - "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir - "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue, - "build/soong/cc/symbolfile": Bp2BuildDefaultTrue, - "build/soong/linkerconfig": Bp2BuildDefaultTrueRecursively, - "build/soong/scripts": Bp2BuildDefaultTrueRecursively, + "build/bazel": Bp2BuildDefaultTrueRecursively, + "build/make/target/product/security": Bp2BuildDefaultTrue, + "build/make/tools/signapk": Bp2BuildDefaultTrue, + "build/make/tools/zipalign": Bp2BuildDefaultTrueRecursively, + "build/soong": Bp2BuildDefaultTrue, + "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir + "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue, + "build/soong/cc/symbolfile": Bp2BuildDefaultTrue, + "build/soong/linkerconfig": Bp2BuildDefaultTrueRecursively, + "build/soong/scripts": Bp2BuildDefaultTrueRecursively, "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively, "development/apps/DevelopmentSettings": Bp2BuildDefaultTrue, @@ -282,24 +279,7 @@ var ( // This is actually build/bazel/build.BAZEL symlinked to ./BUILD ".":/*recursive = */ false, - // build/bazel/examples/apex/... BUILD files should be generated, so - // build/bazel is not recursive. Instead list each subdirectory under - // build/bazel explicitly. - "build/bazel":/* recursive = */ false, - "build/bazel/ci/dist":/* recursive = */ false, - "build/bazel/examples/android_app":/* recursive = */ true, - "build/bazel/examples/cc":/* recursive = */ true, - "build/bazel/examples/java":/* recursive = */ true, - "build/bazel/examples/partitions":/* recursive = */ true, - "build/bazel/bazel_skylib":/* recursive = */ true, - "build/bazel/rules":/* recursive = */ true, - "build/bazel/rules_cc":/* recursive = */ true, - "build/bazel/scripts":/* recursive = */ true, - "build/bazel/tests":/* recursive = */ true, - "build/bazel/platforms":/* recursive = */ true, - "build/bazel/product_config":/* recursive = */ true, - "build/bazel/product_variables":/* recursive = */ true, - "build/bazel/vendor/google":/* recursive = */ true, + "build/bazel":/* recursive = */ true, "build/bazel_common_rules":/* recursive = */ true, // build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive. "build/make/tools":/* recursive = */ false, diff --git a/android/bazel.go b/android/bazel.go index 3ae3d6f40..15729c18d 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -211,7 +211,7 @@ func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module b return "" // no label for unconverted module } -type bp2BuildConversionAllowlist struct { +type Bp2BuildConversionAllowlist struct { // Configure modules in these directories to enable bp2build_available: true or false by default. defaultConfig allowlists.Bp2BuildConfig @@ -241,14 +241,14 @@ type bp2BuildConversionAllowlist struct { // GenerateCcLibraryStaticOnly returns whether a cc_library module should only // generate a static version of itself based on the current global configuration. -func (a bp2BuildConversionAllowlist) GenerateCcLibraryStaticOnly(moduleName string) bool { +func (a Bp2BuildConversionAllowlist) GenerateCcLibraryStaticOnly(moduleName string) bool { return a.ccLibraryStaticOnly[moduleName] } -// NewBp2BuildAllowlist creates a new, empty bp2BuildConversionAllowlist +// NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist // which can be populated using builder pattern Set* methods -func NewBp2BuildAllowlist() bp2BuildConversionAllowlist { - return bp2BuildConversionAllowlist{ +func NewBp2BuildAllowlist() Bp2BuildConversionAllowlist { + return Bp2BuildConversionAllowlist{ allowlists.Bp2BuildConfig{}, map[string]bool{}, map[string]bool{}, @@ -259,7 +259,7 @@ func NewBp2BuildAllowlist() bp2BuildConversionAllowlist { } // SetDefaultConfig copies the entries from defaultConfig into the allowlist -func (a bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) Bp2BuildConversionAllowlist { if a.defaultConfig == nil { a.defaultConfig = allowlists.Bp2BuildConfig{} } @@ -271,7 +271,7 @@ func (a bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.B } // SetKeepExistingBuildFile copies the entries from keepExistingBuildFile into the allowlist -func (a bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) Bp2BuildConversionAllowlist { if a.keepExistingBuildFile == nil { a.keepExistingBuildFile = map[string]bool{} } @@ -283,7 +283,7 @@ func (a bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildF } // SetModuleAlwaysConvertList copies the entries from moduleAlwaysConvert into the allowlist -func (a bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) Bp2BuildConversionAllowlist { if a.moduleAlwaysConvert == nil { a.moduleAlwaysConvert = map[string]bool{} } @@ -295,7 +295,7 @@ func (a bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConv } // SetModuleTypeAlwaysConvertList copies the entries from moduleTypeAlwaysConvert into the allowlist -func (a bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) Bp2BuildConversionAllowlist { if a.moduleTypeAlwaysConvert == nil { a.moduleTypeAlwaysConvert = map[string]bool{} } @@ -307,7 +307,7 @@ func (a bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAl } // SetModuleDoNotConvertList copies the entries from moduleDoNotConvert into the allowlist -func (a bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) Bp2BuildConversionAllowlist { if a.moduleDoNotConvert == nil { a.moduleDoNotConvert = map[string]bool{} } @@ -319,7 +319,7 @@ func (a bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConver } // SetCcLibraryStaticOnlyList copies the entries from ccLibraryStaticOnly into the allowlist -func (a bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticOnly []string) bp2BuildConversionAllowlist { +func (a Bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticOnly []string) Bp2BuildConversionAllowlist { if a.ccLibraryStaticOnly == nil { a.ccLibraryStaticOnly = map[string]bool{} } @@ -330,33 +330,15 @@ func (a bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticO return a } -var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist") -var bp2buildAllowlist OncePer - -func GetBp2BuildAllowList() bp2BuildConversionAllowlist { - return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} { - return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig). - SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile). - SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList). - SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList). - SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList). - SetCcLibraryStaticOnlyList(allowlists.Bp2buildCcLibraryStaticOnlyList) - }).(bp2BuildConversionAllowlist) -} - // ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be // added to the build symlink forest based on the current global configuration. -func ShouldKeepExistingBuildFileForDir(dir string) bool { - return shouldKeepExistingBuildFileForDir(GetBp2BuildAllowList(), dir) -} - -func shouldKeepExistingBuildFileForDir(allowlist bp2BuildConversionAllowlist, dir string) bool { - if _, ok := allowlist.keepExistingBuildFile[dir]; ok { +func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool { + if _, ok := a.keepExistingBuildFile[dir]; ok { // Exact dir match return true } // Check if subtree match - for prefix, recursive := range allowlist.keepExistingBuildFile { + for prefix, recursive := range a.keepExistingBuildFile { if recursive { if strings.HasPrefix(dir, prefix+"/") { return true @@ -367,6 +349,20 @@ func shouldKeepExistingBuildFileForDir(allowlist bp2BuildConversionAllowlist, di return false } +var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist") +var bp2buildAllowlist OncePer + +func GetBp2BuildAllowList() Bp2BuildConversionAllowlist { + return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} { + return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig). + SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile). + SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList). + SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList). + SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList). + SetCcLibraryStaticOnlyList(allowlists.Bp2buildCcLibraryStaticOnlyList) + }).(Bp2BuildConversionAllowlist) +} + // MixedBuildsEnabled returns true if a module is ready to be replaced by a // converted or handcrafted Bazel target. As a side effect, calling this // method will also log whether this module is mixed build enabled for @@ -431,7 +427,7 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, } moduleName := module.Name() - allowlist := ctx.Config().bp2buildPackageConfig + allowlist := ctx.Config().Bp2buildPackageConfig moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName] moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)] allowlistConvert := moduleNameAllowed || moduleTypeAllowed @@ -447,14 +443,6 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, return false } - if allowlistConvert && shouldKeepExistingBuildFileForDir(allowlist, packagePath) { - if moduleNameAllowed { - ctx.ModuleErrorf("A module cannot be in a directory listed in keepExistingBuildFile"+ - " and also be in moduleAlwaysConvert. Directory: '%s'", packagePath) - return false - } - } - // This is a tristate value: true, false, or unset. if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok { if moduleNameAllowed { diff --git a/android/bazel_test.go b/android/bazel_test.go index 98f0a46d9..b578cca04 100644 --- a/android/bazel_test.go +++ b/android/bazel_test.go @@ -158,7 +158,7 @@ func (m TestBazelModule) GenerateBuildActions(blueprint.ModuleContext) { type TestBazelConversionContext struct { omc bazel.OtherModuleTestContext - allowlist bp2BuildConversionAllowlist + allowlist Bp2BuildConversionAllowlist errors []string } @@ -183,7 +183,7 @@ func (bcc *TestBazelConversionContext) ModuleErrorf(format string, args ...inter func (bcc *TestBazelConversionContext) Config() Config { return Config{ &config{ - bp2buildPackageConfig: bcc.allowlist, + Bp2buildPackageConfig: bcc.allowlist, }, } } @@ -202,7 +202,7 @@ func TestBp2BuildAllowlist(t *testing.T) { shouldConvert bool expectedErrors []string module TestBazelModule - allowlist bp2BuildConversionAllowlist + allowlist Bp2BuildConversionAllowlist }{ { description: "allowlist enables module", @@ -215,7 +215,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, BazelModuleBase: bazelableBazelModuleBase, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, @@ -233,7 +233,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, BazelModuleBase: bazelableBazelModuleBase, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, @@ -254,7 +254,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, BazelModuleBase: bazelableBazelModuleBase, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, @@ -263,27 +263,6 @@ func TestBp2BuildAllowlist(t *testing.T) { }, }, }, - { - description: "module in allowlist and existing BUILD file", - shouldConvert: false, - expectedErrors: []string{"A module cannot be in a directory listed in keepExistingBuildFile and also be in moduleAlwaysConvert. Directory: 'existing/build/dir'"}, - module: TestBazelModule{ - TestModuleInfo: bazel.TestModuleInfo{ - ModuleName: "foo", - Typ: "rule1", - Dir: "existing/build/dir", - }, - BazelModuleBase: bazelableBazelModuleBase, - }, - allowlist: bp2BuildConversionAllowlist{ - moduleAlwaysConvert: map[string]bool{ - "foo": true, - }, - keepExistingBuildFile: map[string]bool{ - "existing/build/dir": true, - }, - }, - }, { description: "module allowlist and enabled directory", shouldConvert: false, @@ -296,7 +275,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, BazelModuleBase: bazelableBazelModuleBase, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, @@ -317,7 +296,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, BazelModuleBase: bazelableBazelModuleBase, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, @@ -344,7 +323,7 @@ func TestBp2BuildAllowlist(t *testing.T) { }, }, }, - allowlist: bp2BuildConversionAllowlist{ + allowlist: Bp2BuildConversionAllowlist{ moduleAlwaysConvert: map[string]bool{ "foo": true, }, diff --git a/android/config.go b/android/config.go index a07cb6cd0..745410f1e 100644 --- a/android/config.go +++ b/android/config.go @@ -189,7 +189,7 @@ type config struct { mockBpList string BuildMode SoongBuildMode - bp2buildPackageConfig bp2BuildConversionAllowlist + Bp2buildPackageConfig Bp2BuildConversionAllowlist Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions // If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error @@ -482,7 +482,7 @@ func NewConfig(moduleListFile string, buildMode SoongBuildMode, runGoTests bool, config.BuildMode = buildMode config.BazelContext, err = NewBazelContext(config) - config.bp2buildPackageConfig = GetBp2BuildAllowList() + config.Bp2buildPackageConfig = GetBp2BuildAllowList() return Config{config}, err } diff --git a/android/testing.go b/android/testing.go index ef5e5a988..37085011b 100644 --- a/android/testing.go +++ b/android/testing.go @@ -213,8 +213,8 @@ func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) { ctx.finalDeps = append(ctx.finalDeps, f) } -func (ctx *TestContext) RegisterBp2BuildConfig(config bp2BuildConversionAllowlist) { - ctx.config.bp2buildPackageConfig = config +func (ctx *TestContext) RegisterBp2BuildConfig(config Bp2BuildConversionAllowlist) { + ctx.config.Bp2buildPackageConfig = config } // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index 242ea1e69..8de6d1881 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -373,6 +373,15 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers if generateFilegroups { // Add a filegroup target that exposes all sources in the subtree of this package // NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module) + // + // This works because: https://bazel.build/reference/be/functions#exports_files + // "As a legacy behaviour, also files mentioned as input to a rule are exported with the + // default visibility until the flag --incompatible_no_implicit_file_export is flipped. However, this behavior + // should not be relied upon and actively migrated away from." + // + // TODO(b/198619163): We should change this to export_files(glob(["**/*"])) instead, but doing that causes these errors: + // "Error in exports_files: generated label '//external/avb:avbtool' conflicts with existing py_binary rule" + // So we need to solve all the "target ... is both a rule and a file" warnings first. for dir, _ := range dirs { buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{ name: "bp2build_all_srcs", diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 8cf9beaf4..d98b6a369 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -2,7 +2,6 @@ package bp2build import ( "encoding/json" - "fmt" "reflect" "strings" @@ -80,21 +79,14 @@ func CreateBazelFiles( files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))) } - files = append(files, createBuildFiles(cfg, buildToTargets, mode)...) + files = append(files, createBuildFiles(buildToTargets, mode)...) return files } -func createBuildFiles(cfg android.Config, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { +func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { files := make([]BazelFile, 0, len(buildToTargets)) - warnNotWriting := cfg.IsEnvTrue("BP2BUILD_VERBOSE") for _, dir := range android.SortedStringKeys(buildToTargets) { - if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) { - if warnNotWriting { - fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir) - } - continue - } targets := buildToTargets[dir] targets.sort() diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go index 78e7b0e75..023ec9687 100644 --- a/bp2build/symlink_forest.go +++ b/bp2build/symlink_forest.go @@ -1,12 +1,27 @@ +// Copyright 2022 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 bp2build import ( - "android/soong/android" "fmt" "io/ioutil" "os" "path/filepath" + "regexp" + "android/soong/android" "android/soong/shared" ) @@ -58,6 +73,57 @@ func treeFromExcludePathList(paths []string) *node { return result } +func mergeBuildFiles(output string, srcBuildFile string, generatedBuildFile string, verbose bool) error { + + srcBuildFileContent, err := os.ReadFile(srcBuildFile) + if err != nil { + return err + } + + generatedBuildFileContent, err := os.ReadFile(generatedBuildFile) + if err != nil { + return err + } + + // There can't be a package() call in both the source and generated BUILD files. + // bp2build will generate a package() call for licensing information, but if + // there's no licensing information, it will still generate a package() call + // that just sets default_visibility=public. If the handcrafted build file + // also has a package() call, we'll allow it to override the bp2build + // generated one if it doesn't have any licensing information. If the bp2build + // one has licensing information and the handcrafted one exists, we'll leave + // them both in for bazel to throw an error. + packageRegex := regexp.MustCompile(`(?m)^package\s*\(`) + packageDefaultVisibilityRegex := regexp.MustCompile(`(?m)^package\s*\(\s*default_visibility\s*=\s*\[\s*"//visibility:public",?\s*]\s*\)`) + if packageRegex.Find(srcBuildFileContent) != nil { + if verbose && packageDefaultVisibilityRegex.Find(generatedBuildFileContent) != nil { + fmt.Fprintf(os.Stderr, "Both '%s' and '%s' have a package() target, removing the first one\n", + generatedBuildFile, srcBuildFile) + } + generatedBuildFileContent = packageDefaultVisibilityRegex.ReplaceAll(generatedBuildFileContent, []byte{}) + } + + outFile, err := os.Create(output) + if err != nil { + return err + } + + _, err = outFile.Write(generatedBuildFileContent) + if err != nil { + return err + } + + if generatedBuildFileContent[len(generatedBuildFileContent)-1] != '\n' { + _, err = outFile.WriteString("\n") + if err != nil { + return err + } + } + + _, err = outFile.Write(srcBuildFileContent) + return err +} + // Calls readdir() and returns it as a map from the basename of the files in dir // to os.FileInfo. func readdirToMap(dir string) map[string]os.FileInfo { @@ -125,6 +191,17 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st srcDirMap := readdirToMap(shared.JoinPath(topdir, srcDir)) buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir)) + renamingBuildFile := false + if _, ok := srcDirMap["BUILD"]; ok { + if _, ok := srcDirMap["BUILD.bazel"]; !ok { + if _, ok := buildFilesMap["BUILD.bazel"]; ok { + renamingBuildFile = true + srcDirMap["BUILD.bazel"] = srcDirMap["BUILD"] + delete(srcDirMap, "BUILD") + } + } + } + allEntries := make(map[string]bool) for n := range srcDirMap { allEntries[n] = true @@ -148,21 +225,28 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st // The full paths of children in the input trees and in the output tree forestChild := shared.JoinPath(forestDir, f) srcChild := shared.JoinPath(srcDir, f) + if f == "BUILD.bazel" && renamingBuildFile { + srcChild = shared.JoinPath(srcDir, "BUILD") + } buildFilesChild := shared.JoinPath(buildFilesDir, f) // Descend in the exclusion tree, if there are any excludes left - var excludeChild *node - if exclude == nil { - excludeChild = nil - } else { - excludeChild = exclude.children[f] + var excludeChild *node = nil + if exclude != nil { + if f == "BUILD.bazel" && renamingBuildFile { + excludeChild = exclude.children["BUILD"] + } else { + excludeChild = exclude.children[f] + } } srcChildEntry, sExists := srcDirMap[f] buildFilesChildEntry, bExists := buildFilesMap[f] - excluded := excludeChild != nil && excludeChild.excluded - if excluded { + if excludeChild != nil && excludeChild.excluded { + if bExists { + symlinkIntoForest(topdir, forestChild, buildFilesChild) + } continue } @@ -198,13 +282,15 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st // Both are directories. Descend. plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) } else if !sDir && !bDir { - // Neither is a directory. Prioritize BUILD files generated by bp2build - // over any BUILD file imported into external/. - if cfg.IsEnvTrue("BP2BUILD_VERBOSE") { - fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n", - buildFilesChild, srcChild, forestChild) + // Neither is a directory. Merge them. + srcBuildFile := shared.JoinPath(topdir, srcChild) + generatedBuildFile := shared.JoinPath(topdir, buildFilesChild) + err = mergeBuildFiles(shared.JoinPath(topdir, forestChild), srcBuildFile, generatedBuildFile, cfg.IsEnvTrue("BP2BUILD_VERBOSE")) + if err != nil { + fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s", + srcBuildFile, generatedBuildFile, err) + *okay = false } - symlinkIntoForest(topdir, forestChild, buildFilesChild) } else { // Both exist and one is a file. This is an error. fmt.Fprintf(os.Stderr, diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index d15dea1c0..60e2f93ff 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -406,14 +406,10 @@ func touch(path string) { } } -// Find BUILD files in the srcDir which... -// -// - are not on the allow list (android/bazel.go#ShouldKeepExistingBuildFileForDir()) -// -// - won't be overwritten by corresponding bp2build generated files -// -// And return their paths so they can be left out of the Bazel workspace dir (i.e. ignored) -func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string, verbose bool) []string { +// Find BUILD files in the srcDir which are not in the allowlist +// (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir) +// and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored) +func getPathsToIgnoredBuildFiles(config android.Bp2BuildConversionAllowlist, topDir string, srcDirBazelFiles []string, verbose bool) []string { paths := make([]string, 0) for _, srcDirBazelFileRelativePath := range srcDirBazelFiles { @@ -428,21 +424,14 @@ func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBaze // Don't ignore entire directories continue } - if !(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") { + if fileInfo.Name() != "BUILD" && fileInfo.Name() != "BUILD.bazel" { // Don't ignore this file - it is not a build file continue } - srcDirBazelFileDir := filepath.Dir(srcDirBazelFileRelativePath) - if android.ShouldKeepExistingBuildFileForDir(srcDirBazelFileDir) { + if config.ShouldKeepExistingBuildFileForDir(filepath.Dir(srcDirBazelFileRelativePath)) { // Don't ignore this existing build file continue } - correspondingBp2BuildFile := shared.JoinPath(topDir, generatedRoot, srcDirBazelFileRelativePath) - if _, err := os.Stat(correspondingBp2BuildFile); err == nil { - // If bp2build generated an alternate BUILD file, don't exclude this workspace path - // BUILD file clash resolution happens later in the symlink forest creation - continue - } if verbose { fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath) } @@ -553,7 +542,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { os.Exit(1) } - pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE")) + pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE")) excludes = append(excludes, pathsToIgnoredBuildFiles...) excludes = append(excludes, getTemporaryExcludes()...)