diff --git a/android/androidmk.go b/android/androidmk.go index 5fb0cd167..cac2cfe47 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -34,7 +34,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -815,8 +814,6 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs switch x := mod.(type) { case AndroidMkDataProvider: err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x) - case bootstrap.GoBinaryTool: - err = translateGoBinaryModule(ctx, w, mod, x) case AndroidMkEntriesProvider: err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x) default: @@ -831,23 +828,6 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs return err } -// A simple, special Android.mk entry output func to make it possible to build blueprint tools using -// m by making them phony targets. -func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, - goBinary bootstrap.GoBinaryTool) error { - - name := ctx.ModuleName(mod) - fmt.Fprintln(w, ".PHONY:", name) - fmt.Fprintln(w, name+":", goBinary.InstallPath()) - fmt.Fprintln(w, "") - // Assuming no rules in make include go binaries in distributables. - // If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files. - // In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for - // `goBinary.InstallPath()` pointing to the `name`.meta_lic file. - - return nil -} - func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) { // Get the preamble content through AndroidMkEntries logic. data.Entries = AndroidMkEntries{ diff --git a/android/arch.go b/android/arch.go index 6d896e5fc..a7868bac4 100644 --- a/android/arch.go +++ b/android/arch.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" ) @@ -397,33 +396,8 @@ func (target Target) Variations() []blueprint.Variation { // device_supported and host_supported properties to determine which OsTypes are enabled for this // module, then searches through the Targets to determine which have enabled Targets for this // module. -func osMutator(bpctx blueprint.BottomUpMutatorContext) { - var module Module - var ok bool - if module, ok = bpctx.Module().(Module); !ok { - // The module is not a Soong module, it is a Blueprint module. - if bootstrap.IsBootstrapModule(bpctx.Module()) { - // Bootstrap Go modules are always the build OS or linux bionic. - config := bpctx.Config().(Config) - osNames := []string{config.BuildOSTarget.OsVariation()} - for _, hostCrossTarget := range config.Targets[LinuxBionic] { - if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType { - osNames = append(osNames, hostCrossTarget.OsVariation()) - } - } - osNames = FirstUniqueStrings(osNames) - bpctx.CreateVariations(osNames...) - } - return - } - - // Bootstrap Go module support above requires this mutator to be a - // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext - // filters out non-Soong modules. Now that we've handled them, create a - // normal android.BottomUpMutatorContext. - mctx := bottomUpMutatorContextFactory(bpctx, module, false) - defer bottomUpMutatorContextPool.Put(mctx) - +func osMutator(mctx BottomUpMutatorContext) { + module := mctx.Module() base := module.base() // Nothing to do for modules that are not architecture specific (e.g. a genrule). @@ -553,24 +527,8 @@ var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"} // // Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass, // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets(). -func archMutator(bpctx blueprint.BottomUpMutatorContext) { - var module Module - var ok bool - if module, ok = bpctx.Module().(Module); !ok { - if bootstrap.IsBootstrapModule(bpctx.Module()) { - // Bootstrap Go modules are always the build architecture. - bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation()) - } - return - } - - // Bootstrap Go module support above requires this mutator to be a - // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext - // filters out non-Soong modules. Now that we've handled them, create a - // normal android.BottomUpMutatorContext. - mctx := bottomUpMutatorContextFactory(bpctx, module, false) - defer bottomUpMutatorContextPool.Put(mctx) - +func archMutator(mctx BottomUpMutatorContext) { + module := mctx.Module() base := module.base() if !base.ArchSpecific() { diff --git a/android/module_context.go b/android/module_context.go index 54fe0be17..2bf2a8f00 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -85,7 +85,9 @@ type ModuleBuildParams BuildParams type ModuleContext interface { BaseModuleContext - blueprintModuleContext() blueprint.ModuleContext + // BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps. It may only be + // used by the golang module types that need to call into the bootstrap module types. + BlueprintModuleContext() blueprint.ModuleContext // Deprecated: use ModuleContext.Build instead. ModuleBuild(pctx PackageContext, params ModuleBuildParams) @@ -779,7 +781,7 @@ func (m *moduleContext) UncheckedModule() { m.uncheckedModule = true } -func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { +func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext { return m.bp } diff --git a/android/mutator.go b/android/mutator.go index 38fb857dd..2ef4d7fef 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -148,9 +148,9 @@ var preArch = []RegisterMutatorFunc{ } func registerArchMutator(ctx RegisterMutatorsContext) { - ctx.BottomUpBlueprint("os", osMutator).Parallel() + ctx.BottomUp("os", osMutator).Parallel() ctx.Transition("image", &imageTransitionMutator{}) - ctx.BottomUpBlueprint("arch", archMutator).Parallel() + ctx.BottomUp("arch", archMutator).Parallel() } var preDeps = []RegisterMutatorFunc{ diff --git a/android/paths.go b/android/paths.go index 6322f7566..0a4f89187 100644 --- a/android/paths.go +++ b/android/paths.go @@ -27,7 +27,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" ) @@ -555,13 +554,6 @@ func (p OutputPaths) Strings() []string { return ret } -// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module. -func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path { - goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin") - rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath()) - return goBinaryInstallDir.Join(ctx, rel) -} - // Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax. // If the dependency is not found, a missingErrorDependency is returned. // If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned. @@ -573,10 +565,6 @@ func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) { return nil, missingDependencyError{[]string{moduleName}} } - if goBinary, ok := module.(bootstrap.GoBinaryTool); ok && tag == "" { - goBinaryPath := PathForGoBinary(ctx, goBinary) - return Paths{goBinaryPath}, nil - } outputFiles, err := outputFilesForModule(ctx, module, tag) if outputFiles != nil && err == nil { return outputFiles, nil diff --git a/genrule/genrule.go b/genrule/genrule.go index fd72d3c15..a48038bac 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -25,7 +25,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" "android/soong/android" @@ -365,11 +364,6 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { tools = append(tools, path.Path()) addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}}) } - case bootstrap.GoBinaryTool: - // A GoBinaryTool provides the install path to a tool, which will be copied. - p := android.PathForGoBinary(ctx, t) - tools = append(tools, p) - addLocationLabel(tag.label, toolLocation{android.Paths{p}}) default: ctx.ModuleErrorf("%q is not a host tool provider", tool) return diff --git a/golang/Android.bp b/golang/Android.bp new file mode 100644 index 000000000..3eae94fa2 --- /dev/null +++ b/golang/Android.bp @@ -0,0 +1,22 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-golang", + pkgPath: "android/soong/golang", + deps: [ + "blueprint", + "blueprint-pathtools", + "blueprint-bootstrap", + "soong", + "soong-android", + ], + srcs: [ + "golang.go", + ], + testSrcs: [ + "golang_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/golang/golang.go b/golang/golang.go new file mode 100644 index 000000000..ede2150dc --- /dev/null +++ b/golang/golang.go @@ -0,0 +1,122 @@ +// Copyright 2024 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 golang wraps the blueprint blueprint_go_binary and bootstrap_go_binary module types in versions +// that implement android.Module that are used when building in Soong. This simplifies the code in Soong +// so it can always assume modules are an android.Module. +// The original blueprint blueprint_go_binary and bootstrap_go_binary module types are still used during +// bootstrapping, so the Android.bp entries for these module types must be compatible with both the +// original blueprint module types and these wrapped module types. +package golang + +import ( + "android/soong/android" + "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" +) + +func init() { + // Wrap the blueprint Go module types with Soong ones that interoperate with the rest of the Soong modules. + bootstrap.GoModuleTypesAreWrapped() + RegisterGoModuleTypes(android.InitRegistrationContext) +} + +func RegisterGoModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("bootstrap_go_package", goPackageModuleFactory) + ctx.RegisterModuleType("blueprint_go_binary", goBinaryModuleFactory) +} + +// A GoPackage is a module for building Go packages. +type GoPackage struct { + android.ModuleBase + bootstrap.GoPackage +} + +func goPackageModuleFactory() android.Module { + module := &GoPackage{} + module.AddProperties(module.Properties()...) + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) + return module +} + +func (g *GoPackage) GenerateBuildActions(ctx blueprint.ModuleContext) { + // The embedded ModuleBase and bootstrap.GoPackage each implement GenerateBuildActions, + // the delegation has to be implemented manually to disambiguate. Call ModuleBase's + // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call + // bootstrap.GoPackage.GenerateBuildActions. + g.ModuleBase.GenerateBuildActions(ctx) +} + +func (g *GoPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) { + g.GoPackage.GenerateBuildActions(ctx.BlueprintModuleContext()) +} + +// A GoBinary is a module for building executable binaries from Go sources. +type GoBinary struct { + android.ModuleBase + bootstrap.GoBinary + + outputFile android.Path +} + +func goBinaryModuleFactory() android.Module { + module := &GoBinary{} + module.AddProperties(module.Properties()...) + android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst) + return module +} + +func (g *GoBinary) GenerateBuildActions(ctx blueprint.ModuleContext) { + // The embedded ModuleBase and bootstrap.GoBinary each implement GenerateBuildActions, + // the delegation has to be implemented manually to disambiguate. Call ModuleBase's + // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call + // bootstrap.GoBinary.GenerateBuildActions. + g.ModuleBase.GenerateBuildActions(ctx) +} + +func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Install the file in Soong instead of blueprint so that Soong knows about the install rules. + g.GoBinary.SetSkipInstall() + + // Run the build actions from the wrapped blueprint bootstrap module. + g.GoBinary.GenerateBuildActions(ctx.BlueprintModuleContext()) + + // Translate the bootstrap module's string path into a Path + outputFile := android.PathForArbitraryOutput(ctx, android.Rel(ctx, ctx.Config().OutDir(), g.IntermediateFile())).WithoutRel() + g.outputFile = outputFile + + installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile) + + if !ctx.Config().KatiEnabled() || g.ExportedToMake() { + // Modules in an unexported namespace have no install rule, only add modules in the exported namespaces + // to the blueprint_tools phony rules. + ctx.Phony("blueprint_tools", installPath) + } + + ctx.SetOutputFiles(android.Paths{outputFile}, "") +} + +func (g *GoBinary) HostToolPath() android.OptionalPath { + return android.OptionalPathForPath(g.outputFile) +} + +func (g *GoBinary) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{ + { + Class: "EXECUTABLES", + OutputFile: android.OptionalPathForPath(g.outputFile), + Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", + }, + } +} diff --git a/golang/golang_test.go b/golang/golang_test.go new file mode 100644 index 000000000..b51214402 --- /dev/null +++ b/golang/golang_test.go @@ -0,0 +1,51 @@ +// Copyright 2024 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 golang + +import ( + "android/soong/android" + "github.com/google/blueprint/bootstrap" + "path/filepath" + "testing" +) + +func TestGolang(t *testing.T) { + bp := ` + bootstrap_go_package { + name: "gopkg", + pkgPath: "test/pkg", + } + + blueprint_go_binary { + name: "gobin", + deps: ["gopkg"], + } + ` + + result := android.GroupFixturePreparers( + android.PrepareForTestWithArchMutator, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + RegisterGoModuleTypes(ctx) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUpBlueprint("bootstrap_deps", bootstrap.BootstrapDeps) + }) + }), + ).RunTestWithBp(t, bp) + + bin := result.ModuleForTests("gobin", result.Config.BuildOSTarget.String()) + + expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "bin/go/gobin/obj/gobin") + android.AssertPathsRelativeToTopEquals(t, "output files", []string{expected}, bin.OutputFiles(result.TestContext, t, "")) +}