天天看點

Android.bp轉換的問題

在Android官網上提供了一篇Build System Best Practices的文章(https://android.googlesource.com/platform/build/soong/+/HEAD/docs/best_practices.md),最後寫道,

Conditionally used source files, libraries or flags

The preferred solution is to convert the conditional to runtime, either by autodetecting the correct value or loading the value from a system property or a configuration file.

As a last resort, if the conditional cannot be removed, a Soong plugin can be written in Go that can implement additional features for specific module types. Soong plugins are inherently tightly coupled to the build system and will require ongoing maintenance as the build system is changed; so plugins should be used only when absolutely required.

See art/build/art.go or external/llvm/soong/llvm.go for examples of more complex conditionals on product variables or environment variables.

最後一句話就是說有關産品變量或環境變量的更複雜條件的示例,浏覽那兩個連結。考慮到很多同學都不會科學上網,我就将那兩個連結裡的源碼給搬了過來,具體怎麼實作的還沒有完全摸透。先粘出來,供大家看看吧。

https://android.googlesource.com/platform/art/+/master/build/art.go

// Copyright (C) 2016 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 art
import (
	"android/soong/android"
	"android/soong/apex"
	"android/soong/cc"
	"fmt"
	"log"
	"sync"
	"github.com/google/blueprint/proptools"
)
var supportedArches = []string{"arm", "arm64", "mips", "mips64", "x86", "x86_64"}
func globalFlags(ctx android.BaseContext) ([]string, []string) {
	var cflags []string
	var asflags []string
	opt := envDefault(ctx, "ART_NDEBUG_OPT_FLAG", "-O3")
	cflags = append(cflags, opt)
	tlab := false
	gcType := envDefault(ctx, "ART_DEFAULT_GC_TYPE", "CMS")
	if envTrue(ctx, "ART_TEST_DEBUG_GC") {
		gcType = "SS"
		tlab = true
	}
	cflags = append(cflags, "-DART_DEFAULT_GC_TYPE_IS_"+gcType)
	if tlab {
		cflags = append(cflags, "-DART_USE_TLAB=1")
	}
	imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
	cflags = append(cflags, "-DIMT_SIZE="+imtSize)
	if envTrue(ctx, "ART_HEAP_POISONING") {
		cflags = append(cflags, "-DART_HEAP_POISONING=1")
		asflags = append(asflags, "-DART_HEAP_POISONING=1")
	}
	if envTrue(ctx, "ART_USE_CXX_INTERPRETER") {
		cflags = append(cflags, "-DART_USE_CXX_INTERPRETER=1")
	}
	if !envFalse(ctx, "ART_USE_READ_BARRIER") && ctx.AConfig().ArtUseReadBarrier() {
		// Used to change the read barrier type. Valid values are BAKER, BROOKS,
		// TABLELOOKUP. The default is BAKER.
		barrierType := envDefault(ctx, "ART_READ_BARRIER_TYPE", "BAKER")
		cflags = append(cflags,
			"-DART_USE_READ_BARRIER=1",
			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
		asflags = append(asflags,
			"-DART_USE_READ_BARRIER=1",
			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
	}
	if !envFalse(ctx, "ART_USE_GENERATIONAL_CC") {
		cflags = append(cflags, "-DART_USE_GENERATIONAL_CC=1")
	}
	cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "fast")
	cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
	// We need larger stack overflow guards for ASAN, as the compiled code will have
	// larger frame sizes. For simplicity, just use global not-target-specific cflags.
	// Note: We increase this for both debug and non-debug, as the overflow gap will
	//       be compiled into managed code. We always preopt (and build core images) with
	//       the debug version. So make the gap consistent (and adjust for the worst).
	if len(ctx.AConfig().SanitizeDevice()) > 0 || len(ctx.AConfig().SanitizeHost()) > 0 {
		cflags = append(cflags,
			"-DART_STACK_OVERFLOW_GAP_arm=8192",
			"-DART_STACK_OVERFLOW_GAP_arm64=16384",
			"-DART_STACK_OVERFLOW_GAP_mips=16384",
			"-DART_STACK_OVERFLOW_GAP_mips64=16384",
			"-DART_STACK_OVERFLOW_GAP_x86=16384",
			"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
	} else {
		cflags = append(cflags,
			"-DART_STACK_OVERFLOW_GAP_arm=8192",
			"-DART_STACK_OVERFLOW_GAP_arm64=8192",
			"-DART_STACK_OVERFLOW_GAP_mips=16384",
			"-DART_STACK_OVERFLOW_GAP_mips64=16384",
			"-DART_STACK_OVERFLOW_GAP_x86=8192",
			"-DART_STACK_OVERFLOW_GAP_x86_64=8192")
	}
	if envTrue(ctx, "ART_ENABLE_ADDRESS_SANITIZER") {
		// Used to enable full sanitization, i.e., user poisoning, under ASAN.
		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
		asflags = append(asflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
	}
	if envTrue(ctx, "ART_MIPS32_CHECK_ALIGNMENT") {
		// Enable the use of MIPS32 CHECK_ALIGNMENT macro for debugging purposes
		asflags = append(asflags, "-DART_MIPS32_CHECK_ALIGNMENT")
	}
	if envTrueOrDefault(ctx, "USE_D8_DESUGAR") {
		cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
	}
	return cflags, asflags
}
func debugFlags(ctx android.BaseContext) []string {
	var cflags []string
	opt := envDefault(ctx, "ART_DEBUG_OPT_FLAG", "-O2")
	cflags = append(cflags, opt)
	return cflags
}
func deviceFlags(ctx android.BaseContext) []string {
	var cflags []string
	deviceFrameSizeLimit := 1736
	if len(ctx.AConfig().SanitizeDevice()) > 0 {
		deviceFrameSizeLimit = 7400
	}
	cflags = append(cflags,
		fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", deviceFrameSizeLimit),
	)
	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.AConfig().LibartImgDeviceBaseAddress())
	if envTrue(ctx, "ART_TARGET_LINUX") {
		cflags = append(cflags, "-DART_TARGET_LINUX")
	} else {
		cflags = append(cflags, "-DART_TARGET_ANDROID")
	}
	minDelta := envDefault(ctx, "LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
	maxDelta := envDefault(ctx, "LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
	return cflags
}
func hostFlags(ctx android.BaseContext) []string {
	var cflags []string
	hostFrameSizeLimit := 1736
	if len(ctx.AConfig().SanitizeHost()) > 0 {
		// art/test/137-cfi/cfi.cc
		// error: stack frame size of 1944 bytes in function 'Java_Main_unwindInProcess'
		hostFrameSizeLimit = 6400
	}
	cflags = append(cflags,
		fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
	)
	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.AConfig().LibartImgHostBaseAddress())
	minDelta := envDefault(ctx, "LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
	maxDelta := envDefault(ctx, "LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
	if len(ctx.AConfig().SanitizeHost()) > 0 && !envFalse(ctx, "ART_ENABLE_ADDRESS_SANITIZER") {
		// We enable full sanitization on the host by default.
		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
	}
	return cflags
}
func globalDefaults(ctx android.LoadHookContext) {
	type props struct {
		Target struct {
			Android struct {
				Cflags []string
			}
			Host struct {
				Cflags []string
			}
		}
		Cflags   []string
		Asflags  []string
		Sanitize struct {
			Recover []string
		}
	}
	p := &props{}
	p.Cflags, p.Asflags = globalFlags(ctx)
	p.Target.Android.Cflags = deviceFlags(ctx)
	p.Target.Host.Cflags = hostFlags(ctx)
	if envTrue(ctx, "ART_DEX_FILE_ACCESS_TRACKING") {
		p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
		p.Sanitize.Recover = []string{
			"address",
		}
	}
	ctx.AppendProperties(p)
}
func debugDefaults(ctx android.LoadHookContext) {
	type props struct {
		Cflags []string
	}
	p := &props{}
	p.Cflags = debugFlags(ctx)
	ctx.AppendProperties(p)
}
func customLinker(ctx android.LoadHookContext) {
	linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
	type props struct {
		DynamicLinker string
	}
	p := &props{}
	if linker != "" {
		p.DynamicLinker = linker
	}
	ctx.AppendProperties(p)
}
func prefer32Bit(ctx android.LoadHookContext) {
	type props struct {
		Target struct {
			Host struct {
				Compile_multilib *string
			}
		}
	}
	p := &props{}
	if envTrue(ctx, "HOST_PREFER_32_BIT") {
		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
	}
	ctx.AppendProperties(p)
}
var testMapKey = android.NewOnceKey("artTests")
func testMap(config android.Config) map[string][]string {
	return config.Once(testMapKey, func() interface{} {
		return make(map[string][]string)
	}).(map[string][]string)
}
func testInstall(ctx android.InstallHookContext) {
	testMap := testMap(ctx.AConfig())
	var name string
	if ctx.Host() {
		name = "host_"
	} else {
		name = "device_"
	}
	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
	artTestMutex.Lock()
	defer artTestMutex.Unlock()
	tests := testMap[name]
	tests = append(tests, ctx.Path().ToMakePath().String())
	testMap[name] = tests
}
var artTestMutex sync.Mutex
func init() {
	artModuleTypes := []string{
		"art_cc_library",
		"art_cc_library_static",
		"art_cc_binary",
		"art_cc_test",
		"art_cc_test_library",
		"art_cc_defaults",
		"libart_cc_defaults",
		"libart_static_cc_defaults",
		"art_global_defaults",
		"art_debug_defaults",
		"art_apex_test_host",
	}
	android.AddNeverAllowRules(
		android.NeverAllow().
			NotIn("art", "external/vixl").
			ModuleType(artModuleTypes...))
	android.RegisterModuleType("art_cc_library", artLibrary)
	android.RegisterModuleType("art_cc_library_static", artStaticLibrary)
	android.RegisterModuleType("art_cc_binary", artBinary)
	android.RegisterModuleType("art_cc_test", artTest)
	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
	android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory)
	android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
	// ART apex is special because it must include dexpreopt files for bootclasspath jars.
	android.RegisterModuleType("art_apex", artApexBundleFactory)
	android.RegisterModuleType("art_apex_test", artTestApexBundleFactory)
	// TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is
	// set. We need this because the multilib types of binaries listed in the apex
	// rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT
	// changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
	// only used for testing we can just disable the module.
	// See b/120617876 for more information.
	android.RegisterModuleType("art_apex_test_host", artHostTestApexBundleFactory)
}
func artApexBundleFactory() android.Module {
	return apex.ApexBundleFactory(false /*testApex*/, true /*artApex*/)
}
func artTestApexBundleFactory() android.Module {
	return apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
}
func artHostTestApexBundleFactory() android.Module {
	module := apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		if envTrue(ctx, "HOST_PREFER_32_BIT") {
			type props struct {
				Target struct {
					Host struct {
						Enabled *bool
					}
				}
			}
			p := &props{}
			p.Target.Host.Enabled = proptools.BoolPtr(false)
			ctx.AppendProperties(p)
			log.Print("Disabling host build of " + ctx.ModuleName() + " for HOST_PREFER_32_BIT=true")
		}
	})
	return module
}
func artGlobalDefaultsFactory() android.Module {
	module := artDefaultsFactory()
	android.AddLoadHook(module, globalDefaults)
	return module
}
func artDebugDefaultsFactory() android.Module {
	module := artDefaultsFactory()
	android.AddLoadHook(module, debugDefaults)
	return module
}
func artDefaultsFactory() android.Module {
	c := &codegenProperties{}
	module := cc.DefaultsFactory(c)
	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
	return module
}
func libartDefaultsFactory() android.Module {
	c := &codegenProperties{}
	module := cc.DefaultsFactory(c)
	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
	return module
}
func libartStaticDefaultsFactory() android.Module {
	c := &codegenProperties{}
	module := cc.DefaultsFactory(c)
	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticLibrary) })
	return module
}
func artLibrary() android.Module {
	m, _ := cc.NewLibrary(android.HostAndDeviceSupported)
	module := m.Init()
	installCodegenCustomizer(module, staticAndSharedLibrary)
	return module
}
func artStaticLibrary() android.Module {
	m, library := cc.NewLibrary(android.HostAndDeviceSupported)
	library.BuildOnlyStatic()
	module := m.Init()
	installCodegenCustomizer(module, staticLibrary)
	return module
}
func artBinary() android.Module {
	binary, _ := cc.NewBinary(android.HostAndDeviceSupported)
	module := binary.Init()
	android.AddLoadHook(module, customLinker)
	android.AddLoadHook(module, prefer32Bit)
	return module
}
func artTest() android.Module {
	test := cc.NewTest(android.HostAndDeviceSupported)
	module := test.Init()
	installCodegenCustomizer(module, binary)
	android.AddLoadHook(module, customLinker)
	android.AddLoadHook(module, prefer32Bit)
	android.AddInstallHook(module, testInstall)
	return module
}
func artTestLibrary() android.Module {
	test := cc.NewTestLibrary(android.HostAndDeviceSupported)
	module := test.Init()
	installCodegenCustomizer(module, staticAndSharedLibrary)
	android.AddLoadHook(module, prefer32Bit)
	android.AddInstallHook(module, testInstall)
	return module
}
func envDefault(ctx android.BaseContext, key string, defaultValue string) string {
	ret := ctx.AConfig().Getenv(key)
	if ret == "" {
		return defaultValue
	}
	return ret
}
func envTrue(ctx android.BaseContext, key string) bool {
	return ctx.AConfig().Getenv(key) == "true"
}
func envFalse(ctx android.BaseContext, key string) bool {
	return ctx.AConfig().Getenv(key) == "false"
}
func envTrueOrDefault(ctx android.BaseContext, key string) bool {
	return ctx.AConfig().Getenv(key) != "false"
}
           

https://android.googlesource.com/platform/external/llvm/+/master/soong/llvm.go

// Copyright (C) 2016 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 llvm
import (
	"android/soong/android"
	"android/soong/cc"
	"github.com/google/blueprint/proptools"
)
func globalFlags(ctx android.BaseContext) []string {
	var cflags []string
	if ctx.AConfig().IsEnvTrue("FORCE_BUILD_LLVM_DISABLE_NDEBUG") {
		cflags = append(cflags, "-D_DEBUG", "-UNDEBUG")
	}
	return cflags
}
func deviceFlags(ctx android.BaseContext) []string {
	var cflags []string
	return cflags
}
func hostFlags(ctx android.BaseContext) []string {
	var cflags []string
	if ctx.AConfig().IsEnvTrue("FORCE_BUILD_LLVM_DEBUG") {
		cflags = append(cflags, "-O0", "-g")
	}
	return cflags
}
func llvmDefaults(ctx android.LoadHookContext) {
	type props struct {
		Target struct {
			Android struct {
				Cflags  []string
				Enabled *bool
			}
			Host struct {
				Enabled *bool
			}
			Not_windows struct {
				Cflags []string
			}
		}
		Cflags []string
	}
	p := &props{}
	p.Cflags = globalFlags(ctx)
	p.Target.Android.Cflags = deviceFlags(ctx)
	// Mingw fails to link binaries with lots of debug information
	p.Target.Not_windows.Cflags = hostFlags(ctx)
	if ctx.AConfig().IsEnvTrue("DISABLE_LLVM_DEVICE_BUILDS") {
		p.Target.Android.Enabled = proptools.BoolPtr(false)
	}
	ctx.AppendProperties(p)
}
func forceBuildLlvmComponents(ctx android.LoadHookContext) {
	forceBuild := false
	if ctx.AConfig().IsEnvTrue("FORCE_BUILD_LLVM_COMPONENTS") {
		forceBuild = true
	}
	if len(ctx.AConfig().SanitizeHost()) > 0 {
		forceBuild = true
	}
	if !forceBuild {
		type props struct {
			Target struct {
				Host struct {
					Enabled *bool
				}
			}
		}
		p := &props{}
		p.Target.Host.Enabled = proptools.BoolPtr(false)
		ctx.AppendProperties(p)
	}
}
func init() {
	android.RegisterModuleType("llvm_defaults", llvmDefaultsFactory)
	android.RegisterModuleType("force_build_llvm_components_defaults", forceBuildLlvmComponentsDefaultsFactory)
}
func llvmDefaultsFactory() android.Module {
	module := cc.DefaultsFactory()
	android.AddLoadHook(module, llvmDefaults)
	return module
}
func forceBuildLlvmComponentsDefaultsFactory() android.Module {
	module := cc.DefaultsFactory()
	android.AddLoadHook(module, forceBuildLlvmComponents)
	return module
}