platform_build_soong/cc/binary.go

369 lines
11 KiB
Go
Raw Normal View History

// 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/proptools"
"android/soong/android"
)
type BinaryLinkerProperties struct {
// compile executable with -static
Static_executable *bool `android:"arch_variant"`
// set the name of the output
Stem string `android:"arch_variant"`
// append to the name of the output
Suffix string `android:"arch_variant"`
// if set, add an extra objcopy --prefix-symbols= step
Prefix_symbols string
// local file name to pass to the linker as --version_script
Version_script *string `android:"arch_variant"`
// if set, install a symlink to the preferred architecture
Symlink_preferred_arch bool
// install symlinks to the binary. Symlink names will have the suffix and the binary
// extension (if any) appended
Symlinks []string `android:"arch_variant"`
// do not pass -pie
No_pie *bool `android:"arch_variant"`
DynamicLinker string `blueprint:"mutated"`
}
func init() {
android.RegisterModuleType("cc_binary", binaryFactory)
android.RegisterModuleType("cc_binary_host", binaryHostFactory)
}
// Module factory for binaries
func binaryFactory() android.Module {
module, _ := NewBinary(android.HostAndDeviceSupported)
return module.Init()
}
// Module factory for host binaries
func binaryHostFactory() android.Module {
module, _ := NewBinary(android.HostSupported)
return module.Init()
}
//
// Executables
//
type binaryDecorator struct {
*baseLinker
*baseInstaller
stripper
Properties BinaryLinkerProperties
toolPath android.OptionalPath
// Names of symlinks to be installed for use in LOCAL_MODULE_SYMLINKS
symlinks []string
// Output archive of gcno coverage information
coverageOutputFile android.OptionalPath
}
var _ linker = (*binaryDecorator)(nil)
func (binary *binaryDecorator) linkerProps() []interface{} {
return append(binary.baseLinker.linkerProps(),
&binary.Properties,
&binary.stripper.StripProperties)
}
func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
stem := ctx.baseModuleName()
if binary.Properties.Stem != "" {
stem = binary.Properties.Stem
}
return stem + binary.Properties.Suffix
}
func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps = binary.baseLinker.linkerDeps(ctx, deps)
if ctx.toolchain().Bionic() {
if !Bool(binary.baseLinker.Properties.Nocrt) {
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-07 03:43:22 +08:00
if !ctx.sdk() {
if binary.static() {
deps.CrtBegin = "crtbegin_static"
} else {
deps.CrtBegin = "crtbegin_dynamic"
}
deps.CrtEnd = "crtend_android"
} else {
// TODO(danalbert): Add generation of crt objects.
// For `sdk_version: "current"`, we don't actually have a
// freshly generated set of CRT objects. Use the last stable
// version.
version := ctx.sdkVersion()
if version == "current" {
version = getCurrentNdkPrebuiltVersion(ctx)
}
if binary.static() {
deps.CrtBegin = "ndk_crtbegin_static." + version
} else {
if binary.static() {
deps.CrtBegin = "ndk_crtbegin_static." + version
} else {
deps.CrtBegin = "ndk_crtbegin_dynamic." + version
}
deps.CrtEnd = "ndk_crtend_android." + version
}
}
}
if binary.static() {
if ctx.selectedStl() == "libc++_static" {
deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
}
// static libraries libcompiler_rt, libc and libc_nomalloc need to be linked with
// --start-group/--end-group along with libgcc. If they are in deps.StaticLibs,
// move them to the beginning of deps.LateStaticLibs
var groupLibs []string
deps.StaticLibs, groupLibs = filterList(deps.StaticLibs,
[]string{"libc", "libc_nomalloc", "libcompiler_rt"})
deps.LateStaticLibs = append(groupLibs, deps.LateStaticLibs...)
}
}
if !binary.static() && inList("libc", deps.StaticLibs) {
ctx.ModuleErrorf("statically linking libc to dynamic executable, please remove libc\n" +
"from static libs or set static_executable: true")
}
return deps
}
func (binary *binaryDecorator) isDependencyRoot() bool {
return true
}
func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
module := newModule(hod, android.MultilibFirst)
binary := &binaryDecorator{
baseLinker: NewBaseLinker(),
baseInstaller: NewBaseInstaller("bin", "", InstallInSystem),
}
module.compiler = NewBaseCompiler()
module.linker = binary
module.installer = binary
return module, binary
}
func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) {
binary.baseLinker.linkerInit(ctx)
if !ctx.toolchain().Bionic() {
if ctx.Os() == android.Linux {
if binary.Properties.Static_executable == nil && Bool(ctx.AConfig().ProductVariables.HostStaticBinaries) {
binary.Properties.Static_executable = proptools.BoolPtr(true)
}
} else {
// Static executables are not supported on Darwin or Windows
binary.Properties.Static_executable = nil
}
}
}
func (binary *binaryDecorator) static() bool {
return Bool(binary.Properties.Static_executable)
}
func (binary *binaryDecorator) staticBinary() bool {
return binary.static()
}
func (binary *binaryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
flags = binary.baseLinker.linkerFlags(ctx, flags)
if ctx.Host() && !binary.static() {
if !ctx.AConfig().IsEnvTrue("DISABLE_HOST_PIE") {
flags.LdFlags = append(flags.LdFlags, "-pie")
if ctx.Windows() {
flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup")
}
}
}
// MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because
// all code is position independent, and then those warnings get promoted to
// errors.
if !ctx.Windows() {
flags.CFlags = append(flags.CFlags, "-fPIE")
}
if ctx.toolchain().Bionic() {
if binary.static() {
// Clang driver needs -static to create static executable.
// However, bionic/linker uses -shared to overwrite.
// Linker for x86 targets does not allow coexistance of -static and -shared,
// so we add -static only if -shared is not used.
if !inList("-shared", flags.LdFlags) {
flags.LdFlags = append(flags.LdFlags, "-static")
}
flags.LdFlags = append(flags.LdFlags,
"-nostdlib",
"-Bstatic",
"-Wl,--gc-sections",
)
} else {
if flags.DynamicLinker == "" {
if binary.Properties.DynamicLinker != "" {
flags.DynamicLinker = binary.Properties.DynamicLinker
} else {
switch ctx.Os() {
case android.Android:
flags.DynamicLinker = "/system/bin/linker"
case android.LinuxBionic:
// The linux kernel expects the linker to be an
// absolute path
path := android.PathForOutput(ctx,
"host", "linux_bionic-x86", "bin", "linker")
if p, err := filepath.Abs(path.String()); err == nil {
flags.DynamicLinker = p
} else {
ctx.ModuleErrorf("can't find path to dynamic linker: %q", err)
}
default:
ctx.ModuleErrorf("unknown dynamic linker")
}
if flags.Toolchain.Is64Bit() {
flags.DynamicLinker += "64"
}
}
}
flags.LdFlags = append(flags.LdFlags,
"-pie",
"-nostdlib",
"-Bdynamic",
"-Wl,--gc-sections",
"-Wl,-z,nocopyreloc",
)
}
} else {
if binary.static() {
flags.LdFlags = append(flags.LdFlags, "-static")
}
if ctx.Darwin() {
flags.LdFlags = append(flags.LdFlags, "-Wl,-headerpad_max_install_names")
}
}
return flags
}
func (binary *binaryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
versionScript := android.OptionalPathForModuleSrc(ctx, binary.Properties.Version_script)
fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
outputFile := android.PathForModuleOut(ctx, fileName)
ret := outputFile
var linkerDeps android.Paths
sharedLibs := deps.SharedLibs
sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
if versionScript.Valid() {
if ctx.Darwin() {
ctx.PropertyErrorf("version_script", "Not supported on Darwin")
} else {
flags.LdFlags = append(flags.LdFlags, "-Wl,--version-script,"+versionScript.String())
linkerDeps = append(linkerDeps, versionScript.Path())
}
}
if flags.DynamicLinker != "" {
flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
}
builderFlags := flagsToBuilderFlags(flags)
if binary.stripper.needsStrip(ctx) {
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
binary.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
}
if binary.Properties.Prefix_symbols != "" {
afterPrefixSymbols := outputFile
outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName)
TransformBinaryPrefixSymbols(ctx, binary.Properties.Prefix_symbols, outputFile,
flagsToBuilderFlags(flags), afterPrefixSymbols)
}
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
linkerDeps = append(linkerDeps, objs.tidyFiles...)
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
builderFlags, outputFile)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx))
return ret
}
func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
binary.baseInstaller.install(ctx, file)
for _, symlink := range binary.Properties.Symlinks {
binary.symlinks = append(binary.symlinks,
symlink+binary.Properties.Suffix+ctx.toolchain().ExecutableSuffix())
}
if binary.Properties.Symlink_preferred_arch {
if binary.Properties.Stem == "" && binary.Properties.Suffix == "" {
ctx.PropertyErrorf("symlink_preferred_arch", "must also specify stem or suffix")
}
if ctx.TargetPrimary() {
binary.symlinks = append(binary.symlinks, ctx.baseModuleName())
}
}
for _, symlink := range binary.symlinks {
ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
}
if ctx.Os().Class == android.Host {
binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
}
}
func (binary *binaryDecorator) hostToolPath() android.OptionalPath {
return binary.toolPath
}