diff options
author | Colin Cross <ccross@android.com> | 2016-07-29 17:28:03 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2016-08-05 10:25:09 -0700 |
commit | b916a38233e6862ec74dd840038ae224f6fde1c7 (patch) | |
tree | c830af79126bf82b750bad58bd9808a638607da8 | |
parent | 01344df46ee1744dd1ff7815705564deb43ac7cb (diff) | |
download | build_soong-b916a38233e6862ec74dd840038ae224f6fde1c7.tar.gz build_soong-b916a38233e6862ec74dd840038ae224f6fde1c7.tar.bz2 build_soong-b916a38233e6862ec74dd840038ae224f6fde1c7.zip |
Refactor cc modules to use decorators instead of inheritance
For example , instead of trying to have libraryLinker inherit from
baseLinker and libraryCompiler inherit from baseCompiler, create a
single decorator object that wraps both baseLinker and baseCompiler.
Test: Builds, no unexpected changes to build.ninja
Change-Id: I2468adaea8466c203a240259ba5694b8b1df7a52
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | cc/androidmk.go | 88 | ||||
-rw-r--r-- | cc/binary.go | 85 | ||||
-rw-r--r-- | cc/cc.go | 110 | ||||
-rw-r--r-- | cc/compiler.go | 8 | ||||
-rw-r--r-- | cc/installer.go | 23 | ||||
-rw-r--r-- | cc/library.go | 325 | ||||
-rw-r--r-- | cc/linker.go | 58 | ||||
-rw-r--r-- | cc/ndk_library.go | 83 | ||||
-rw-r--r-- | cc/ndk_prebuilt.go | 84 | ||||
-rw-r--r-- | cc/ndk_sysroot.go | 2 | ||||
-rw-r--r-- | cc/object.go | 11 | ||||
-rw-r--r-- | cc/sanitize.go | 2 | ||||
-rw-r--r-- | cc/test.go | 224 | ||||
-rw-r--r-- | cc/toolchain_library.go | 76 |
15 files changed, 628 insertions, 552 deletions
@@ -166,6 +166,7 @@ bootstrap_go_package { "cc/library.go", "cc/object.go", "cc/test.go", + "cc/toolchain_library.go", "cc/ndk_prebuilt.go", "cc/ndk_headers.go", diff --git a/cc/androidmk.go b/cc/androidmk.go index df44a4c2..4986387e 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -26,6 +26,23 @@ import ( type AndroidMkContext interface { Target() android.Target + subAndroidMk(*android.AndroidMkData, interface{}) +} + +type subAndroidMkProvider interface { + AndroidMk(AndroidMkContext, *android.AndroidMkData) +} + +func (c *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) { + if c.subAndroidMkOnce == nil { + c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool) + } + if androidmk, ok := obj.(subAndroidMkProvider); ok { + if !c.subAndroidMkOnce[androidmk] { + c.subAndroidMkOnce[androidmk] = true + androidmk.AndroidMk(c, data) + } + } } func (c *Module) AndroidMk() (ret android.AndroidMkData, err error) { @@ -50,43 +67,27 @@ func (c *Module) AndroidMk() (ret android.AndroidMkData, err error) { return nil }) - callSubAndroidMk := func(obj interface{}) { - if obj != nil { - if androidmk, ok := obj.(interface { - AndroidMk(AndroidMkContext, *android.AndroidMkData) - }); ok { - androidmk.AndroidMk(c, &ret) - } - } - } - for _, feature := range c.features { - callSubAndroidMk(feature) + c.subAndroidMk(&ret, feature) } - callSubAndroidMk(c.compiler) - callSubAndroidMk(c.linker) - if c.linker.installable() { - callSubAndroidMk(c.installer) - } + c.subAndroidMk(&ret, c.compiler) + c.subAndroidMk(&ret, c.linker) + c.subAndroidMk(&ret, c.installer) return ret, nil } -func (library *baseLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { +func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + if !library.static() { + ctx.subAndroidMk(ret, &library.stripper) + } + if library.static() { ret.Class = "STATIC_LIBRARIES" } else { ret.Class = "SHARED_LIBRARIES" } -} - -func (library *libraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - library.baseLinker.AndroidMk(ctx, ret) - - if !library.static() { - library.stripper.AndroidMk(ctx, ret) - } ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error { var exportedIncludes []string @@ -106,6 +107,10 @@ func (library *libraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.Andro return nil }) + + if !library.static() { + ctx.subAndroidMk(ret, library.baseInstaller) + } } func (object *objectLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { @@ -119,30 +124,39 @@ func (object *objectLinker) AndroidMk(ctx AndroidMkContext, ret *android.Android } } -func (binary *binaryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - binary.stripper.AndroidMk(ctx, ret) +func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.subAndroidMk(ret, &binary.stripper) ret.Class = "EXECUTABLES" ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error { fmt.Fprintln(w, "LOCAL_CXX_STL := none") fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=") - if binary.static() { + if Bool(binary.Properties.Static_executable) { fmt.Fprintln(w, "LOCAL_FORCE_STATIC_EXECUTABLE := true") } return nil }) } -func (test *testBinaryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - test.binaryLinker.AndroidMk(ctx, ret) - if Bool(test.testLinker.Properties.Test_per_src) { - ret.SubName = "_" + test.binaryLinker.Properties.Stem +func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.subAndroidMk(ret, benchmark.binaryDecorator) + ctx.subAndroidMk(ret, benchmark.baseInstaller) +} + +func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.subAndroidMk(ret, test.binaryDecorator) + ctx.subAndroidMk(ret, test.baseInstaller) + if Bool(test.Properties.Test_per_src) { + ret.SubName = "_" + test.binaryDecorator.Properties.Stem } } -func (library *toolchainLibraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - library.baseLinker.AndroidMk(ctx, ret) +func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.subAndroidMk(ret, test.libraryDecorator) +} +func (library *toolchainLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ret.Class = "STATIC_LIBRARIES" ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error { fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+outputFile.Ext()) fmt.Fprintln(w, "LOCAL_CXX_STL := none") @@ -185,13 +199,11 @@ func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.And }) } -func (c *stubCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { +func (c *stubDecorator) 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) + path, file := filepath.Split(c.installPath) stem := strings.TrimSuffix(file, filepath.Ext(file)) fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) diff --git a/cc/binary.go b/cc/binary.go index fd64cdaf..2dbce66c 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -16,6 +16,7 @@ package cc import ( "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "android/soong" "android/soong/android" @@ -42,13 +43,13 @@ func init() { // Module factory for binaries func binaryFactory() (blueprint.Module, []interface{}) { - module := NewBinary(android.HostAndDeviceSupported) + module, _ := NewBinary(android.HostAndDeviceSupported) return module.Init() } // Module factory for host binaries func binaryHostFactory() (blueprint.Module, []interface{}) { - module := NewBinary(android.HostSupported) + module, _ := NewBinary(android.HostSupported) return module.Init() } @@ -56,8 +57,8 @@ func binaryHostFactory() (blueprint.Module, []interface{}) { // Executables // -type binaryLinker struct { - baseLinker +type binaryDecorator struct { + *baseLinker stripper Properties BinaryLinkerProperties @@ -65,24 +66,16 @@ type binaryLinker struct { hostToolPath android.OptionalPath } -var _ linker = (*binaryLinker)(nil) +var _ linker = (*binaryDecorator)(nil) -func (binary *binaryLinker) linkerProps() []interface{} { +func (binary *binaryDecorator) linkerProps() []interface{} { return append(binary.baseLinker.linkerProps(), &binary.Properties, &binary.stripper.StripProperties) } -func (binary *binaryLinker) buildStatic() bool { - return binary.baseLinker.staticBinary() -} - -func (binary *binaryLinker) buildShared() bool { - return !binary.baseLinker.staticBinary() -} - -func (binary *binaryLinker) getStem(ctx BaseModuleContext) string { +func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string { stem := ctx.ModuleName() if binary.Properties.Stem != "" { stem = binary.Properties.Stem @@ -91,22 +84,22 @@ func (binary *binaryLinker) getStem(ctx BaseModuleContext) string { return stem + binary.Properties.Suffix } -func (binary *binaryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { +func (binary *binaryDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { deps = binary.baseLinker.linkerDeps(ctx, deps) if ctx.Device() { if !Bool(binary.baseLinker.Properties.Nocrt) { if !ctx.sdk() { - if binary.buildStatic() { + if binary.static() { deps.CrtBegin = "crtbegin_static" } else { deps.CrtBegin = "crtbegin_dynamic" } deps.CrtEnd = "crtend_android" } else { - if binary.buildStatic() { + if binary.static() { deps.CrtBegin = "ndk_crtbegin_static." + ctx.sdkVersion() } else { - if Bool(binary.Properties.Static_executable) { + if binary.static() { deps.CrtBegin = "ndk_crtbegin_static." + ctx.sdkVersion() } else { deps.CrtBegin = "ndk_crtbegin_dynamic." + ctx.sdkVersion() @@ -116,7 +109,7 @@ func (binary *binaryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { } } - if binary.buildStatic() { + if binary.static() { if inList("libc++_static", deps.StaticLibs) { deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl") } @@ -130,55 +123,55 @@ func (binary *binaryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { } } - if binary.buildShared() && inList("libc", deps.StaticLibs) { + 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 (*binaryLinker) installable() bool { - return true -} - -func (binary *binaryLinker) isDependencyRoot() bool { +func (binary *binaryDecorator) isDependencyRoot() bool { return true } -func NewBinary(hod android.HostOrDeviceSupported) *Module { +func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { module := newModule(hod, android.MultilibFirst) - module.compiler = &baseCompiler{} - module.linker = &binaryLinker{} - module.installer = &baseInstaller{ - dir: "bin", + binary := &binaryDecorator{ + baseLinker: NewBaseLinker(), } - return module + module.compiler = NewBaseCompiler() + module.linker = binary + module.installer = NewBaseInstaller("bin", "", InstallInSystem) + return module, binary } -func (binary *binaryLinker) linkerInit(ctx BaseModuleContext) { +func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) { binary.baseLinker.linkerInit(ctx) - static := Bool(binary.Properties.Static_executable) if ctx.Host() { if ctx.Os() == android.Linux { if binary.Properties.Static_executable == nil && Bool(ctx.AConfig().ProductVariables.HostStaticBinaries) { - static = true + binary.Properties.Static_executable = proptools.BoolPtr(true) } } else { // Static executables are not supported on Darwin or Windows - static = false + binary.Properties.Static_executable = nil } } - if static { - binary.dynamicProperties.VariantIsStatic = true - binary.dynamicProperties.VariantIsStaticBinary = true - } } -func (binary *binaryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { +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.staticBinary() { + if ctx.Host() && !binary.static() { flags.LdFlags = append(flags.LdFlags, "-pie") if ctx.Os() == android.Windows { flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup") @@ -193,7 +186,7 @@ func (binary *binaryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { } if ctx.Device() { - if binary.buildStatic() { + 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, @@ -225,7 +218,7 @@ func (binary *binaryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { ) } } else { - if binary.staticBinary() { + if binary.static() { flags.LdFlags = append(flags.LdFlags, "-static") } if ctx.Darwin() { @@ -236,7 +229,7 @@ func (binary *binaryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (binary *binaryLinker) link(ctx ModuleContext, +func (binary *binaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path { fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix() @@ -277,6 +270,6 @@ func (binary *binaryLinker) link(ctx ModuleContext, return ret } -func (binary *binaryLinker) HostToolPath() android.OptionalPath { +func (binary *binaryDecorator) HostToolPath() android.OptionalPath { return binary.hostToolPath } @@ -35,8 +35,6 @@ import ( func init() { soong.RegisterModuleType("cc_defaults", defaultsFactory) - soong.RegisterModuleType("toolchain_library", toolchainLibraryFactory) - // LinkageMutator must be registered after common.ArchMutator, but that is guaranteed by // the Go initialization order because this package depends on common, so common's init // functions will run first. @@ -189,7 +187,6 @@ type linker interface { link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path appendLdflags([]string) - installable() bool } type installer interface { @@ -252,6 +249,8 @@ type Module struct { outputFile android.OptionalPath cachedToolchain config.Toolchain + + subAndroidMkOnce map[subAndroidMkProvider]bool } func (c *Module) Init() (blueprint.Module, []interface{}) { @@ -283,6 +282,17 @@ func (c *Module) Init() (blueprint.Module, []interface{}) { return android.InitDefaultableModule(c, c, props...) } +// Returns true for dependency roots (binaries) +// TODO(ccross): also handle dlopenable libraries +func (c *Module) isDependencyRoot() bool { + if root, ok := c.linker.(interface { + isDependencyRoot() bool + }); ok { + return root.isDependencyRoot() + } + return false +} + type baseModuleContext struct { android.BaseContext moduleContextImpl @@ -322,25 +332,21 @@ func (ctx *moduleContextImpl) toolchain() config.Toolchain { } func (ctx *moduleContextImpl) static() bool { - if ctx.mod.linker == nil { - panic(fmt.Errorf("static called on module %q with no linker", ctx.ctx.ModuleName())) - } - if linker, ok := ctx.mod.linker.(baseLinkerInterface); ok { - return linker.static() - } else { - panic(fmt.Errorf("static called on module %q that doesn't use base linker", ctx.ctx.ModuleName())) + if static, ok := ctx.mod.linker.(interface { + static() bool + }); ok { + return static.static() } + return false } func (ctx *moduleContextImpl) staticBinary() bool { - if ctx.mod.linker == nil { - panic(fmt.Errorf("staticBinary called on module %q with no linker", ctx.ctx.ModuleName())) - } - if linker, ok := ctx.mod.linker.(baseLinkerInterface); ok { - return linker.staticBinary() - } else { - panic(fmt.Errorf("staticBinary called on module %q that doesn't use base linker", ctx.ctx.ModuleName())) + if static, ok := ctx.mod.linker.(interface { + staticBinary() bool + }); ok { + return static.staticBinary() } + return false } func (ctx *moduleContextImpl) noDefaultCompilerFlags() bool { @@ -453,7 +459,7 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } c.outputFile = android.OptionalPathForPath(outputFile) - if c.installer != nil && c.linker.installable() { + if c.installer != nil { c.installer.install(ctx, outputFile) if ctx.Failed() { return @@ -680,7 +686,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Platform code can link to anything return } - if _, ok := to.linker.(*toolchainLibraryLinker); ok { + if _, ok := to.linker.(*toolchainLibraryDecorator); ok { // These are always allowed return } @@ -692,7 +698,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // These are allowed, but don't set sdk_version return } - if _, ok := to.linker.(*stubLinker); ok { + if _, ok := to.linker.(*stubDecorator); ok { // These aren't real libraries, but are the stub shared libraries that are included in // the NDK. return @@ -794,7 +800,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if tag == reuseObjTag { depPaths.ObjFiles = append(depPaths.ObjFiles, - cc.compiler.(*libraryCompiler).reuseObjFiles...) + cc.compiler.(libraryInterface).reuseObjs()...) return } @@ -824,8 +830,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPtr = &depPaths.LateStaticLibs case wholeStaticDepTag: depPtr = &depPaths.WholeStaticLibs - staticLib, _ := cc.linker.(libraryInterface) - if staticLib == nil || !staticLib.static() { + staticLib, ok := cc.linker.(libraryInterface) + if !ok || !staticLib.static() { ctx.ModuleErrorf("module %q not a static library", name) return } @@ -882,11 +888,11 @@ func defaultsFactory() (blueprint.Module, []interface{}) { &BaseProperties{}, &BaseCompilerProperties{}, &BaseLinkerProperties{}, - &LibraryCompilerProperties{}, + &LibraryProperties{}, &FlagExporterProperties{}, - &LibraryLinkerProperties{}, &BinaryLinkerProperties{}, - &TestLinkerProperties{}, + &TestProperties{}, + &TestBinaryProperties{}, &UnusedProperties{}, &StlProperties{}, &SanitizeProperties{}, @@ -899,58 +905,6 @@ func defaultsFactory() (blueprint.Module, []interface{}) { return android.InitDefaultsModule(module, module, propertyStructs...) } -// -// Device libraries shipped with gcc -// - -type toolchainLibraryLinker struct { - baseLinker -} - -var _ baseLinkerInterface = (*toolchainLibraryLinker)(nil) - -func (*toolchainLibraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { - // toolchain libraries can't have any dependencies - return deps -} - -func (*toolchainLibraryLinker) buildStatic() bool { - return true -} - -func (*toolchainLibraryLinker) buildShared() bool { - return false -} - -func toolchainLibraryFactory() (blueprint.Module, []interface{}) { - module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - module.compiler = &baseCompiler{} - module.linker = &toolchainLibraryLinker{} - module.Properties.Clang = proptools.BoolPtr(false) - return module.Init() -} - -func (library *toolchainLibraryLinker) link(ctx ModuleContext, - flags Flags, deps PathDeps, objFiles android.Paths) android.Path { - - libName := ctx.ModuleName() + staticLibraryExtension - outputFile := android.PathForModuleOut(ctx, libName) - - if flags.Clang { - ctx.ModuleErrorf("toolchain_library must use GCC, not Clang") - } - - CopyGccLib(ctx, libName, flagsToBuilderFlags(flags), outputFile) - - ctx.CheckbuildFile(outputFile) - - return outputFile -} - -func (*toolchainLibraryLinker) installable() bool { - return false -} - // lastUniqueElements returns all unique elements of a slice, keeping the last copy of each // modifies the slice contents in place, and returns a subslice of the original slice func lastUniqueElements(list []string) []string { diff --git a/cc/compiler.go b/cc/compiler.go index 0182491e..4a7bba9c 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -89,6 +89,10 @@ type BaseCompilerProperties struct { } `android:"arch_variant"` } +func NewBaseCompiler() *baseCompiler { + return &baseCompiler{} +} + type baseCompiler struct { Properties BaseCompilerProperties } @@ -311,7 +315,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD pathDeps := deps.GeneratedHeaders pathDeps = append(pathDeps, ndkPathDeps(ctx)...) // Compile files listed in c.Properties.Srcs into objects - objFiles := compiler.compileObjs(ctx, flags, "", + objFiles := compileObjs(ctx, flags, "", compiler.Properties.Srcs, compiler.Properties.Exclude_srcs, deps.GeneratedSources, pathDeps) @@ -323,7 +327,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD } // Compile a list of source files into objects a specified subdirectory -func (compiler *baseCompiler) compileObjs(ctx android.ModuleContext, flags Flags, +func compileObjs(ctx android.ModuleContext, flags Flags, subdir string, srcFiles, excludes []string, extraSrcs, deps android.Paths) android.Paths { buildFlags := flagsToBuilderFlags(flags) diff --git a/cc/installer.go b/cc/installer.go index 9a1e1fa0..a133bf20 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -30,12 +30,27 @@ type InstallerProperties struct { Symlinks []string `android:"arch_variant"` } +type installLocation int + +const ( + InstallInSystem installLocation = 0 + InstallInData = iota +) + +func NewBaseInstaller(dir, dir64 string, location installLocation) *baseInstaller { + return &baseInstaller{ + dir: dir, + dir64: dir64, + location: location, + } +} + type baseInstaller struct { Properties InstallerProperties - dir string - dir64 string - data bool + dir string + dir64 string + location installLocation path android.OutputPath } @@ -62,5 +77,5 @@ func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) { } func (installer *baseInstaller) inData() bool { - return installer.data + return installer.location == InstallInData } diff --git a/cc/library.go b/cc/library.go index 2ae18e99..14ceb289 100644 --- a/cc/library.go +++ b/cc/library.go @@ -23,33 +23,22 @@ import ( "android/soong/android" ) -type LibraryCompilerProperties struct { +type LibraryProperties struct { Static struct { Srcs []string `android:"arch_variant"` Exclude_srcs []string `android:"arch_variant"` Cflags []string `android:"arch_variant"` - } `android:"arch_variant"` - Shared struct { - Srcs []string `android:"arch_variant"` - Exclude_srcs []string `android:"arch_variant"` - Cflags []string `android:"arch_variant"` - } `android:"arch_variant"` -} -type FlagExporterProperties struct { - // 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 `android:"arch_variant"` -} - -type LibraryLinkerProperties struct { - Static struct { Enabled *bool `android:"arch_variant"` Whole_static_libs []string `android:"arch_variant"` Static_libs []string `android:"arch_variant"` Shared_libs []string `android:"arch_variant"` } `android:"arch_variant"` Shared struct { + Srcs []string `android:"arch_variant"` + Exclude_srcs []string `android:"arch_variant"` + Cflags []string `android:"arch_variant"` + Enabled *bool `android:"arch_variant"` Whole_static_libs []string `android:"arch_variant"` Static_libs []string `android:"arch_variant"` @@ -69,6 +58,21 @@ type LibraryLinkerProperties struct { Unique_host_soname *bool VariantName string `blueprint:"mutated"` + + // Build a static variant + BuildStatic bool `blueprint:"mutated"` + // Build a shared variant + BuildShared bool `blueprint:"mutated"` + // This variant is shared + VariantIsShared bool `blueprint:"mutated"` + // This variant is static + VariantIsStatic bool `blueprint:"mutated"` +} + +type FlagExporterProperties struct { + // 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 `android:"arch_variant"` } func init() { @@ -82,31 +86,31 @@ func init() { // Module factory for combined static + shared libraries, device by default but with possible host // support func libraryFactory() (blueprint.Module, []interface{}) { - module := NewLibrary(android.HostAndDeviceSupported, true, true) + module, _ := NewLibrary(android.HostAndDeviceSupported, true, true) return module.Init() } // Module factory for static libraries func libraryStaticFactory() (blueprint.Module, []interface{}) { - module := NewLibrary(android.HostAndDeviceSupported, false, true) + module, _ := NewLibrary(android.HostAndDeviceSupported, false, true) return module.Init() } // Module factory for shared libraries func librarySharedFactory() (blueprint.Module, []interface{}) { - module := NewLibrary(android.HostAndDeviceSupported, true, false) + module, _ := NewLibrary(android.HostAndDeviceSupported, true, false) return module.Init() } // Module factory for host static libraries func libraryHostStaticFactory() (blueprint.Module, []interface{}) { - module := NewLibrary(android.HostSupported, false, true) + module, _ := NewLibrary(android.HostSupported, false, true) return module.Init() } // Module factory for host shared libraries func libraryHostSharedFactory() (blueprint.Module, []interface{}) { - module := NewLibrary(android.HostSupported, true, false) + module, _ := NewLibrary(android.HostSupported, true, false) return module.Init() } @@ -137,25 +141,47 @@ type exportedFlagsProducer interface { var _ exportedFlagsProducer = (*flagExporter)(nil) -type libraryCompiler struct { - baseCompiler - - linker *libraryLinker - Properties LibraryCompilerProperties +// libraryDecorator wraps baseCompiler, baseLinker and baseInstaller to provide library-specific +// functionality: static vs. shared linkage, reusing object files for shared libraries +type libraryDecorator struct { + Properties LibraryProperties // For reusing static library objects for shared library reuseObjFiles android.Paths -} -var _ compiler = (*libraryCompiler)(nil) + flagExporter + stripper + + // If we're used as a whole_static_lib, our missing dependencies need + // to be given + wholeStaticMissingDeps []string + + // For whole_static_libs + objFiles android.Paths + + // Uses the module's name if empty, but can be overridden. Does not include + // shlib suffix. + libName string + + sanitize *sanitize -func (library *libraryCompiler) compilerProps() []interface{} { - props := library.baseCompiler.compilerProps() - return append(props, &library.Properties) + // Decorated interafaces + *baseCompiler + *baseLinker + *baseInstaller } -func (library *libraryCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { - flags = library.baseCompiler.compilerFlags(ctx, flags) +func (library *libraryDecorator) linkerProps() []interface{} { + var props []interface{} + props = append(props, library.baseLinker.linkerProps()...) + return append(props, + &library.Properties, + &library.flagExporter.Properties, + &library.stripper.StripProperties) +} + +func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + flags = library.baseLinker.linkerFlags(ctx, flags) // MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because // all code is position independent, and then those warnings get promoted to @@ -164,16 +190,47 @@ func (library *libraryCompiler) compilerFlags(ctx ModuleContext, flags Flags) Fl flags.CFlags = append(flags.CFlags, "-fPIC") } - if library.linker.static() { + if library.static() { flags.CFlags = append(flags.CFlags, library.Properties.Static.Cflags...) } else { flags.CFlags = append(flags.CFlags, library.Properties.Shared.Cflags...) } + if !library.static() { + libName := library.getLibName(ctx) + // GCC for Android assumes that -shared means -Bsymbolic, use -Wl,-shared instead + sharedFlag := "-Wl,-shared" + if flags.Clang || ctx.Host() { + sharedFlag = "-shared" + } + var f []string + if ctx.Device() { + f = append(f, + "-nostdlib", + "-Wl,--gc-sections", + ) + } + + if ctx.Darwin() { + f = append(f, + "-dynamiclib", + "-single_module", + //"-read_only_relocs suppress", + "-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(), + ) + } else { + f = append(f, + sharedFlag, + "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix()) + } + + flags.LdFlags = append(f, flags.LdFlags...) + } + return flags } -func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { +func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { var objFiles android.Paths objFiles = library.baseCompiler.compile(ctx, flags, deps) @@ -182,12 +239,12 @@ func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps Pat pathDeps := deps.GeneratedHeaders pathDeps = append(pathDeps, ndkPathDeps(ctx)...) - if library.linker.static() { - objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceStaticLibrary, + if library.static() { + objFiles = append(objFiles, compileObjs(ctx, flags, android.DeviceStaticLibrary, library.Properties.Static.Srcs, library.Properties.Static.Exclude_srcs, nil, pathDeps)...) } else { - objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceSharedLibrary, + objFiles = append(objFiles, compileObjs(ctx, flags, android.DeviceSharedLibrary, library.Properties.Shared.Srcs, library.Properties.Shared.Exclude_srcs, nil, pathDeps)...) } @@ -195,48 +252,21 @@ func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps Pat return objFiles } -type libraryLinker struct { - baseLinker - flagExporter - stripper - - Properties LibraryLinkerProperties - - dynamicProperties struct { - BuildStatic bool `blueprint:"mutated"` - BuildShared bool `blueprint:"mutated"` - } - - // If we're used as a whole_static_lib, our missing dependencies need - // to be given - wholeStaticMissingDeps []string - - // For whole_static_libs - 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) - type libraryInterface interface { getWholeStaticMissingDeps() []string static() bool objs() android.Paths -} + reuseObjs() android.Paths -func (library *libraryLinker) linkerProps() []interface{} { - props := library.baseLinker.linkerProps() - return append(props, - &library.Properties, - &library.dynamicProperties, - &library.flagExporter.Properties, - &library.stripper.StripProperties) + // Returns true if the build options for the module have selected a static or shared build + buildStatic() bool + buildShared() bool + + // Sets whether a specific variant is static or shared + setStatic(bool) } -func (library *libraryLinker) getLibName(ctx ModuleContext) string { +func (library *libraryDecorator) getLibName(ctx ModuleContext) string { name := library.libName if name == "" { name = ctx.ModuleName() @@ -251,47 +281,22 @@ func (library *libraryLinker) getLibName(ctx ModuleContext) string { return name + library.Properties.VariantName } -func (library *libraryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { - flags = library.baseLinker.linkerFlags(ctx, flags) - - if !library.static() { - libName := library.getLibName(ctx) - // GCC for Android assumes that -shared means -Bsymbolic, use -Wl,-shared instead - sharedFlag := "-Wl,-shared" - if flags.Clang || ctx.Host() { - sharedFlag = "-shared" - } - var f []string - if ctx.Device() { - f = append(f, - "-nostdlib", - "-Wl,--gc-sections", - ) - } - - if ctx.Darwin() { - f = append(f, - "-dynamiclib", - "-single_module", - //"-read_only_relocs suppress", - "-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(), - ) - } else { - f = append(f, - sharedFlag, - "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix()) - } - - flags.LdFlags = append(f, flags.LdFlags...) +func (library *libraryDecorator) linkerInit(ctx BaseModuleContext) { + location := InstallInSystem + if library.sanitize.inData() { + location = InstallInData } + library.baseInstaller.location = location - return flags + library.baseLinker.linkerInit(ctx) } -func (library *libraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { +func (library *libraryDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { deps = library.baseLinker.linkerDeps(ctx, deps) + if library.static() { - deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.Properties.Static.Whole_static_libs...) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, + library.Properties.Static.Whole_static_libs...) deps.StaticLibs = append(deps.StaticLibs, library.Properties.Static.Static_libs...) deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...) } else { @@ -312,7 +317,7 @@ func (library *libraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps return deps } -func (library *libraryLinker) linkStatic(ctx ModuleContext, +func (library *libraryDecorator) linkStatic(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path { library.objFiles = append(android.Paths{}, deps.WholeStaticLibObjFiles...) @@ -334,7 +339,7 @@ func (library *libraryLinker) linkStatic(ctx ModuleContext, return outputFile } -func (library *libraryLinker) linkShared(ctx ModuleContext, +func (library *libraryDecorator) linkShared(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path { var linkerDeps android.Paths @@ -397,7 +402,7 @@ func (library *libraryLinker) linkShared(ctx ModuleContext, return ret } -func (library *libraryLinker) link(ctx ModuleContext, +func (library *libraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path { objFiles = append(objFiles, deps.ObjFiles...) @@ -415,64 +420,92 @@ func (library *libraryLinker) link(ctx ModuleContext, return out } -func (library *libraryLinker) buildStatic() bool { - return library.dynamicProperties.BuildStatic && +func (library *libraryDecorator) buildStatic() bool { + return library.Properties.BuildStatic && (library.Properties.Static.Enabled == nil || *library.Properties.Static.Enabled) } -func (library *libraryLinker) buildShared() bool { - return library.dynamicProperties.BuildShared && +func (library *libraryDecorator) buildShared() bool { + return library.Properties.BuildShared && (library.Properties.Shared.Enabled == nil || *library.Properties.Shared.Enabled) } -func (library *libraryLinker) getWholeStaticMissingDeps() []string { +func (library *libraryDecorator) getWholeStaticMissingDeps() []string { return library.wholeStaticMissingDeps } -func (library *libraryLinker) installable() bool { - return !library.static() -} - -func (library *libraryLinker) objs() android.Paths { +func (library *libraryDecorator) objs() android.Paths { return library.objFiles } -type libraryInstaller struct { - baseInstaller - - linker *libraryLinker - sanitize *sanitize +func (library *libraryDecorator) reuseObjs() android.Paths { + return library.reuseObjFiles } -func (library *libraryInstaller) install(ctx ModuleContext, file android.Path) { - if !library.linker.static() { +func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { + if !ctx.static() { library.baseInstaller.install(ctx, file) } } -func (library *libraryInstaller) inData() bool { - return library.baseInstaller.inData() || library.sanitize.inData() +func (library *libraryDecorator) static() bool { + return library.Properties.VariantIsStatic } -func NewLibrary(hod android.HostOrDeviceSupported, shared, static bool) *Module { - module := newModule(hod, android.MultilibBoth) +func (library *libraryDecorator) setStatic(static bool) { + library.Properties.VariantIsStatic = static +} - linker := &libraryLinker{} - linker.dynamicProperties.BuildShared = shared - linker.dynamicProperties.BuildStatic = static - module.linker = linker +func NewLibrary(hod android.HostOrDeviceSupported, shared, static bool) (*Module, *libraryDecorator) { + module := newModule(hod, android.MultilibBoth) - module.compiler = &libraryCompiler{ - linker: linker, - } - module.installer = &libraryInstaller{ - baseInstaller: baseInstaller{ - dir: "lib", - dir64: "lib64", + library := &libraryDecorator{ + Properties: LibraryProperties{ + BuildShared: shared, + BuildStatic: static, }, - linker: linker, - sanitize: module.sanitize, + baseCompiler: NewBaseCompiler(), + baseLinker: NewBaseLinker(), + baseInstaller: NewBaseInstaller("lib", "lib64", InstallInSystem), + sanitize: module.sanitize, } - return module + module.compiler = library + module.linker = library + module.installer = library + + return module, library +} + +func linkageMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*Module); ok && m.linker != nil { + if library, ok := m.linker.(libraryInterface); ok { + var modules []blueprint.Module + if library.buildStatic() && library.buildShared() { + modules = mctx.CreateLocalVariations("static", "shared") + static := modules[0].(*Module) + shared := modules[1].(*Module) + + static.linker.(libraryInterface).setStatic(true) + shared.linker.(libraryInterface).setStatic(false) + + if staticCompiler, ok := static.compiler.(*libraryDecorator); ok { + sharedCompiler := shared.compiler.(*libraryDecorator) + if len(staticCompiler.Properties.Static.Cflags) == 0 && + len(sharedCompiler.Properties.Shared.Cflags) == 0 { + // Optimize out compiling common .o files twice for static+shared libraries + mctx.AddInterVariantDependency(reuseObjTag, shared, static) + sharedCompiler.baseCompiler.Properties.Srcs = nil + sharedCompiler.baseCompiler.Properties.Generated_sources = nil + } + } + } else if library.buildStatic() { + modules = mctx.CreateLocalVariations("static") + modules[0].(*Module).linker.(libraryInterface).setStatic(true) + } else if library.buildShared() { + modules = mctx.CreateLocalVariations("shared") + modules[0].(*Module).linker.(libraryInterface).setStatic(false) + } + } + } } diff --git a/cc/linker.go b/cc/linker.go index 97677559..df19de7a 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -14,6 +14,11 @@ package cc +import ( + "android/soong/android" + "fmt" +) + // This file contains the basic functionality for linking against static libraries and shared // libraries. Final linking into libraries or executables is handled in library.go, binary.go, etc. @@ -67,14 +72,15 @@ type BaseLinkerProperties struct { Nocrt *bool `android:"arch_variant"` } +func NewBaseLinker() *baseLinker { + return &baseLinker{} +} + // baseLinker provides support for shared_libs, static_libs, and whole_static_libs properties type baseLinker struct { Properties BaseLinkerProperties dynamicProperties struct { - VariantIsShared bool `blueprint:"mutated"` - VariantIsStatic bool `blueprint:"mutated"` - VariantIsStaticBinary bool `blueprint:"mutated"` - RunPaths []string `blueprint:"mutated"` + RunPaths []string `blueprint:"mutated"` } } @@ -84,9 +90,9 @@ func (linker *baseLinker) appendLdflags(flags []string) { func (linker *baseLinker) linkerInit(ctx BaseModuleContext) { if ctx.toolchain().Is64Bit() { - linker.dynamicProperties.RunPaths = []string{"../lib64", "lib64"} + linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, "../lib64", "lib64") } else { - linker.dynamicProperties.RunPaths = []string{"../lib", "lib"} + linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, "../lib", "lib") } } @@ -113,7 +119,7 @@ func (linker *baseLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc") } - if !linker.static() { + if !ctx.static() { if linker.Properties.System_shared_libs != nil { deps.LateSharedLibs = append(deps.LateSharedLibs, linker.Properties.System_shared_libs...) @@ -158,7 +164,7 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags.LdFlags = append(flags.LdFlags, linker.Properties.Ldflags...) - if ctx.Host() && !linker.static() { + if ctx.Host() { rpath_prefix := `\$$ORIGIN/` if ctx.Darwin() { rpath_prefix = "@loader_path/" @@ -178,37 +184,7 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (linker *baseLinker) static() bool { - return linker.dynamicProperties.VariantIsStatic -} - -func (linker *baseLinker) staticBinary() bool { - return linker.dynamicProperties.VariantIsStaticBinary -} - -func (linker *baseLinker) setStatic(static bool) { - linker.dynamicProperties.VariantIsStatic = static -} - -func (linker *baseLinker) isDependencyRoot() bool { - return false -} - -type baseLinkerInterface interface { - // Returns true if the build options for the module have selected a static or shared build - buildStatic() bool - buildShared() bool - - // Sets whether a specific variant is static or shared - setStatic(bool) - - // Returns whether a specific variant is a static library or binary - static() bool - - // Returns whether a module is a static binary - staticBinary() bool - - // Returns true for dependency roots (binaries) - // TODO(ccross): also handle dlopenable libraries - isDependencyRoot() bool +func (linker *baseLinker) link(ctx ModuleContext, + flags Flags, deps PathDeps, objFiles android.Paths) android.Path { + panic(fmt.Errorf("baseLinker doesn't know how to link")) } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 1dd02de2..891b49a5 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -89,12 +89,13 @@ type libraryProperties struct { ApiLevel int `blueprint:"mutated"` } -type stubCompiler struct { - baseCompiler +type stubDecorator struct { + *libraryDecorator properties libraryProperties - linker *stubLinker + versionScriptPath android.ModuleGenPath + installPath string } // OMG GO @@ -106,7 +107,7 @@ func intMin(a int, b int) int { } } -func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubCompiler) { +func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) { 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 @@ -152,19 +153,19 @@ func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubCompile modules := mctx.CreateVariations(versionStrs...) for i, module := range modules { - module.(*Module).compiler.(*stubCompiler).properties.ApiLevel = firstGenVersion + i + module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = firstGenVersion + i } } func ndkApiMutator(mctx android.BottomUpMutatorContext) { if m, ok := mctx.Module().(*Module); ok { - if compiler, ok := m.compiler.(*stubCompiler); ok { + if compiler, ok := m.compiler.(*stubDecorator); ok { generateStubApiVariants(mctx, compiler) } } } -func (c *stubCompiler) compilerInit(ctx BaseModuleContext) { +func (c *stubDecorator) compilerInit(ctx BaseModuleContext) { c.baseCompiler.compilerInit(ctx) name := strings.TrimSuffix(ctx.ModuleName(), ".ndk") @@ -176,7 +177,7 @@ func (c *stubCompiler) compilerInit(ctx BaseModuleContext) { ndkMigratedLibs = append(ndkMigratedLibs, name) } -func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { +func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { arch := ctx.Arch().ArchType.String() if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) { @@ -189,7 +190,7 @@ func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) an stubSrcPath := android.PathForModuleGen(ctx, stubSrcName) versionScriptName := fileBase + ".map" versionScriptPath := android.PathForModuleGen(ctx, versionScriptName) - c.linker.versionScriptPath = versionScriptPath + c.versionScriptPath = versionScriptPath symbolFilePath := android.PathForModuleSrc(ctx, c.properties.Symbol_file) ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: genStubSrc, @@ -218,47 +219,31 @@ func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) an excludeSrcs := []string{} extraSrcs := []android.Path{stubSrcPath} extraDeps := []android.Path{} - return c.baseCompiler.compileObjs(ctx, flags, subdir, srcs, excludeSrcs, + return compileObjs(ctx, flags, subdir, srcs, excludeSrcs, extraSrcs, extraDeps) } -type stubLinker struct { - libraryLinker - - versionScriptPath android.ModuleGenPath -} - -func (linker *stubLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { +func (linker *stubDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { return Deps{} } -func (linker *stubLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { - linker.libraryLinker.libName = strings.TrimSuffix(ctx.ModuleName(), +func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + stub.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix) - return linker.libraryLinker.linkerFlags(ctx, flags) + return stub.libraryDecorator.linkerFlags(ctx, flags) } -func (linker *stubLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, +func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path { - linkerScriptFlag := "-Wl,--version-script," + linker.versionScriptPath.String() + linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String() flags.LdFlags = append(flags.LdFlags, linkerScriptFlag) - return linker.libraryLinker.link(ctx, flags, deps, objFiles) -} - -type stubInstaller struct { - baseInstaller - - compiler *stubCompiler - - installPath string + return stub.libraryDecorator.link(ctx, flags, deps, objFiles) } -var _ installer = (*stubInstaller)(nil) - -func (installer *stubInstaller) install(ctx ModuleContext, path android.Path) { +func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) { arch := ctx.Target().Arch.ArchType.Name - apiLevel := installer.compiler.properties.ApiLevel + apiLevel := stub.properties.ApiLevel // arm64 isn't actually a multilib toolchain, so unlike the other LP64 // architectures it's just installed to lib. @@ -269,32 +254,26 @@ func (installer *stubInstaller) install(ctx ModuleContext, path android.Path) { installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf( "platforms/android-%d/arch-%s/usr/%s", apiLevel, arch, libDir)) - installer.installPath = ctx.InstallFile(installDir, path).String() + stub.installPath = ctx.InstallFile(installDir, path).String() } func newStubLibrary() *Module { - module := newModule(android.DeviceSupported, android.MultilibBoth) + module, library := NewLibrary(android.DeviceSupported, true, false) module.stl = nil + module.sanitize = nil + library.StripProperties.Strip.None = true - linker := &stubLinker{} - linker.dynamicProperties.BuildShared = true - linker.dynamicProperties.BuildStatic = false - linker.stripper.StripProperties.Strip.None = true - module.linker = linker - - compiler := &stubCompiler{} - compiler.linker = linker - module.compiler = compiler - module.installer = &stubInstaller{baseInstaller{ - dir: "lib", - dir64: "lib64", - }, compiler, ""} + stub := &stubDecorator{ + libraryDecorator: library, + } + module.compiler = stub + module.linker = stub + module.installer = stub return module } func ndkLibraryFactory() (blueprint.Module, []interface{}) { module := newStubLibrary() - return android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth, - &module.compiler.(*stubCompiler).properties) + return module.Init() } diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index 2b24507e..407a026a 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -70,7 +70,11 @@ func (*ndkPrebuiltObjectLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Dep func ndkPrebuiltObjectFactory() (blueprint.Module, []interface{}) { module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - module.linker = &ndkPrebuiltObjectLinker{} + module.linker = &ndkPrebuiltObjectLinker{ + objectLinker: objectLinker{ + baseLinker: NewBaseLinker(), + }, + } module.Properties.HideFromMake = true return module.Init() } @@ -86,14 +90,11 @@ func (c *ndkPrebuiltObjectLinker) link(ctx ModuleContext, flags Flags, } type ndkPrebuiltLibraryLinker struct { - libraryLinker + *libraryDecorator } -var _ baseLinkerInterface = (*ndkPrebuiltLibraryLinker)(nil) -var _ exportedFlagsProducer = (*libraryLinker)(nil) - func (ndk *ndkPrebuiltLibraryLinker) linkerProps() []interface{} { - return append(ndk.libraryLinker.linkerProps(), &ndk.Properties, &ndk.flagExporter.Properties) + return append(ndk.libraryDecorator.linkerProps(), &ndk.Properties, &ndk.flagExporter.Properties) } func (*ndkPrebuiltLibraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { @@ -102,10 +103,14 @@ func (*ndkPrebuiltLibraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) De } func ndkPrebuiltLibraryFactory() (blueprint.Module, []interface{}) { - module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - linker := &ndkPrebuiltLibraryLinker{} - linker.dynamicProperties.BuildShared = true + module, library := NewLibrary(android.DeviceSupported, true, false) + linker := &ndkPrebuiltLibraryLinker{ + libraryDecorator: library, + } + module.compiler = nil module.linker = linker + module.installer = nil + module.stl = nil module.Properties.HideFromMake = true return module.Init() } @@ -128,19 +133,29 @@ type ndkPrebuiltStlLinker struct { } func ndkPrebuiltSharedStlFactory() (blueprint.Module, []interface{}) { - module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - linker := &ndkPrebuiltStlLinker{} - linker.dynamicProperties.BuildShared = true + module, library := NewLibrary(android.DeviceSupported, true, false) + linker := &ndkPrebuiltStlLinker{ + ndkPrebuiltLibraryLinker: ndkPrebuiltLibraryLinker{ + libraryDecorator: library, + }, + } + module.compiler = nil module.linker = linker + module.installer = nil module.Properties.HideFromMake = true return module.Init() } func ndkPrebuiltStaticStlFactory() (blueprint.Module, []interface{}) { - module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - linker := &ndkPrebuiltStlLinker{} - linker.dynamicProperties.BuildStatic = true + module, library := NewLibrary(android.DeviceSupported, false, true) + linker := &ndkPrebuiltStlLinker{ + ndkPrebuiltLibraryLinker: ndkPrebuiltLibraryLinker{ + libraryDecorator: library, + }, + } + module.compiler = nil module.linker = linker + module.installer = nil module.Properties.HideFromMake = true return module.Init() } @@ -177,7 +192,7 @@ func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_") libExt := flags.Toolchain.ShlibSuffix() - if ndk.dynamicProperties.BuildStatic { + if ndk.Properties.BuildStatic { libExt = staticLibraryExtension } @@ -186,40 +201,3 @@ func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, libDir := getNdkStlLibDir(ctx, flags.Toolchain, stlName) return libDir.Join(ctx, libName+libExt) } - -func linkageMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*Module); ok { - if m.linker != nil { - if linker, ok := m.linker.(baseLinkerInterface); ok { - var modules []blueprint.Module - if linker.buildStatic() && linker.buildShared() { - modules = mctx.CreateLocalVariations("static", "shared") - static := modules[0].(*Module) - shared := modules[1].(*Module) - - static.linker.(baseLinkerInterface).setStatic(true) - shared.linker.(baseLinkerInterface).setStatic(false) - - if staticCompiler, ok := static.compiler.(*libraryCompiler); ok { - sharedCompiler := shared.compiler.(*libraryCompiler) - if len(staticCompiler.Properties.Static.Cflags) == 0 && - len(sharedCompiler.Properties.Shared.Cflags) == 0 { - // Optimize out compiling common .o files twice for static+shared libraries - mctx.AddInterVariantDependency(reuseObjTag, shared, static) - sharedCompiler.baseCompiler.Properties.Srcs = nil - sharedCompiler.baseCompiler.Properties.Generated_sources = nil - } - } - } else if linker.buildStatic() { - modules = mctx.CreateLocalVariations("static") - modules[0].(*Module).linker.(baseLinkerInterface).setStatic(true) - } else if linker.buildShared() { - modules = mctx.CreateLocalVariations("shared") - modules[0].(*Module).linker.(baseLinkerInterface).setStatic(false) - } else { - panic(fmt.Errorf("library %q not static or shared", mctx.ModuleName())) - } - } - } - } -} diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index 2eae360c..04dce7b1 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -96,7 +96,7 @@ func (n *ndkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { ctx.VisitAllModules(func(module blueprint.Module) { if m, ok := module.(*Module); ok { - if installer, ok := m.installer.(*stubInstaller); ok { + if installer, ok := m.installer.(*stubDecorator); ok { installPaths = append(installPaths, installer.installPath) } } diff --git a/cc/object.go b/cc/object.go index fbb7b7f2..c9f0a060 100644 --- a/cc/object.go +++ b/cc/object.go @@ -32,13 +32,16 @@ func init() { } type objectLinker struct { + *baseLinker Properties ObjectLinkerProperties } func objectFactory() (blueprint.Module, []interface{}) { module := newBaseModule(android.DeviceSupported, android.MultilibBoth) - module.compiler = &baseCompiler{} - module.linker = &objectLinker{} + module.linker = &objectLinker{ + baseLinker: NewBaseLinker(), + } + module.compiler = NewBaseCompiler() return module.Init() } @@ -84,7 +87,3 @@ func (object *objectLinker) link(ctx ModuleContext, ctx.CheckbuildFile(outputFile) return outputFile } - -func (*objectLinker) installable() bool { - return false -} diff --git a/cc/sanitize.go b/cc/sanitize.go index e7f021a3..fb7cb371 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -345,7 +345,7 @@ func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) { func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { return func(mctx android.BottomUpMutatorContext) { if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { - if d, ok := c.linker.(baseLinkerInterface); ok && d.isDependencyRoot() && c.sanitize.Sanitizer(t) { + if c.isDependencyRoot() && c.sanitize.Sanitizer(t) { modules := mctx.CreateVariations(t.String()) modules[0].(*Module).sanitize.SetSanitizer(t, true) if mctx.AConfig().EmbeddedInMake() && !c.Host() { @@ -24,10 +24,12 @@ import ( "android/soong/android" ) -type TestLinkerProperties struct { +type TestProperties struct { // if set, build against the gtest library. Defaults to true. Gtest bool +} +type TestBinaryProperties struct { // Create a separate binary for each source file. Useful when there is // global state that can not be torn down and reset between each test suite. Test_per_src *bool @@ -71,29 +73,50 @@ func benchmarkHostFactory() (blueprint.Module, []interface{}) { return module.Init() } +type testPerSrc interface { + testPerSrc() bool + srcs() []string + setSrc(string, string) +} + +func (test *testBinary) testPerSrc() bool { + return Bool(test.Properties.Test_per_src) +} + +func (test *testBinary) srcs() []string { + return test.baseCompiler.Properties.Srcs +} + +func (test *testBinary) setSrc(name, src string) { + test.baseCompiler.Properties.Srcs = []string{src} + test.binaryDecorator.Properties.Stem = name +} + +var _ testPerSrc = (*testBinary)(nil) + func testPerSrcMutator(mctx android.BottomUpMutatorContext) { if m, ok := mctx.Module().(*Module); ok { - if test, ok := m.linker.(*testBinaryLinker); ok { - if Bool(test.testLinker.Properties.Test_per_src) { - testNames := make([]string, len(m.compiler.(*baseCompiler).Properties.Srcs)) - for i, src := range m.compiler.(*baseCompiler).Properties.Srcs { + if test, ok := m.linker.(testPerSrc); ok { + if test.testPerSrc() && len(test.srcs()) > 0 { + testNames := make([]string, len(test.srcs())) + for i, src := range test.srcs() { testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) } tests := mctx.CreateLocalVariations(testNames...) - for i, src := range m.compiler.(*baseCompiler).Properties.Srcs { - tests[i].(*Module).compiler.(*baseCompiler).Properties.Srcs = []string{src} - tests[i].(*Module).linker.(*testBinaryLinker).binaryLinker.Properties.Stem = testNames[i] + for i, src := range test.srcs() { + tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) } } } } } -type testLinker struct { - Properties TestLinkerProperties +type testDecorator struct { + Properties TestProperties + linker *baseLinker } -func (test *testLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { +func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { if !test.Properties.Gtest { return flags } @@ -119,7 +142,7 @@ func (test *testLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (test *testLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { +func (test *testDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { if test.Properties.Gtest { if ctx.sdk() && ctx.Device() { switch ctx.selectedStl() { @@ -134,123 +157,156 @@ func (test *testLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest") } } - return deps -} -type testBinaryLinker struct { - testLinker - binaryLinker + return deps } -func (test *testBinaryLinker) linkerInit(ctx BaseModuleContext) { - test.binaryLinker.linkerInit(ctx) +func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) { runpath := "../../lib" if ctx.toolchain().Is64Bit() { runpath += "64" } - test.dynamicProperties.RunPaths = append([]string{runpath}, test.dynamicProperties.RunPaths...) + linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath) } -func (test *testBinaryLinker) linkerProps() []interface{} { - return append(test.binaryLinker.linkerProps(), &test.testLinker.Properties) +func (test *testDecorator) linkerProps() []interface{} { + return []interface{}{&test.Properties} } -func (test *testBinaryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { - flags = test.binaryLinker.linkerFlags(ctx, flags) - flags = test.testLinker.linkerFlags(ctx, flags) - return flags +func NewTestInstaller() *baseInstaller { + return NewBaseInstaller("nativetest", "nativetest64", InstallInData) } -func (test *testBinaryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { - deps = test.testLinker.linkerDeps(ctx, deps) - deps = test.binaryLinker.linkerDeps(ctx, deps) - return deps +type testBinary struct { + testDecorator + *binaryDecorator + *baseCompiler + *baseInstaller + Properties TestBinaryProperties } -type testLibraryLinker struct { - testLinker - *libraryLinker +func (test *testBinary) linkerProps() []interface{} { + props := append(test.testDecorator.linkerProps(), test.binaryDecorator.linkerProps()...) + props = append(props, &test.Properties) + return props } -func (test *testLibraryLinker) linkerProps() []interface{} { - return append(test.libraryLinker.linkerProps(), &test.testLinker.Properties) +func (test *testBinary) linkerInit(ctx BaseModuleContext) { + test.testDecorator.linkerInit(ctx, test.binaryDecorator.baseLinker) + test.binaryDecorator.linkerInit(ctx) } -func (test *testLibraryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { - flags = test.libraryLinker.linkerFlags(ctx, flags) - flags = test.testLinker.linkerFlags(ctx, flags) - return flags -} - -func (test *testLibraryLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { - deps = test.testLinker.linkerDeps(ctx, deps) - deps = test.libraryLinker.linkerDeps(ctx, deps) +func (test *testBinary) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { + deps = test.testDecorator.linkerDeps(ctx, deps) + deps = test.binaryDecorator.linkerDeps(ctx, deps) return deps } -type testInstaller struct { - baseInstaller +func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { + flags = test.binaryDecorator.linkerFlags(ctx, flags) + flags = test.testDecorator.linkerFlags(ctx, flags) + return flags } -func (installer *testInstaller) install(ctx ModuleContext, file android.Path) { - installer.dir = filepath.Join(installer.dir, ctx.ModuleName()) - installer.dir64 = filepath.Join(installer.dir64, ctx.ModuleName()) - installer.baseInstaller.install(ctx, file) +func (test *testBinary) install(ctx ModuleContext, file android.Path) { + test.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName()) + test.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName()) + test.baseInstaller.install(ctx, file) } func NewTest(hod android.HostOrDeviceSupported) *Module { - module := newModule(hod, android.MultilibBoth) - module.compiler = &baseCompiler{} - linker := &testBinaryLinker{} - linker.testLinker.Properties.Gtest = true - module.linker = linker - module.installer = &testInstaller{ - baseInstaller: baseInstaller{ - dir: "nativetest", - dir64: "nativetest64", - data: true, + module, binary := NewBinary(hod) + module.multilib = android.MultilibBoth + + test := &testBinary{ + testDecorator: testDecorator{ + linker: binary.baseLinker, }, + binaryDecorator: binary, + baseCompiler: NewBaseCompiler(), + baseInstaller: NewTestInstaller(), } + test.testDecorator.Properties.Gtest = true + module.compiler = test + module.linker = test + module.installer = test return module } +type testLibrary struct { + testDecorator + *libraryDecorator +} + +func (test *testLibrary) linkerProps() []interface{} { + return append(test.testDecorator.linkerProps(), test.libraryDecorator.linkerProps()...) +} + +func (test *testLibrary) linkerInit(ctx BaseModuleContext) { + test.testDecorator.linkerInit(ctx, test.libraryDecorator.baseLinker) + test.libraryDecorator.linkerInit(ctx) +} + +func (test *testLibrary) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { + deps = test.testDecorator.linkerDeps(ctx, deps) + deps = test.libraryDecorator.linkerDeps(ctx, deps) + return deps +} + +func (test *testLibrary) linkerFlags(ctx ModuleContext, flags Flags) Flags { + flags = test.libraryDecorator.linkerFlags(ctx, flags) + flags = test.testDecorator.linkerFlags(ctx, flags) + return flags +} + func NewTestLibrary(hod android.HostOrDeviceSupported) *Module { - module := NewLibrary(android.HostAndDeviceSupported, false, true) - linker := &testLibraryLinker{ - libraryLinker: module.linker.(*libraryLinker), - } - linker.testLinker.Properties.Gtest = true - module.linker = linker - module.installer = &testInstaller{ - baseInstaller: baseInstaller{ - dir: "nativetest", - dir64: "nativetest64", - data: true, + module, library := NewLibrary(android.HostAndDeviceSupported, false, true) + test := &testLibrary{ + testDecorator: testDecorator{ + linker: library.baseLinker, }, + libraryDecorator: library, } + test.testDecorator.Properties.Gtest = true + module.linker = test + module.installer = nil return module } -type benchmarkLinker struct { - testBinaryLinker +type benchmarkDecorator struct { + *binaryDecorator + *baseInstaller } -func (benchmark *benchmarkLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { - deps = benchmark.testBinaryLinker.linkerDeps(ctx, deps) +func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) { + runpath := "../../lib" + if ctx.toolchain().Is64Bit() { + runpath += "64" + } + benchmark.baseLinker.dynamicProperties.RunPaths = append(benchmark.baseLinker.dynamicProperties.RunPaths, runpath) + benchmark.binaryDecorator.linkerInit(ctx) +} + +func (benchmark *benchmarkDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { + deps = benchmark.binaryDecorator.linkerDeps(ctx, deps) deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark") return deps } +func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) { + benchmark.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName()) + benchmark.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName()) +} + func NewBenchmark(hod android.HostOrDeviceSupported) *Module { - module := newModule(hod, android.MultilibFirst) - module.compiler = &baseCompiler{} - module.linker = &benchmarkLinker{} - module.installer = &testInstaller{ - baseInstaller: baseInstaller{ - dir: "nativetest", - dir64: "nativetest64", - data: true, - }, + module, binary := NewBinary(hod) + module.multilib = android.MultilibBoth + + benchmark := &benchmarkDecorator{ + binaryDecorator: binary, + baseInstaller: NewTestInstaller(), } + module.linker = benchmark + module.installer = benchmark return module } diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go new file mode 100644 index 00000000..0548da98 --- /dev/null +++ b/cc/toolchain_library.go @@ -0,0 +1,76 @@ +// 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 ( + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + + "android/soong" + "android/soong/android" +) + +// +// Device libraries shipped with gcc +// + +func init() { + soong.RegisterModuleType("toolchain_library", toolchainLibraryFactory) +} + +type toolchainLibraryDecorator struct { + *libraryDecorator +} + +func (*toolchainLibraryDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { + // toolchain libraries can't have any dependencies + return deps +} + +func toolchainLibraryFactory() (blueprint.Module, []interface{}) { + module, library := NewLibrary(android.DeviceSupported, false, true) + toolchainLibrary := &toolchainLibraryDecorator{ + libraryDecorator: library, + } + module.compiler = toolchainLibrary + module.linker = toolchainLibrary + module.Properties.Clang = proptools.BoolPtr(false) + module.stl = nil + module.sanitize = nil + module.installer = nil + return module.Init() +} + +func (library *toolchainLibraryDecorator) compile(ctx ModuleContext, flags Flags, + deps PathDeps) android.Paths { + return nil +} + +func (library *toolchainLibraryDecorator) link(ctx ModuleContext, + flags Flags, deps PathDeps, objFiles android.Paths) android.Path { + + libName := ctx.ModuleName() + staticLibraryExtension + outputFile := android.PathForModuleOut(ctx, libName) + + if flags.Clang { + ctx.ModuleErrorf("toolchain_library must use GCC, not Clang") + } + + CopyGccLib(ctx, libName, flagsToBuilderFlags(flags), outputFile) + + ctx.CheckbuildFile(outputFile) + + return outputFile +} |