Merge "Generate NDK sysroots from the platform build."
This commit is contained in:
commit
c6b4e452b4
|
@ -134,6 +134,10 @@ bootstrap_go_package {
|
||||||
"cc/toolchain.go",
|
"cc/toolchain.go",
|
||||||
"cc/util.go",
|
"cc/util.go",
|
||||||
|
|
||||||
|
"cc/ndk_headers.go",
|
||||||
|
"cc/ndk_library.go",
|
||||||
|
"cc/ndk_sysroot.go",
|
||||||
|
|
||||||
"cc/arm_device.go",
|
"cc/arm_device.go",
|
||||||
"cc/arm64_device.go",
|
"cc/arm64_device.go",
|
||||||
"cc/mips_device.go",
|
"cc/mips_device.go",
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
@ -183,3 +184,22 @@ func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.And
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *stubCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
|
||||||
|
ret.SubName = "." + strconv.Itoa(c.properties.ApiLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (installer *stubInstaller) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
|
||||||
|
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
|
||||||
|
path, file := filepath.Split(installer.installPath)
|
||||||
|
stem := strings.TrimSuffix(file, filepath.Ext(file))
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
|
||||||
|
|
||||||
|
// Prevent make from installing the libraries to obj/lib (since we have
|
||||||
|
// dozens of libraries with the same name, they'll clobber each other
|
||||||
|
// and the real versions of the libraries from the platform).
|
||||||
|
fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
113
cc/cc.go
113
cc/cc.go
|
@ -58,6 +58,7 @@ func init() {
|
||||||
// the Go initialization order because this package depends on common, so common's init
|
// the Go initialization order because this package depends on common, so common's init
|
||||||
// functions will run first.
|
// functions will run first.
|
||||||
android.RegisterBottomUpMutator("link", linkageMutator)
|
android.RegisterBottomUpMutator("link", linkageMutator)
|
||||||
|
android.RegisterBottomUpMutator("ndk_api", ndkApiMutator)
|
||||||
android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
|
android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
|
||||||
android.RegisterBottomUpMutator("deps", depsMutator)
|
android.RegisterBottomUpMutator("deps", depsMutator)
|
||||||
|
|
||||||
|
@ -70,6 +71,10 @@ func init() {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
|
HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
|
||||||
|
|
||||||
|
// These libraries have migrated over to the new ndk_library, which is added
|
||||||
|
// as a variation dependency via depsMutator.
|
||||||
|
ndkMigratedLibs = []string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Flags used by lots of devices. Putting them in package static variables will save bytes in
|
// Flags used by lots of devices. Putting them in package static variables will save bytes in
|
||||||
|
@ -555,6 +560,8 @@ var (
|
||||||
crtBeginDepTag = dependencyTag{name: "crtbegin"}
|
crtBeginDepTag = dependencyTag{name: "crtbegin"}
|
||||||
crtEndDepTag = dependencyTag{name: "crtend"}
|
crtEndDepTag = dependencyTag{name: "crtend"}
|
||||||
reuseObjTag = dependencyTag{name: "reuse objects"}
|
reuseObjTag = dependencyTag{name: "reuse objects"}
|
||||||
|
ndkStubDepTag = dependencyTag{name: "ndk stub", library: true}
|
||||||
|
ndkLateStubDepTag = dependencyTag{name: "ndk late stub", library: true}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module contains the properties and members used by all C/C++ module types, and implements
|
// Module contains the properties and members used by all C/C++ module types, and implements
|
||||||
|
@ -883,20 +890,40 @@ func (c *Module) depsMutator(actx android.BottomUpMutatorContext) {
|
||||||
c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.SharedLibs...)
|
c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.SharedLibs...)
|
||||||
c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.LateSharedLibs...)
|
c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.LateSharedLibs...)
|
||||||
|
|
||||||
|
variantNdkLibs := []string{}
|
||||||
|
variantLateNdkLibs := []string{}
|
||||||
if ctx.sdk() {
|
if ctx.sdk() {
|
||||||
version := "." + ctx.sdkVersion()
|
version := ctx.sdkVersion()
|
||||||
|
|
||||||
rewriteNdkLibs := func(list []string) []string {
|
// Rewrites the names of shared libraries into the names of the NDK
|
||||||
for i, entry := range list {
|
// libraries where appropriate. This returns two slices.
|
||||||
|
//
|
||||||
|
// The first is a list of non-variant shared libraries (either rewritten
|
||||||
|
// NDK libraries to the modules in prebuilts/ndk, or not rewritten
|
||||||
|
// because they are not NDK libraries).
|
||||||
|
//
|
||||||
|
// The second is a list of ndk_library modules. These need to be
|
||||||
|
// separated because they are a variation dependency and must be added
|
||||||
|
// in a different manner.
|
||||||
|
rewriteNdkLibs := func(list []string) ([]string, []string) {
|
||||||
|
variantLibs := []string{}
|
||||||
|
nonvariantLibs := []string{}
|
||||||
|
for _, entry := range list {
|
||||||
if inList(entry, ndkPrebuiltSharedLibraries) {
|
if inList(entry, ndkPrebuiltSharedLibraries) {
|
||||||
list[i] = "ndk_" + entry + version
|
if !inList(entry, ndkMigratedLibs) {
|
||||||
|
nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version)
|
||||||
|
} else {
|
||||||
|
variantLibs = append(variantLibs, entry+ndkLibrarySuffix)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nonvariantLibs = append(variantLibs, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list
|
return nonvariantLibs, variantLibs
|
||||||
}
|
}
|
||||||
|
|
||||||
deps.SharedLibs = rewriteNdkLibs(deps.SharedLibs)
|
deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs)
|
||||||
deps.LateSharedLibs = rewriteNdkLibs(deps.LateSharedLibs)
|
deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
|
||||||
}
|
}
|
||||||
|
|
||||||
actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, wholeStaticDepTag,
|
actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, wholeStaticDepTag,
|
||||||
|
@ -935,6 +962,12 @@ func (c *Module) depsMutator(actx android.BottomUpMutatorContext) {
|
||||||
if deps.CrtEnd != "" {
|
if deps.CrtEnd != "" {
|
||||||
actx.AddDependency(c, crtEndDepTag, deps.CrtEnd)
|
actx.AddDependency(c, crtEndDepTag, deps.CrtEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version := ctx.sdkVersion()
|
||||||
|
actx.AddVariationDependencies([]blueprint.Variation{
|
||||||
|
{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
|
||||||
|
actx.AddVariationDependencies([]blueprint.Variation{
|
||||||
|
{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func depsMutator(ctx android.BottomUpMutatorContext) {
|
func depsMutator(ctx android.BottomUpMutatorContext) {
|
||||||
|
@ -990,6 +1023,11 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
||||||
// These are allowed, but don't set sdk_version
|
// These are allowed, but don't set sdk_version
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if _, ok := to.linker.(*stubLinker); ok {
|
||||||
|
// These aren't real libraries, but are the stub shared libraries that are included in
|
||||||
|
// the NDK.
|
||||||
|
return true
|
||||||
|
}
|
||||||
return to.Properties.Sdk_version != ""
|
return to.Properties.Sdk_version != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,9 +1111,9 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
||||||
var depPtr *android.Paths
|
var depPtr *android.Paths
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case sharedDepTag, sharedExportDepTag:
|
case ndkStubDepTag, sharedDepTag, sharedExportDepTag:
|
||||||
depPtr = &depPaths.SharedLibs
|
depPtr = &depPaths.SharedLibs
|
||||||
case lateSharedDepTag:
|
case lateSharedDepTag, ndkLateStubDepTag:
|
||||||
depPtr = &depPaths.LateSharedLibs
|
depPtr = &depPaths.LateSharedLibs
|
||||||
case staticDepTag, staticExportDepTag:
|
case staticDepTag, staticExportDepTag:
|
||||||
depPtr = &depPaths.StaticLibs
|
depPtr = &depPaths.StaticLibs
|
||||||
|
@ -1190,6 +1228,30 @@ func (compiler *baseCompiler) flags(ctx ModuleContext, flags Flags) Flags {
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.sdk() {
|
||||||
|
// The NDK headers are installed to a common sysroot. While a more
|
||||||
|
// typical Soong approach would be to only make the headers for the
|
||||||
|
// library you're using available, we're trying to emulate the NDK
|
||||||
|
// behavior here, and the NDK always has all the NDK headers available.
|
||||||
|
flags.GlobalFlags = append(flags.GlobalFlags,
|
||||||
|
"-isystem "+getCurrentIncludePath(ctx).String(),
|
||||||
|
"-isystem "+getCurrentIncludePath(ctx).Join(ctx, toolchain.ClangTriple()).String())
|
||||||
|
|
||||||
|
// Traditionally this has come from android/api-level.h, but with the
|
||||||
|
// libc headers unified it must be set by the build system since we
|
||||||
|
// don't have per-API level copies of that header now.
|
||||||
|
flags.GlobalFlags = append(flags.GlobalFlags,
|
||||||
|
"-D__ANDROID_API__="+ctx.sdkVersion())
|
||||||
|
|
||||||
|
// Until the full NDK has been migrated to using ndk_headers, we still
|
||||||
|
// need to add the legacy sysroot includes to get the full set of
|
||||||
|
// headers.
|
||||||
|
legacyIncludes := fmt.Sprintf(
|
||||||
|
"prebuilts/ndk/current/platforms/android-%s/arch-%s/usr/include",
|
||||||
|
ctx.sdkVersion(), ctx.Arch().ArchType.String())
|
||||||
|
flags.GlobalFlags = append(flags.GlobalFlags, "-isystem "+legacyIncludes)
|
||||||
|
}
|
||||||
|
|
||||||
instructionSet := compiler.Properties.Instruction_set
|
instructionSet := compiler.Properties.Instruction_set
|
||||||
if flags.RequiredInstructionSet != "" {
|
if flags.RequiredInstructionSet != "" {
|
||||||
instructionSet = flags.RequiredInstructionSet
|
instructionSet = flags.RequiredInstructionSet
|
||||||
|
@ -1310,11 +1372,22 @@ func (compiler *baseCompiler) flags(ctx ModuleContext, flags Flags) Flags {
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ndkPathDeps(ctx ModuleContext) android.Paths {
|
||||||
|
if ctx.sdk() {
|
||||||
|
// The NDK sysroot timestamp file depends on all the NDK sysroot files
|
||||||
|
// (headers and libraries).
|
||||||
|
return android.Paths{getNdkSysrootTimestampFile(ctx)}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
|
func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
|
||||||
|
pathDeps := deps.GeneratedHeaders
|
||||||
|
pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
|
||||||
// Compile files listed in c.Properties.Srcs into objects
|
// Compile files listed in c.Properties.Srcs into objects
|
||||||
objFiles := compiler.compileObjs(ctx, flags, "",
|
objFiles := compiler.compileObjs(ctx, flags, "",
|
||||||
compiler.Properties.Srcs, compiler.Properties.Exclude_srcs,
|
compiler.Properties.Srcs, compiler.Properties.Exclude_srcs,
|
||||||
deps.GeneratedSources, deps.GeneratedHeaders)
|
deps.GeneratedSources, pathDeps)
|
||||||
|
|
||||||
if ctx.Failed() {
|
if ctx.Failed() {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1595,14 +1668,17 @@ func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps Pat
|
||||||
objFiles = library.baseCompiler.compile(ctx, flags, deps)
|
objFiles = library.baseCompiler.compile(ctx, flags, deps)
|
||||||
library.reuseObjFiles = objFiles
|
library.reuseObjFiles = objFiles
|
||||||
|
|
||||||
|
pathDeps := deps.GeneratedHeaders
|
||||||
|
pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
|
||||||
|
|
||||||
if library.linker.static() {
|
if library.linker.static() {
|
||||||
objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceStaticLibrary,
|
objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceStaticLibrary,
|
||||||
library.Properties.Static.Srcs, library.Properties.Static.Exclude_srcs,
|
library.Properties.Static.Srcs, library.Properties.Static.Exclude_srcs,
|
||||||
nil, deps.GeneratedHeaders)...)
|
nil, pathDeps)...)
|
||||||
} else {
|
} else {
|
||||||
objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceSharedLibrary,
|
objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceSharedLibrary,
|
||||||
library.Properties.Shared.Srcs, library.Properties.Shared.Exclude_srcs,
|
library.Properties.Shared.Srcs, library.Properties.Shared.Exclude_srcs,
|
||||||
nil, deps.GeneratedHeaders)...)
|
nil, pathDeps)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return objFiles
|
return objFiles
|
||||||
|
@ -1626,6 +1702,10 @@ type libraryLinker struct {
|
||||||
|
|
||||||
// For whole_static_libs
|
// For whole_static_libs
|
||||||
objFiles android.Paths
|
objFiles android.Paths
|
||||||
|
|
||||||
|
// Uses the module's name if empty, but can be overridden. Does not include
|
||||||
|
// shlib suffix.
|
||||||
|
libName string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ linker = (*libraryLinker)(nil)
|
var _ linker = (*libraryLinker)(nil)
|
||||||
|
@ -1646,7 +1726,10 @@ func (library *libraryLinker) props() []interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (library *libraryLinker) getLibName(ctx ModuleContext) string {
|
func (library *libraryLinker) getLibName(ctx ModuleContext) string {
|
||||||
name := ctx.ModuleName()
|
name := library.libName
|
||||||
|
if name == "" {
|
||||||
|
name = ctx.ModuleName()
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
|
if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
|
||||||
if !strings.HasSuffix(name, "-host") {
|
if !strings.HasSuffix(name, "-host") {
|
||||||
|
@ -2634,10 +2717,6 @@ func ndkPrebuiltLibraryFactory() (blueprint.Module, []interface{}) {
|
||||||
func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags,
|
func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags,
|
||||||
deps PathDeps, objFiles android.Paths) android.Path {
|
deps PathDeps, objFiles android.Paths) android.Path {
|
||||||
// A null build step, but it sets up the output path.
|
// 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
ndk.exportIncludes(ctx, "-isystem")
|
ndk.exportIncludes(ctx, "-isystem")
|
||||||
|
|
||||||
return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, flags.Toolchain.ShlibSuffix(),
|
return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, flags.Toolchain.ShlibSuffix(),
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
"""Generates source for stub shared libraries for the NDK."""
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
ALL_ARCHITECTURES = (
|
||||||
|
'arm',
|
||||||
|
'arm64',
|
||||||
|
'mips',
|
||||||
|
'mips64',
|
||||||
|
'x86',
|
||||||
|
'x86_64',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Scope(object):
|
||||||
|
"""Enum for version script scope.
|
||||||
|
|
||||||
|
Top: Top level of the file.
|
||||||
|
Global: In a version and visibility section where symbols should be visible
|
||||||
|
to the NDK.
|
||||||
|
Local: In a visibility section of a public version where symbols should be
|
||||||
|
hidden to the NDK.
|
||||||
|
Private: In a version where symbols should not be visible to the NDK.
|
||||||
|
"""
|
||||||
|
Top = 1
|
||||||
|
Global = 2
|
||||||
|
Local = 3
|
||||||
|
Private = 4
|
||||||
|
|
||||||
|
|
||||||
|
class Stack(object):
|
||||||
|
"""Basic stack implementation."""
|
||||||
|
def __init__(self):
|
||||||
|
self.stack = []
|
||||||
|
|
||||||
|
def push(self, obj):
|
||||||
|
"""Push an item on to the stack."""
|
||||||
|
self.stack.append(obj)
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
"""Remove and return the item on the top of the stack."""
|
||||||
|
return self.stack.pop()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def top(self):
|
||||||
|
"""Return the top of the stack."""
|
||||||
|
return self.stack[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def version_is_private(version):
|
||||||
|
"""Returns True if the version name should be treated as private."""
|
||||||
|
return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
|
||||||
|
|
||||||
|
|
||||||
|
def enter_version(scope, line, version_file):
|
||||||
|
"""Enters a new version block scope."""
|
||||||
|
if scope.top != Scope.Top:
|
||||||
|
raise RuntimeError('Encountered nested version block.')
|
||||||
|
|
||||||
|
# Entering a new version block. By convention symbols with versions ending
|
||||||
|
# with "_PRIVATE" or "_PLATFORM" are not included in the NDK.
|
||||||
|
version_name = line.split('{')[0].strip()
|
||||||
|
if version_is_private(version_name):
|
||||||
|
scope.push(Scope.Private)
|
||||||
|
else:
|
||||||
|
scope.push(Scope.Global) # By default symbols are visible.
|
||||||
|
version_file.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def leave_version(scope, line, version_file):
|
||||||
|
"""Leave a version block scope."""
|
||||||
|
# There is no close to a visibility section, just the end of the version or
|
||||||
|
# a new visiblity section.
|
||||||
|
assert scope.top in (Scope.Global, Scope.Local, Scope.Private)
|
||||||
|
if scope.top != Scope.Private:
|
||||||
|
version_file.write(line)
|
||||||
|
scope.pop()
|
||||||
|
assert scope.top == Scope.Top
|
||||||
|
|
||||||
|
|
||||||
|
def enter_visibility(scope, line, version_file):
|
||||||
|
"""Enters a new visibility block scope."""
|
||||||
|
leave_visibility(scope)
|
||||||
|
version_file.write(line)
|
||||||
|
visibility = line.split(':')[0].strip()
|
||||||
|
if visibility == 'local':
|
||||||
|
scope.push(Scope.Local)
|
||||||
|
elif visibility == 'global':
|
||||||
|
scope.push(Scope.Global)
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Unknown visiblity label: ' + visibility)
|
||||||
|
|
||||||
|
|
||||||
|
def leave_visibility(scope):
|
||||||
|
"""Leaves a visibility block scope."""
|
||||||
|
assert scope.top in (Scope.Global, Scope.Local)
|
||||||
|
scope.pop()
|
||||||
|
assert scope.top == Scope.Top
|
||||||
|
|
||||||
|
|
||||||
|
def handle_top_scope(scope, line, version_file):
|
||||||
|
"""Processes a line in the top level scope."""
|
||||||
|
if '{' in line:
|
||||||
|
enter_version(scope, line, version_file)
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Unexpected contents at top level: ' + line)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_private_scope(scope, line, version_file):
|
||||||
|
"""Eats all input."""
|
||||||
|
if '}' in line:
|
||||||
|
leave_version(scope, line, version_file)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_local_scope(scope, line, version_file):
|
||||||
|
"""Passes through input."""
|
||||||
|
if ':' in line:
|
||||||
|
enter_visibility(scope, line, version_file)
|
||||||
|
elif '}' in line:
|
||||||
|
leave_version(scope, line, version_file)
|
||||||
|
else:
|
||||||
|
version_file.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def symbol_in_arch(tags, arch):
|
||||||
|
"""Returns true if the symbol is present for the given architecture."""
|
||||||
|
has_arch_tags = False
|
||||||
|
for tag in tags:
|
||||||
|
if tag == arch:
|
||||||
|
return True
|
||||||
|
if tag in ALL_ARCHITECTURES:
|
||||||
|
has_arch_tags = True
|
||||||
|
|
||||||
|
# If there were no arch tags, the symbol is available for all
|
||||||
|
# architectures. If there were any arch tags, the symbol is only available
|
||||||
|
# for the tagged architectures.
|
||||||
|
return not has_arch_tags
|
||||||
|
|
||||||
|
|
||||||
|
def symbol_in_version(tags, arch, version):
|
||||||
|
"""Returns true if the symbol is present for the given version."""
|
||||||
|
introduced_tag = None
|
||||||
|
arch_specific = False
|
||||||
|
for tag in tags:
|
||||||
|
# If there is an arch-specific tag, it should override the common one.
|
||||||
|
if tag.startswith('introduced=') and not arch_specific:
|
||||||
|
introduced_tag = tag
|
||||||
|
elif tag.startswith('introduced-' + arch + '='):
|
||||||
|
introduced_tag = tag
|
||||||
|
arch_specific = True
|
||||||
|
|
||||||
|
if introduced_tag is None:
|
||||||
|
# We found no "introduced" tags, so the symbol has always been
|
||||||
|
# available.
|
||||||
|
return True
|
||||||
|
|
||||||
|
# The tag is a key=value pair, and we only care about the value now.
|
||||||
|
_, _, version_str = introduced_tag.partition('=')
|
||||||
|
return version >= int(version_str)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_global_scope(scope, line, src_file, version_file, arch, api):
|
||||||
|
"""Emits present symbols to the version file and stub source file."""
|
||||||
|
if ':' in line:
|
||||||
|
enter_visibility(scope, line, version_file)
|
||||||
|
return
|
||||||
|
if '}' in line:
|
||||||
|
leave_version(scope, line, version_file)
|
||||||
|
return
|
||||||
|
|
||||||
|
if ';' not in line:
|
||||||
|
raise RuntimeError('Expected ; to terminate symbol: ' + line)
|
||||||
|
if '*' in line:
|
||||||
|
raise RuntimeError('Wildcard global symbols are not permitted.')
|
||||||
|
|
||||||
|
# Line is now in the format "<symbol-name>; # tags"
|
||||||
|
# Tags are whitespace separated.
|
||||||
|
symbol_name, _, rest = line.strip().partition(';')
|
||||||
|
_, _, all_tags = rest.partition('#')
|
||||||
|
tags = re.split(r'\s+', all_tags)
|
||||||
|
|
||||||
|
if not symbol_in_arch(tags, arch):
|
||||||
|
return
|
||||||
|
if not symbol_in_version(tags, arch, api):
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'var' in tags:
|
||||||
|
src_file.write('int {} = 0;\n'.format(symbol_name))
|
||||||
|
else:
|
||||||
|
src_file.write('void {}() {{}}\n'.format(symbol_name))
|
||||||
|
version_file.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def generate(symbol_file, src_file, version_file, arch, api):
|
||||||
|
"""Generates the stub source file and version script."""
|
||||||
|
scope = Stack()
|
||||||
|
scope.push(Scope.Top)
|
||||||
|
for line in symbol_file:
|
||||||
|
if line.strip() == '' or line.strip().startswith('#'):
|
||||||
|
version_file.write(line)
|
||||||
|
elif scope.top == Scope.Top:
|
||||||
|
handle_top_scope(scope, line, version_file)
|
||||||
|
elif scope.top == Scope.Private:
|
||||||
|
handle_private_scope(scope, line, version_file)
|
||||||
|
elif scope.top == Scope.Local:
|
||||||
|
handle_local_scope(scope, line, version_file)
|
||||||
|
elif scope.top == Scope.Global:
|
||||||
|
handle_global_scope(scope, line, src_file, version_file, arch, api)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
"""Parses and returns command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument('--api', type=int, help='API level being targeted.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--arch', choices=ALL_ARCHITECTURES,
|
||||||
|
help='Architecture being targeted.')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'symbol_file', type=os.path.realpath, help='Path to symbol file.')
|
||||||
|
parser.add_argument(
|
||||||
|
'stub_src', type=os.path.realpath,
|
||||||
|
help='Path to output stub source file.')
|
||||||
|
parser.add_argument(
|
||||||
|
'version_script', type=os.path.realpath,
|
||||||
|
help='Path to output version script.')
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Program entry point."""
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
with open(args.symbol_file) as symbol_file:
|
||||||
|
with open(args.stub_src, 'w') as src_file:
|
||||||
|
with open(args.version_script, 'w') as version_file:
|
||||||
|
generate(symbol_file, src_file, version_file, args.arch,
|
||||||
|
args.api)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -50,6 +50,8 @@ func makeVarsProvider(ctx android.MakeVarsContext) {
|
||||||
ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " "))
|
ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " "))
|
||||||
ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " "))
|
ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " "))
|
||||||
|
|
||||||
|
ctx.Strict("NDK_MIGRATED_LIBS", strings.Join(ndkMigratedLibs, " "))
|
||||||
|
|
||||||
hostTargets := ctx.Config().Targets[android.Host]
|
hostTargets := ctx.Config().Targets[android.Host]
|
||||||
makeVarsToolchain(ctx, "", hostTargets[0])
|
makeVarsToolchain(ctx, "", hostTargets[0])
|
||||||
if len(hostTargets) > 1 {
|
if len(hostTargets) > 1 {
|
||||||
|
@ -198,6 +200,7 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string,
|
||||||
ctx.Strict(makePrefix+"STRIP", gccCmd(toolchain, "strip"))
|
ctx.Strict(makePrefix+"STRIP", gccCmd(toolchain, "strip"))
|
||||||
ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
|
ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
|
||||||
ctx.Strict(makePrefix+"NDK_GCC_VERSION", toolchain.GccVersion())
|
ctx.Strict(makePrefix+"NDK_GCC_VERSION", toolchain.GccVersion())
|
||||||
|
ctx.Strict(makePrefix+"NDK_TRIPLE", toolchain.ClangTriple())
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Strict(makePrefix+"TOOLCHAIN_ROOT", toolchain.GccRoot())
|
ctx.Strict(makePrefix+"TOOLCHAIN_ROOT", toolchain.GccRoot())
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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 cc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Returns the NDK base include path for use with sdk_version current. Usable with -I.
|
||||||
|
func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
|
||||||
|
return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerProperies struct {
|
||||||
|
// Base directory of the headers being installed. As an example:
|
||||||
|
//
|
||||||
|
// ndk_headers {
|
||||||
|
// name: "foo",
|
||||||
|
// from: "include",
|
||||||
|
// to: "",
|
||||||
|
// srcs: ["include/foo/bar/baz.h"],
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
|
||||||
|
// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
|
||||||
|
From string
|
||||||
|
|
||||||
|
// Install path within the sysroot. This is relative to usr/include.
|
||||||
|
To string
|
||||||
|
|
||||||
|
// List of headers to install. Glob compatible. Common case is "include/**/*.h".
|
||||||
|
Srcs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerModule struct {
|
||||||
|
android.ModuleBase
|
||||||
|
|
||||||
|
properties headerProperies
|
||||||
|
|
||||||
|
installPaths []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
|
||||||
|
for _, header := range srcFiles {
|
||||||
|
// Output path is the sysroot base + "usr/include" + to directory + directory component
|
||||||
|
// of the file without the leading from directory stripped.
|
||||||
|
//
|
||||||
|
// Given:
|
||||||
|
// sysroot base = "ndk/sysroot"
|
||||||
|
// from = "include/foo"
|
||||||
|
// to = "bar"
|
||||||
|
// header = "include/foo/woodly/doodly.h"
|
||||||
|
// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
|
||||||
|
|
||||||
|
// full/platform/path/to/include/foo
|
||||||
|
fullFromPath := android.PathForModuleSrc(ctx, m.properties.From)
|
||||||
|
|
||||||
|
// full/platform/path/to/include/foo/woodly
|
||||||
|
headerDir := filepath.Dir(header.String())
|
||||||
|
|
||||||
|
// woodly
|
||||||
|
strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
|
||||||
|
fullFromPath.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// full/platform/path/to/sysroot/usr/include/bar/woodly
|
||||||
|
installDir := getCurrentIncludePath(ctx).Join(ctx, m.properties.To, strippedHeaderDir)
|
||||||
|
|
||||||
|
// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
|
||||||
|
installPath := ctx.InstallFile(installDir, header)
|
||||||
|
m.installPaths = append(m.installPaths, installPath.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.installPaths) == 0 {
|
||||||
|
ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ndkHeadersFactory() (blueprint.Module, []interface{}) {
|
||||||
|
module := &headerModule{}
|
||||||
|
return android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst,
|
||||||
|
&module.properties)
|
||||||
|
}
|
|
@ -0,0 +1,250 @@
|
||||||
|
// 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 cc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
|
||||||
|
|
||||||
|
genStubSrc = pctx.StaticRule("genStubSrc",
|
||||||
|
blueprint.RuleParams{
|
||||||
|
Command: "$toolPath --arch $arch --api $apiLevel $in $out",
|
||||||
|
Description: "genStubSrc $out",
|
||||||
|
CommandDeps: []string{"$toolPath"},
|
||||||
|
}, "arch", "apiLevel")
|
||||||
|
|
||||||
|
ndkLibrarySuffix = ".ndk"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Creates a stub shared library based on the provided version file.
|
||||||
|
//
|
||||||
|
// The name of the generated file will be based on the module name by stripping
|
||||||
|
// the ".ndk" suffix from the module name. Module names must end with ".ndk"
|
||||||
|
// (as a convention to allow soong to guess the NDK name of a dependency when
|
||||||
|
// needed). "libfoo.ndk" will generate "libfoo.so.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// ndk_library {
|
||||||
|
// name: "libfoo.ndk",
|
||||||
|
// symbol_file: "libfoo.map.txt",
|
||||||
|
// first_version: "9",
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type libraryProperties struct {
|
||||||
|
// Relative path to the symbol map.
|
||||||
|
// An example file can be seen here: TODO(danalbert): Make an example.
|
||||||
|
Symbol_file string
|
||||||
|
|
||||||
|
// The first API level a library was available. A library will be generated
|
||||||
|
// for every API level beginning with this one.
|
||||||
|
First_version string
|
||||||
|
|
||||||
|
// Private property for use by the mutator that splits per-API level.
|
||||||
|
ApiLevel int `blueprint:"mutated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type stubCompiler struct {
|
||||||
|
baseCompiler
|
||||||
|
|
||||||
|
properties libraryProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// OMG GO
|
||||||
|
func intMin(a int, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
} else {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubCompiler) {
|
||||||
|
minVersion := 9 // Minimum version supported by the NDK.
|
||||||
|
// TODO(danalbert): Use PlatformSdkVersion when possible.
|
||||||
|
// This is an interesting case because for the moment we actually need 24
|
||||||
|
// even though the latest released version in aosp is 23. prebuilts/ndk/r11
|
||||||
|
// has android-24 versions of libraries, and as platform libraries get
|
||||||
|
// migrated the libraries in prebuilts will need to depend on them.
|
||||||
|
//
|
||||||
|
// Once everything is all moved over to the new stuff (when there isn't a
|
||||||
|
// prebuilts/ndk any more) then this should be fixable, but for now I think
|
||||||
|
// it needs to remain as-is.
|
||||||
|
maxVersion := 24
|
||||||
|
firstArchVersions := map[string]int{
|
||||||
|
"arm": 9,
|
||||||
|
"arm64": 21,
|
||||||
|
"mips": 9,
|
||||||
|
"mips64": 21,
|
||||||
|
"x86": 9,
|
||||||
|
"x86_64": 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the NDK drops support for a platform version, we don't want to have to
|
||||||
|
// fix up every module that was using it as its minimum version. Clip to the
|
||||||
|
// supported version here instead.
|
||||||
|
firstVersion, err := strconv.Atoi(c.properties.First_version)
|
||||||
|
if err != nil {
|
||||||
|
mctx.ModuleErrorf("Invalid first_version value (must be int): %q",
|
||||||
|
c.properties.First_version)
|
||||||
|
}
|
||||||
|
if firstVersion < minVersion {
|
||||||
|
firstVersion = minVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
arch := mctx.Arch().ArchType.String()
|
||||||
|
firstArchVersion, ok := firstArchVersions[arch]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch))
|
||||||
|
}
|
||||||
|
firstGenVersion := intMin(firstVersion, firstArchVersion)
|
||||||
|
versionStrs := make([]string, maxVersion-firstGenVersion+1)
|
||||||
|
for version := firstGenVersion; version <= maxVersion; version++ {
|
||||||
|
versionStrs[version-firstGenVersion] = strconv.Itoa(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
modules := mctx.CreateVariations(versionStrs...)
|
||||||
|
for i, module := range modules {
|
||||||
|
module.(*Module).compiler.(*stubCompiler).properties.ApiLevel = firstGenVersion + i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ndkApiMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(*Module); ok {
|
||||||
|
if compiler, ok := m.compiler.(*stubCompiler); ok {
|
||||||
|
generateStubApiVariants(mctx, compiler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
|
||||||
|
arch := ctx.Arch().ArchType.String()
|
||||||
|
|
||||||
|
if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) {
|
||||||
|
ctx.ModuleErrorf("ndk_library modules names must be suffixed with %q\n",
|
||||||
|
ndkLibrarySuffix)
|
||||||
|
}
|
||||||
|
libName := strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix)
|
||||||
|
fileBase := fmt.Sprintf("%s.%s.%d", libName, arch, c.properties.ApiLevel)
|
||||||
|
stubSrcName := fileBase + ".c"
|
||||||
|
stubSrcPath := android.PathForModuleGen(ctx, stubSrcName)
|
||||||
|
versionScriptName := fileBase + ".map"
|
||||||
|
versionScriptPath := android.PathForModuleGen(ctx, versionScriptName)
|
||||||
|
symbolFilePath := android.PathForModuleSrc(ctx, c.properties.Symbol_file)
|
||||||
|
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
|
||||||
|
Rule: genStubSrc,
|
||||||
|
Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
|
||||||
|
Input: symbolFilePath,
|
||||||
|
Args: map[string]string{
|
||||||
|
"arch": arch,
|
||||||
|
"apiLevel": strconv.Itoa(c.properties.ApiLevel),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
flags.CFlags = append(flags.CFlags,
|
||||||
|
// We're knowingly doing some otherwise unsightly things with builtin
|
||||||
|
// functions here. We're just generating stub libraries, so ignore it.
|
||||||
|
"-Wno-incompatible-library-redeclaration",
|
||||||
|
"-Wno-builtin-requires-header",
|
||||||
|
"-Wno-invalid-noreturn",
|
||||||
|
|
||||||
|
// These libraries aren't actually used. Don't worry about unwinding
|
||||||
|
// (avoids the need to link an unwinder into a fake library).
|
||||||
|
"-fno-unwind-tables",
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir := ""
|
||||||
|
srcs := []string{}
|
||||||
|
excludeSrcs := []string{}
|
||||||
|
extraSrcs := []android.Path{stubSrcPath}
|
||||||
|
extraDeps := []android.Path{}
|
||||||
|
return c.baseCompiler.compileObjs(ctx, flags, subdir, srcs, excludeSrcs,
|
||||||
|
extraSrcs, extraDeps)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stubLinker struct {
|
||||||
|
libraryLinker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (linker *stubLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
|
||||||
|
return Deps{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (linker *stubLinker) flags(ctx ModuleContext, flags Flags) Flags {
|
||||||
|
linker.libraryLinker.libName = strings.TrimSuffix(ctx.ModuleName(),
|
||||||
|
ndkLibrarySuffix)
|
||||||
|
return linker.libraryLinker.flags(ctx, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stubInstaller struct {
|
||||||
|
baseInstaller
|
||||||
|
|
||||||
|
compiler *stubCompiler
|
||||||
|
|
||||||
|
installPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ installer = (*stubInstaller)(nil)
|
||||||
|
|
||||||
|
func (installer *stubInstaller) install(ctx ModuleContext, path android.Path) {
|
||||||
|
arch := ctx.Target().Arch.ArchType.Name
|
||||||
|
apiLevel := installer.compiler.properties.ApiLevel
|
||||||
|
|
||||||
|
// arm64 isn't actually a multilib toolchain, so unlike the other LP64
|
||||||
|
// architectures it's just installed to lib.
|
||||||
|
libDir := "lib"
|
||||||
|
if ctx.toolchain().Is64Bit() && arch != "arm64" {
|
||||||
|
libDir = "lib64"
|
||||||
|
}
|
||||||
|
|
||||||
|
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
|
||||||
|
"platforms/android-%d/arch-%s/usr/%s", apiLevel, arch, libDir))
|
||||||
|
installer.installPath = ctx.InstallFile(installDir, path).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStubLibrary() *Module {
|
||||||
|
module := newModule(android.DeviceSupported, android.MultilibBoth)
|
||||||
|
module.stl = nil
|
||||||
|
|
||||||
|
linker := &stubLinker{}
|
||||||
|
linker.dynamicProperties.BuildShared = true
|
||||||
|
linker.dynamicProperties.BuildStatic = false
|
||||||
|
linker.stripper.StripProperties.Strip.None = true
|
||||||
|
module.linker = linker
|
||||||
|
|
||||||
|
compiler := &stubCompiler{}
|
||||||
|
module.compiler = compiler
|
||||||
|
module.installer = &stubInstaller{baseInstaller{
|
||||||
|
dir: "lib",
|
||||||
|
dir64: "lib64",
|
||||||
|
}, compiler, ""}
|
||||||
|
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
|
||||||
|
func ndkLibraryFactory() (blueprint.Module, []interface{}) {
|
||||||
|
module := newStubLibrary()
|
||||||
|
return android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth,
|
||||||
|
&module.compiler.(*stubCompiler).properties)
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
// 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 cc
|
||||||
|
|
||||||
|
// The platform needs to provide the following artifacts for the NDK:
|
||||||
|
// 1. Bionic headers.
|
||||||
|
// 2. Platform API headers.
|
||||||
|
// 3. NDK stub shared libraries.
|
||||||
|
// 4. Bionic static libraries.
|
||||||
|
//
|
||||||
|
// TODO(danalbert): All of the above need to include NOTICE files.
|
||||||
|
//
|
||||||
|
// Components 1 and 2: Headers
|
||||||
|
// The bionic and platform API headers are generalized into a single
|
||||||
|
// `ndk_headers` rule. This rule has a `from` property that indicates a base
|
||||||
|
// directory from which headers are to be taken, and a `to` property that
|
||||||
|
// indicates where in the sysroot they should reside relative to usr/include.
|
||||||
|
// There is also a `srcs` property that is glob compatible for specifying which
|
||||||
|
// headers to include.
|
||||||
|
//
|
||||||
|
// Component 3: Stub Libraries
|
||||||
|
// The shared libraries in the NDK are not the actual shared libraries they
|
||||||
|
// refer to (to prevent people from accidentally loading them), but stub
|
||||||
|
// libraries with dummy implementations of everything for use at build time
|
||||||
|
// only.
|
||||||
|
//
|
||||||
|
// Since we don't actually need to know anything about the stub libraries aside
|
||||||
|
// from a list of functions and globals to be exposed, we can create these for
|
||||||
|
// every platform level in the current tree. This is handled by the
|
||||||
|
// ndk_library rule.
|
||||||
|
//
|
||||||
|
// Component 4: Static Libraries
|
||||||
|
// The NDK only provides static libraries for bionic, not the platform APIs.
|
||||||
|
// Since these need to be the actual implementation, we can't build old versions
|
||||||
|
// in the current platform tree. As such, legacy versions are checked in
|
||||||
|
// prebuilt to development/ndk, and a current version is built and archived as
|
||||||
|
// part of the platform build. The platfrom already builds these libraries, our
|
||||||
|
// NDK build rules only need to archive them for retrieval so they can be added
|
||||||
|
// to the prebuilts.
|
||||||
|
//
|
||||||
|
// TODO(danalbert): Write `ndk_static_library` rule.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong"
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
soong.RegisterModuleType("ndk_headers", ndkHeadersFactory)
|
||||||
|
soong.RegisterModuleType("ndk_library", ndkLibraryFactory)
|
||||||
|
soong.RegisterSingletonType("ndk", NdkSingleton)
|
||||||
|
|
||||||
|
pctx.Import("android/soong/common")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNdkInstallBase(ctx android.ModuleContext) android.OutputPath {
|
||||||
|
return android.PathForOutput(ctx, "ndk")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the main install directory for the NDK sysroot. Usable with --sysroot.
|
||||||
|
func getNdkSysrootBase(ctx android.ModuleContext) android.OutputPath {
|
||||||
|
return getNdkInstallBase(ctx).Join(ctx, "sysroot")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNdkSysrootTimestampFile(ctx android.PathContext) android.Path {
|
||||||
|
return android.PathForOutput(ctx, "ndk.timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func NdkSingleton() blueprint.Singleton {
|
||||||
|
return &ndkSingleton{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ndkSingleton struct{}
|
||||||
|
|
||||||
|
func (n *ndkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
|
||||||
|
installPaths := []string{}
|
||||||
|
ctx.VisitAllModules(func(module blueprint.Module) {
|
||||||
|
if m, ok := module.(*headerModule); ok {
|
||||||
|
installPaths = append(installPaths, m.installPaths...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.VisitAllModules(func(module blueprint.Module) {
|
||||||
|
if m, ok := module.(*Module); ok {
|
||||||
|
if installer, ok := m.installer.(*stubInstaller); ok {
|
||||||
|
installPaths = append(installPaths, installer.installPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// There's a dummy "ndk" rule defined in ndk/Android.mk that depends on
|
||||||
|
// this. `m ndk` will build the sysroots.
|
||||||
|
ctx.Build(pctx, blueprint.BuildParams{
|
||||||
|
Rule: android.Touch,
|
||||||
|
Outputs: []string{getNdkSysrootTimestampFile(ctx).String()},
|
||||||
|
Implicits: installPaths,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,280 @@
|
||||||
|
[MASTER]
|
||||||
|
|
||||||
|
# Specify a configuration file.
|
||||||
|
#rcfile=
|
||||||
|
|
||||||
|
# Python code to execute, usually for sys.path manipulation such as
|
||||||
|
# pygtk.require().
|
||||||
|
#init-hook=
|
||||||
|
|
||||||
|
# Profiled execution.
|
||||||
|
profile=no
|
||||||
|
|
||||||
|
# Add files or directories to the blacklist. They should be base names, not
|
||||||
|
# paths.
|
||||||
|
ignore=CVS
|
||||||
|
|
||||||
|
# Pickle collected data for later comparisons.
|
||||||
|
persistent=yes
|
||||||
|
|
||||||
|
# List of plugins (as comma separated values of python modules names) to load,
|
||||||
|
# usually to register additional checkers.
|
||||||
|
load-plugins=
|
||||||
|
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
|
||||||
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
# multiple time. See also the "--disable" option for examples.
|
||||||
|
#enable=
|
||||||
|
|
||||||
|
# Disable the message, report, category or checker with the given id(s). You
|
||||||
|
# can either give multiple identifiers separated by comma (,) or put this
|
||||||
|
# option multiple times (only on the command line, not in the configuration
|
||||||
|
# file where it should appear only once).You can also use "--disable=all" to
|
||||||
|
# disable everything first and then reenable specific checks. For example, if
|
||||||
|
# you want to run only the similarities checker, you can use "--disable=all
|
||||||
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
|
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||||
|
# --disable=W"
|
||||||
|
disable=design
|
||||||
|
|
||||||
|
|
||||||
|
[REPORTS]
|
||||||
|
|
||||||
|
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||||
|
# (visual studio) and html. You can also give a reporter class, eg
|
||||||
|
# mypackage.mymodule.MyReporterClass.
|
||||||
|
output-format=text
|
||||||
|
|
||||||
|
# Put messages in a separate file for each module / package specified on the
|
||||||
|
# command line instead of printing them on stdout. Reports (if any) will be
|
||||||
|
# written in a file name "pylint_global.[txt|html]".
|
||||||
|
files-output=no
|
||||||
|
|
||||||
|
# Tells whether to display a full report or only the messages
|
||||||
|
reports=yes
|
||||||
|
|
||||||
|
# Python expression which should return a note less than 10 (10 is the highest
|
||||||
|
# note). You have access to the variables errors warning, statement which
|
||||||
|
# respectively contain the number of errors / warnings messages and the total
|
||||||
|
# number of statements analyzed. This is used by the global evaluation report
|
||||||
|
# (RP0004).
|
||||||
|
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||||
|
|
||||||
|
# Add a comment according to your evaluation note. This is used by the global
|
||||||
|
# evaluation report (RP0004).
|
||||||
|
comment=no
|
||||||
|
|
||||||
|
# Template used to display messages. This is a python new-style format string
|
||||||
|
# used to format the message information. See doc for all details
|
||||||
|
#msg-template=
|
||||||
|
|
||||||
|
|
||||||
|
[BASIC]
|
||||||
|
|
||||||
|
# Required attributes for module, separated by a comma
|
||||||
|
required-attributes=
|
||||||
|
|
||||||
|
# List of builtins function names that should not be used, separated by a comma
|
||||||
|
bad-functions=map,filter,apply,input
|
||||||
|
|
||||||
|
# Regular expression which should only match correct module names
|
||||||
|
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct module level names
|
||||||
|
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct class names
|
||||||
|
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct function names
|
||||||
|
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct method names
|
||||||
|
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct instance attribute names
|
||||||
|
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct argument names
|
||||||
|
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct variable names
|
||||||
|
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct attribute names in class
|
||||||
|
# bodies
|
||||||
|
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||||
|
|
||||||
|
# Regular expression which should only match correct list comprehension /
|
||||||
|
# generator expression variable names
|
||||||
|
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||||
|
|
||||||
|
# Good variable names which should always be accepted, separated by a comma
|
||||||
|
good-names=i,j,k,ex,Run,_
|
||||||
|
|
||||||
|
# Bad variable names which should always be refused, separated by a comma
|
||||||
|
bad-names=foo,bar,baz,toto,tutu,tata
|
||||||
|
|
||||||
|
# Regular expression which should only match function or class names that do
|
||||||
|
# not require a docstring.
|
||||||
|
no-docstring-rgx=__.*__
|
||||||
|
|
||||||
|
# Minimum line length for functions/classes that require docstrings, shorter
|
||||||
|
# ones are exempt.
|
||||||
|
docstring-min-length=-1
|
||||||
|
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
|
||||||
|
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||||
|
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||||
|
ignore-mixin-members=yes
|
||||||
|
|
||||||
|
# List of classes names for which member attributes should not be checked
|
||||||
|
# (useful for classes with attributes dynamically set).
|
||||||
|
ignored-classes=SQLObject
|
||||||
|
|
||||||
|
# When zope mode is activated, add a predefined set of Zope acquired attributes
|
||||||
|
# to generated-members.
|
||||||
|
zope=no
|
||||||
|
|
||||||
|
# List of members which are set dynamically and missed by pylint inference
|
||||||
|
# system, and so shouldn't trigger E0201 when accessed. Python regular
|
||||||
|
# expressions are accepted.
|
||||||
|
generated-members=REQUEST,acl_users,aq_parent
|
||||||
|
|
||||||
|
|
||||||
|
[MISCELLANEOUS]
|
||||||
|
|
||||||
|
# List of note tags to take in consideration, separated by a comma.
|
||||||
|
notes=FIXME,XXX,TODO
|
||||||
|
|
||||||
|
|
||||||
|
[SIMILARITIES]
|
||||||
|
|
||||||
|
# Minimum lines number of a similarity.
|
||||||
|
min-similarity-lines=4
|
||||||
|
|
||||||
|
# Ignore comments when computing similarities.
|
||||||
|
ignore-comments=yes
|
||||||
|
|
||||||
|
# Ignore docstrings when computing similarities.
|
||||||
|
ignore-docstrings=yes
|
||||||
|
|
||||||
|
# Ignore imports when computing similarities.
|
||||||
|
ignore-imports=no
|
||||||
|
|
||||||
|
|
||||||
|
[VARIABLES]
|
||||||
|
|
||||||
|
# Tells whether we should check for unused import in __init__ files.
|
||||||
|
init-import=no
|
||||||
|
|
||||||
|
# A regular expression matching the beginning of the name of dummy variables
|
||||||
|
# (i.e. not used).
|
||||||
|
dummy-variables-rgx=_|dummy
|
||||||
|
|
||||||
|
# List of additional names supposed to be defined in builtins. Remember that
|
||||||
|
# you should avoid to define new builtins when possible.
|
||||||
|
additional-builtins=
|
||||||
|
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
|
||||||
|
# Maximum number of characters on a single line.
|
||||||
|
max-line-length=80
|
||||||
|
|
||||||
|
# Regexp for a line that is allowed to be longer than the limit.
|
||||||
|
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||||
|
|
||||||
|
# Allow the body of an if to be on the same line as the test if there is no
|
||||||
|
# else.
|
||||||
|
single-line-if-stmt=no
|
||||||
|
|
||||||
|
# List of optional constructs for which whitespace checking is disabled
|
||||||
|
no-space-check=trailing-comma,dict-separator
|
||||||
|
|
||||||
|
# Maximum number of lines in a module
|
||||||
|
max-module-lines=1000
|
||||||
|
|
||||||
|
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||||
|
# tab).
|
||||||
|
indent-string=' '
|
||||||
|
|
||||||
|
|
||||||
|
[IMPORTS]
|
||||||
|
|
||||||
|
# Deprecated modules which should not be used, separated by a comma
|
||||||
|
deprecated-modules=regsub,TERMIOS,Bastion,rexec
|
||||||
|
|
||||||
|
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||||
|
# given file (report RP0402 must not be disabled)
|
||||||
|
import-graph=
|
||||||
|
|
||||||
|
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled)
|
||||||
|
ext-import-graph=
|
||||||
|
|
||||||
|
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled)
|
||||||
|
int-import-graph=
|
||||||
|
|
||||||
|
|
||||||
|
[DESIGN]
|
||||||
|
|
||||||
|
# Maximum number of arguments for function / method
|
||||||
|
max-args=5
|
||||||
|
|
||||||
|
# Argument names that match this expression will be ignored. Default to name
|
||||||
|
# with leading underscore
|
||||||
|
ignored-argument-names=_.*
|
||||||
|
|
||||||
|
# Maximum number of locals for function / method body
|
||||||
|
max-locals=15
|
||||||
|
|
||||||
|
# Maximum number of return / yield for function / method body
|
||||||
|
max-returns=6
|
||||||
|
|
||||||
|
# Maximum number of branch for function / method body
|
||||||
|
max-branches=12
|
||||||
|
|
||||||
|
# Maximum number of statements in function / method body
|
||||||
|
max-statements=50
|
||||||
|
|
||||||
|
# Maximum number of parents for a class (see R0901).
|
||||||
|
max-parents=7
|
||||||
|
|
||||||
|
# Maximum number of attributes for a class (see R0902).
|
||||||
|
max-attributes=7
|
||||||
|
|
||||||
|
# Minimum number of public methods for a class (see R0903).
|
||||||
|
min-public-methods=2
|
||||||
|
|
||||||
|
# Maximum number of public methods for a class (see R0904).
|
||||||
|
max-public-methods=20
|
||||||
|
|
||||||
|
|
||||||
|
[CLASSES]
|
||||||
|
|
||||||
|
# List of interface methods to ignore, separated by a comma. This is used for
|
||||||
|
# instance to not check methods defines in Zope's Interface base class.
|
||||||
|
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
|
||||||
|
|
||||||
|
# List of method names used to declare (i.e. assign) instance attributes.
|
||||||
|
defining-attr-methods=__init__,__new__,setUp
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a class method.
|
||||||
|
valid-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a metaclass class method.
|
||||||
|
valid-metaclass-classmethod-first-arg=mcs
|
||||||
|
|
||||||
|
|
||||||
|
[EXCEPTIONS]
|
||||||
|
|
||||||
|
# Exceptions that will emit a warning when being caught. Defaults to
|
||||||
|
# "Exception"
|
||||||
|
overgeneral-exceptions=Exception
|
Loading…
Reference in New Issue