Add support for building NDK modules.

Change-Id: I2c5ede530e40a635e26ae45950580ef450e7dcc6
This commit is contained in:
Dan Albert 2015-03-18 23:38:50 -07:00
parent 68f55102da
commit be96168ee3
9 changed files with 224 additions and 14 deletions

View File

@ -17,13 +17,15 @@ const (
)
var stringProperties = map[string]string{
"LOCAL_MODULE": "name",
"LOCAL_MODULE_STEM": "stem",
"LOCAL_MODULE_CLASS": "class",
"LOCAL_CXX_STL": "stl",
"LOCAL_STRIP_MODULE": "strip",
"LOCAL_MULTILIB": "compile_multilib",
"LOCAL_ARM_MODE_HACK": "instruction_set",
"LOCAL_MODULE": "name",
"LOCAL_MODULE_STEM": "stem",
"LOCAL_MODULE_CLASS": "class",
"LOCAL_CXX_STL": "stl",
"LOCAL_STRIP_MODULE": "strip",
"LOCAL_MULTILIB": "compile_multilib",
"LOCAL_ARM_MODE_HACK": "instruction_set",
"LOCAL_SDK_VERSION": "sdk_version",
"LOCAL_NDK_STL_VARIANT": "stl",
}
var listProperties = map[string]string{

View File

@ -88,6 +88,10 @@ type toolchainArm64 struct {
var toolchainArm64Singleton = &toolchainArm64{}
func (t *toolchainArm64) Name() string {
return "arm64"
}
func (t *toolchainArm64) GccRoot() string {
return "${arm64GccRoot}"
}
@ -96,6 +100,10 @@ func (t *toolchainArm64) GccTriple() string {
return "${arm64GccTriple}"
}
func (t *toolchainArm64) GccVersion() string {
return "${arm64GccVersion}"
}
func (t *toolchainArm64) Cflags() string {
return "${arm64Cflags} ${arm64IncludeFlags}"
}

View File

@ -232,6 +232,10 @@ type toolchainArm struct {
cflags, ldflags, clangCflags string
}
func (t *toolchainArm) Name() string {
return "arm"
}
func (t *toolchainArm) GccRoot() string {
return "${armGccRoot}"
}
@ -240,6 +244,10 @@ func (t *toolchainArm) GccTriple() string {
return "${armGccTriple}"
}
func (t *toolchainArm) GccVersion() string {
return "${armGccVersion}"
}
func (t *toolchainArm) Cflags() string {
return t.cflags
}

184
cc/cc.go
View File

@ -146,7 +146,7 @@ type ccProperties struct {
// export_include_dirs: list of directories relative to the Blueprints file that will
// be added to the include path using -I for any module that links against this module
Export_include_dirs []string
Export_include_dirs []string `android:"arch_variant"`
// clang_cflags: list of module-specific flags that will be used for C and C++ compiles when
// compiling with clang
@ -350,6 +350,23 @@ func (c *ccBase) findToolchain(ctx common.AndroidModuleContext) Toolchain {
return factory(arch.ArchVariant, arch.CpuVariant)
}
func addNdkStlDepNames(ctx common.AndroidBaseContext, stl string, depNames CCDeps) CCDeps {
if stl == "ndk_system" {
// TODO: Make a system STL prebuilt for the NDK.
// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
// its own includes. The includes are handled in ccBase.Flags().
return depNames
}
if strings.HasSuffix(stl, "_static") {
depNames.StaticLibs = append(depNames.StaticLibs, stl)
} else {
depNames.SharedLibs = append(depNames.SharedLibs, stl)
}
return depNames
}
func (c *ccBase) DepNames(ctx common.AndroidBaseContext, depNames CCDeps) CCDeps {
depNames.WholeStaticLibs = append(depNames.WholeStaticLibs, c.properties.Whole_static_libs...)
depNames.StaticLibs = append(depNames.StaticLibs, c.properties.Static_libs...)
@ -369,6 +386,14 @@ func (c *ccBase) DepNames(ctx common.AndroidBaseContext, depNames CCDeps) CCDeps
depNames.SharedLibs = append(depNames.SharedLibs, "libstdc++", "libstlport")
case "stlport_static":
depNames.StaticLibs = append(depNames.StaticLibs, "libstdc++", "libstlport_static")
case "":
// None or error.
default:
if !strings.HasPrefix(stl, "ndk_") {
panic("unexpected case")
}
depNames = addNdkStlDepNames(ctx, stl, depNames)
}
return depNames
@ -533,6 +558,14 @@ func (c *ccBase) collectFlags(ctx common.AndroidModuleContext, toolchain Toolcha
}
func (c *ccBase) stl(ctx common.AndroidBaseContext) string {
if c.properties.Sdk_version != "" {
stl := c.properties.Stl
if stl == "" {
return "ndk_system"
}
return "ndk_lib" + stl
}
switch c.properties.Stl {
case "libc++", "libc++_static",
"stlport", "stlport_static",
@ -542,8 +575,6 @@ func (c *ccBase) stl(ctx common.AndroidBaseContext) string {
return ""
case "":
return "libc++" // TODO: mingw needs libstdc++
case "ndk":
panic("TODO: stl: ndk")
default:
ctx.ModuleErrorf("stl: %q is not a supported STL", c.properties.Stl)
return ""
@ -572,8 +603,6 @@ func (c *ccBase) Flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags {
"${SrcDir}/bionic/libstdc++/include",
"${SrcDir}/bionic")
}
case "ndk":
panic("TODO")
case "libstdc++":
// Using bionic's basic libstdc++. Not actually an STL. Only around until the
// tree is in good enough shape to not need it.
@ -581,14 +610,19 @@ func (c *ccBase) Flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags {
if ctx.Device() {
flags.IncludeDirs = append(flags.IncludeDirs, "${SrcDir}/bionic/libstdc++/include")
}
case "ndk_system":
ndkSrcRoot := ctx.Config().(Config).SrcDir() + "/prebuilts/ndk/current/sources/"
flags.IncludeDirs = append(flags.IncludeDirs, ndkSrcRoot + "cxx-stl/system/include")
case "ndk_c++_shared", "ndk_c++_static":
// TODO(danalbert): This really shouldn't be here...
flags.CppFlags = append(flags.CppFlags, "-std=c++11")
case "":
// None or error.
if ctx.Host() {
flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs")
flags.LdLibs = append(flags.LdLibs, "-lc", "-lm")
}
default:
panic(fmt.Errorf("Unknown stl: %q", stl))
}
return flags
@ -766,6 +800,17 @@ func (c *ccDynamic) systemSharedLibs(ctx common.AndroidBaseContext) []string {
if ctx.Host() {
return []string{}
} else if c.properties.Sdk_version != "" {
version := c.properties.Sdk_version
libs := []string{
"ndk_libc." + version,
"ndk_libm." + version,
}
if c.properties.Sdk_version != "" && c.stl(ctx) == "ndk_system" {
libs = append([]string{"libstdc++"}, libs...)
}
return libs
} else {
return []string{"libc", "libm"}
}
@ -1295,6 +1340,131 @@ func (c *toolchainLibrary) installModule(ctx common.AndroidModuleContext, flags
// Toolchain libraries do not get installed.
}
// NDK prebuilt libraries.
//
// These differ from regular prebuilts in that they aren't stripped and usually aren't installed
// either (with the exception of the shared STLs, which are installed to the app's directory rather
// than to the system image).
func getNdkLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, version string) string {
return fmt.Sprintf("%s/prebuilts/ndk/current/platforms/android-%s/arch-%s/usr/lib",
ctx.Config().(Config).SrcDir(), version, toolchain.Name())
}
type ndkPrebuiltLibrary struct {
CCLibrary
}
func (*ndkPrebuiltLibrary) AndroidDynamicDependencies(
ctx common.AndroidDynamicDependerModuleContext) []string {
// NDK libraries can't have any dependencies
return nil
}
func (*ndkPrebuiltLibrary) DepNames(ctx common.AndroidBaseContext, depNames CCDeps) CCDeps {
// NDK libraries can't have any dependencies
return CCDeps{}
}
func NdkPrebuiltLibraryFactory() (blueprint.Module, []interface{}) {
module := &ndkPrebuiltLibrary{}
module.LibraryProperties.BuildShared = true
return NewCCLibrary(&module.CCLibrary, module, common.DeviceSupported)
}
func (c *ndkPrebuiltLibrary) compileModule(ctx common.AndroidModuleContext, flags CCFlags,
deps CCDeps, objFiles []string) {
// A null build step, but it sets up the output path.
if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")
}
c.exportIncludeDirs = pathtools.PrefixPaths(c.properties.Export_include_dirs,
common.ModuleSrcDir(ctx))
// NDK prebuilt libraries are named like: ndk_LIBNAME.SDK_VERSION.
// We want to translate to just LIBNAME.
libName := strings.Split(strings.TrimPrefix(ctx.ModuleName(), "ndk_"), ".")[0]
libDir := getNdkLibDir(ctx, flags.Toolchain, c.properties.Sdk_version)
c.out = filepath.Join(libDir, libName + sharedLibraryExtension)
}
func (c *ndkPrebuiltLibrary) installModule(ctx common.AndroidModuleContext, flags CCFlags) {
// Toolchain libraries do not get installed.
}
// The NDK STLs are slightly different from the prebuilt system libraries:
// * Are not specific to each platform version.
// * The libraries are not in a predictable location for each STL.
type ndkPrebuiltStl struct {
ndkPrebuiltLibrary
}
type ndkPrebuiltStaticStl struct {
ndkPrebuiltStl
}
type ndkPrebuiltSharedStl struct {
ndkPrebuiltStl
}
func NdkPrebuiltSharedStlFactory() (blueprint.Module, []interface{}) {
module := &ndkPrebuiltSharedStl{}
module.LibraryProperties.BuildShared = true
return NewCCLibrary(&module.CCLibrary, module, common.DeviceSupported)
}
func NdkPrebuiltStaticStlFactory() (blueprint.Module, []interface{}) {
module := &ndkPrebuiltStaticStl{}
module.LibraryProperties.BuildStatic = true
return NewCCLibrary(&module.CCLibrary, module, common.DeviceSupported)
}
func getNdkStlLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, stl string) string {
gccVersion := toolchain.GccVersion()
var libDir string
switch stl {
case "libstlport":
libDir = "cxx-stl/stlport/libs"
case "libc++":
libDir = "cxx-stl/llvm-libc++/libs"
case "libgnustl":
libDir = fmt.Sprintf("cxx-stl/gnu-libstdc++/%s/libs", gccVersion)
}
if libDir != "" {
ndkSrcRoot := ctx.Config().(Config).SrcDir() + "/prebuilts/ndk/current/sources"
return fmt.Sprintf("%s/%s/%s", ndkSrcRoot, libDir, ctx.Arch().Abi)
}
ctx.ModuleErrorf("Unknown NDK STL: %s", stl)
return ""
}
func (c *ndkPrebuiltStl) compileModule(ctx common.AndroidModuleContext, flags CCFlags,
deps CCDeps, objFiles []string) {
// A null build step, but it sets up the output path.
if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")
}
c.exportIncludeDirs = pathtools.PrefixPaths(c.properties.Export_include_dirs,
common.ModuleSrcDir(ctx))
libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
libExt := sharedLibraryExtension
if c.LibraryProperties.BuildStatic {
libExt = staticLibraryExtension
}
stlName := strings.TrimSuffix(libName, "_shared")
stlName = strings.TrimSuffix(stlName, "_static")
libDir := getNdkStlLibDir(ctx, flags.Toolchain, stlName)
c.out = libDir + "/" + libName + libExt
}
func LinkageMutator(mctx blueprint.EarlyMutatorContext) {
if c, ok := mctx.Module().(ccLibraryInterface); ok {
var modules []blueprint.Module

View File

@ -34,8 +34,11 @@ func registerToolchainFactory(hod common.HostOrDevice, arch common.ArchType,
}
type Toolchain interface {
Name() string
GccRoot() string
GccTriple() string
GccVersion() string
Cflags() string
Cppflags() string
Ldflags() string

View File

@ -148,6 +148,14 @@ type toolchainLinuxX8664 struct {
toolchainLinux
}
func (t *toolchainLinuxX86) Name() string {
return "x86"
}
func (t *toolchainLinuxX8664) Name() string {
return "x86_64"
}
func (t *toolchainLinux) GccRoot() string {
return "${linuxGccRoot}"
}
@ -156,6 +164,10 @@ func (t *toolchainLinux) GccTriple() string {
return "${linuxGccTriple}"
}
func (t *toolchainLinux) GccVersion() string {
return "${linuxGccVersion}"
}
func (t *toolchainLinuxX86) Cflags() string {
return "${linuxCflags} ${linuxX86Cflags}"
}

View File

@ -47,6 +47,9 @@ func main() {
ctx.RegisterModuleType("cc_test", cc.CCTestFactory)
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.RegisterModuleType("ndk_prebuilt_library", cc.NdkPrebuiltLibraryFactory)
ctx.RegisterModuleType("ndk_prebuilt_static_stl", cc.NdkPrebuiltStaticStlFactory)
ctx.RegisterModuleType("ndk_prebuilt_shared_stl", cc.NdkPrebuiltSharedStlFactory)
ctx.RegisterModuleType("cc_library_host_static", cc.CCLibraryHostStaticFactory)
ctx.RegisterModuleType("cc_library_host_shared", cc.CCLibraryHostSharedFactory)

View File

@ -117,6 +117,7 @@ type Arch struct {
ArchType ArchType
ArchVariant string
CpuVariant string
Abi string
}
func (a Arch) String() string {
@ -234,12 +235,14 @@ var (
ArchType: Arm,
ArchVariant: "armv7-a-neon",
CpuVariant: "cortex-a15",
Abi: "armeabi-v7a",
}
arm64Arch = Arch{
HostOrDevice: Device,
ArchType: Arm64,
ArchVariant: "armv8-a",
CpuVariant: "denver",
Abi: "arm64-v8a",
}
hostArch = Arch{
HostOrDevice: Host,

View File

@ -5,5 +5,6 @@ subdirs = [
"bionic/*",
"external/*",
"libnativehelper",
"prebuilts/ndk",
"system/core/*",
]