// Copyright 2015 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 // This file contains the module types for compiling C/C++ for Android, and converts the properties // into the flags and filenames necessary to pass to the compiler. The final creation of the rules // is handled in builder.go import ( "blueprint" "blueprint/pathtools" "fmt" "path/filepath" "strings" "android/soong/common" "android/soong/genrule" ) type Config interface { SrcDir() string PrebuiltOS() string } var ( HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", Config.PrebuiltOS) SrcDir = pctx.VariableConfigMethod("SrcDir", Config.SrcDir) LibcRoot = pctx.StaticVariable("LibcRoot", "${SrcDir}/bionic/libc") LibmRoot = pctx.StaticVariable("LibmRoot", "${SrcDir}/bionic/libm") ) // Flags used by lots of devices. Putting them in package static variables will save bytes in // build.ninja so they aren't repeated for every file var ( commonGlobalCflags = []string{ "-DANDROID", "-fmessage-length=0", "-W", "-Wall", "-Wno-unused", "-Winit-self", "-Wpointer-arith", // COMMON_RELEASE_CFLAGS "-DNDEBUG", "-UDEBUG", } deviceGlobalCflags = []string{ // TARGET_ERROR_FLAGS "-Werror=return-type", "-Werror=non-virtual-dtor", "-Werror=address", "-Werror=sequence-point", } hostGlobalCflags = []string{} commonGlobalCppflags = []string{ "-Wsign-promo", "-std=gnu++11", } ) func init() { pctx.StaticVariable("commonGlobalCflags", strings.Join(commonGlobalCflags, " ")) pctx.StaticVariable("deviceGlobalCflags", strings.Join(deviceGlobalCflags, " ")) pctx.StaticVariable("hostGlobalCflags", strings.Join(hostGlobalCflags, " ")) pctx.StaticVariable("commonGlobalCppflags", strings.Join(commonGlobalCppflags, " ")) pctx.StaticVariable("commonClangGlobalCflags", strings.Join(clangFilterUnknownCflags(commonGlobalCflags), " ")) pctx.StaticVariable("deviceClangGlobalCflags", strings.Join(clangFilterUnknownCflags(deviceGlobalCflags), " ")) pctx.StaticVariable("hostClangGlobalCflags", strings.Join(clangFilterUnknownCflags(hostGlobalCflags), " ")) pctx.StaticVariable("commonClangGlobalCppflags", strings.Join(clangFilterUnknownCflags(commonGlobalCppflags), " ")) // Everything in this list is a crime against abstraction and dependency tracking. // Do not add anything to this list. pctx.StaticVariable("commonGlobalIncludes", strings.Join([]string{ "-isystem ${SrcDir}/system/core/include", "-isystem ${SrcDir}/hardware/libhardware/include", "-isystem ${SrcDir}/hardware/libhardware_legacy/include", "-isystem ${SrcDir}/hardware/ril/include", "-isystem ${SrcDir}/libnativehelper/include", "-isystem ${SrcDir}/frameworks/native/include", "-isystem ${SrcDir}/frameworks/native/opengl/include", "-isystem ${SrcDir}/frameworks/av/include", "-isystem ${SrcDir}/frameworks/base/include", }, " ")) pctx.StaticVariable("clangPath", "${SrcDir}/prebuilts/clang/${HostPrebuiltTag}/host/3.6/bin/") } // CcProperties describes properties used to compile all C or C++ modules type ccProperties struct { // srcs: list of source files used to compile the C/C++ module. May be .c, .cpp, or .S files. Srcs []string `android:"arch_variant,arch_subtract"` // cflags: list of module-specific flags that will be used for C and C++ compiles. Cflags []string `android:"arch_variant"` // cppflags: list of module-specific flags that will be used for C++ compiles Cppflags []string `android:"arch_variant"` // conlyflags: list of module-specific flags that will be used for C compiles Conlyflags []string `android:"arch_variant"` // asflags: list of module-specific flags that will be used for .S compiles Asflags []string `android:"arch_variant"` // ldflags: list of module-specific flags that will be used for all link steps Ldflags []string `android:"arch_variant"` // instruction_set: the instruction set architecture to use to compile the C/C++ // module. Instruction_set string `android:"arch_variant"` // include_dirs: list of directories relative to the root of the source tree that will // be added to the include path using -I. // If possible, don't use this. If adding paths from the current directory use // local_include_dirs, if adding paths from other modules use export_include_dirs in // that module. Include_dirs []string `android:"arch_variant"` // local_include_dirs: list of directories relative to the Blueprints file that will // be added to the include path using -I Local_include_dirs []string `android:"arch_variant"` // export_include_dirs: list of directories relative to the Blueprints file that will // be added to the include path using -I for any module that links against this module Export_include_dirs []string // clang_cflags: list of module-specific flags that will be used for C and C++ compiles when // compiling with clang Clang_cflags []string `android:"arch_variant"` // clang_asflags: list of module-specific flags that will be used for .S compiles when // compiling with clang Clang_asflags []string `android:"arch_variant"` // system_shared_libs: list of system libraries that will be dynamically linked to // shared library and executable modules. If unset, generally defaults to libc // and libm. Set to [] to prevent linking against libc and libm. System_shared_libs []string // whole_static_libs: list of modules whose object files should be linked into this module // in their entirety. For static library modules, all of the .o files from the intermediate // directory of the dependency will be linked into this modules .a file. For a shared library, // the dependency's .a file will be linked into this module using -Wl,--whole-archive. Whole_static_libs []string `android:"arch_variant"` // static_libs: list of modules that should be statically linked into this module. Static_libs []string `android:"arch_variant"` // shared_libs: list of modules that should be dynamically linked into this module. Shared_libs []string `android:"arch_variant"` // allow_undefined_symbols: allow the module to contain undefined symbols. By default, // modules cannot contain undefined symbols that are not satisified by their immediate // dependencies. Set this flag to true to remove --no-undefined from the linker flags. // This flag should only be necessary for compiling low-level libraries like libc. Allow_undefined_symbols bool // nocrt: don't link in crt_begin and crt_end. This flag should only be necessary for // compiling crt or libc. Nocrt bool `android:"arch_variant"` // no_default_compiler_flags: don't insert default compiler flags into asflags, cflags, // cppflags, conlyflags, ldflags, or include_dirs No_default_compiler_flags bool // clang: compile module with clang instead of gcc Clang bool `android:"arch_variant"` // rtti: pass -frtti instead of -fno-rtti Rtti bool // host_ldlibs: -l arguments to pass to linker for host-provided shared libraries Host_ldlibs []string `android:"arch_variant"` // stl: select the STL library to use. Possible values are "libc++", "libc++_static", // "stlport", "stlport_static", "ndk", "libstdc++", or "none". Leave blank to select the // default Stl string // Set for combined shared/static libraries to prevent compiling object files a second time SkipCompileObjs bool `blueprint:"mutated"` Debug struct { Cflags []string `android:"arch_variant"` } `android:"arch_variant"` Release struct { Cflags []string `android:"arch_variant"` } `android:"arch_variant"` // Minimum sdk version supported when compiling against the ndk Sdk_version string } type unusedProperties struct { Asan bool Native_coverage bool Strip string Tags []string Required []string } // Building C/C++ code is handled by objects that satisfy this interface via composition type ccModuleType interface { common.AndroidModule // Return the cflags that are specific to this _type_ of module moduleTypeCflags(common.AndroidModuleContext, toolchain) []string // Return the ldflags that are specific to this _type_ of module moduleTypeLdflags(common.AndroidModuleContext, toolchain) []string // Create a ccDeps struct that collects the module dependency info. Can also // modify ccFlags in order to add dependency include directories, etc. collectDeps(common.AndroidModuleContext, ccFlags) (ccDeps, ccFlags) // Compile objects into final module compileModule(common.AndroidModuleContext, ccFlags, ccDeps, []string) // Install the built module. installModule(common.AndroidModuleContext, ccFlags) // Return the output file (.o, .a or .so) for use by other modules outputFile() string } type ccDeps struct { staticLibs, sharedLibs, lateStaticLibs, wholeStaticLibs, objFiles, includeDirs []string crtBegin, crtEnd string } type ccFlags struct { globalFlags []string asFlags []string cFlags []string conlyFlags []string cppFlags []string ldFlags []string ldLibs []string includeDirs []string nocrt bool toolchain toolchain clang bool extraStaticLibs []string extraSharedLibs []string } // ccBase contains the properties and members used by all C/C++ module types, and implements // the blueprint.Module interface. It expects to be embedded into an outer specialization struct, // and uses a ccModuleType interface to that struct to create the build steps. type ccBase struct { common.AndroidModuleBase module ccModuleType properties ccProperties unused unusedProperties installPath string } func newCCBase(base *ccBase, module ccModuleType, hod common.HostOrDeviceSupported, multilib common.Multilib, props ...interface{}) (blueprint.Module, []interface{}) { base.module = module props = append(props, &base.properties, &base.unused) return common.InitAndroidArchModule(module, hod, multilib, props...) } func (c *ccBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { toolchain := c.findToolchain(ctx) if ctx.Failed() { return } flags := c.flags(ctx, toolchain) if ctx.Failed() { return } flags = c.addStlFlags(ctx, flags) if ctx.Failed() { return } deps, flags := c.ccModuleType().collectDeps(ctx, flags) if ctx.Failed() { return } objFiles := c.compileObjs(ctx, flags, deps) if ctx.Failed() { return } generatedObjFiles := c.compileGeneratedObjs(ctx, flags, deps) if ctx.Failed() { return } objFiles = append(objFiles, generatedObjFiles...) c.ccModuleType().compileModule(ctx, flags, deps, objFiles) if ctx.Failed() { return } c.ccModuleType().installModule(ctx, flags) if ctx.Failed() { return } } func (c *ccBase) ccModuleType() ccModuleType { return c.module } var _ common.AndroidDynamicDepender = (*ccBase)(nil) func (c *ccBase) findToolchain(ctx common.AndroidModuleContext) toolchain { arch := ctx.Arch() factory := toolchainFactories[arch.HostOrDevice][arch.ArchType] if factory == nil { panic(fmt.Sprintf("Toolchain not found for %s arch %q", arch.HostOrDevice.String(), arch.String())) } return factory(arch.ArchVariant, arch.CpuVariant) } func (c *ccBase) moduleTypeCflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { return nil } func (c *ccBase) moduleTypeLdflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { return nil } func (c *ccBase) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, c.properties.Whole_static_libs...) ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, c.properties.Static_libs...) ctx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, c.properties.Shared_libs...) return nil } // Create a ccFlags struct that collects the compile flags from global values, // per-target values, module type values, and per-module Blueprints properties func (c *ccBase) flags(ctx common.AndroidModuleContext, toolchain toolchain) ccFlags { arch := ctx.Arch() flags := ccFlags{ cFlags: c.properties.Cflags, cppFlags: c.properties.Cppflags, conlyFlags: c.properties.Conlyflags, ldFlags: c.properties.Ldflags, asFlags: c.properties.Asflags, nocrt: c.properties.Nocrt, toolchain: toolchain, clang: c.properties.Clang, } instructionSet := c.properties.Instruction_set instructionSetFlags, err := toolchain.InstructionSetFlags(instructionSet) if err != nil { ctx.ModuleErrorf("%s", err) } // TODO: debug flags.cFlags = append(flags.cFlags, c.properties.Release.Cflags...) if arch.HostOrDevice.Host() { // TODO: allow per-module clang disable for host flags.clang = true } if flags.clang { flags.cFlags = clangFilterUnknownCflags(flags.cFlags) flags.cFlags = append(flags.cFlags, c.properties.Clang_cflags...) flags.asFlags = append(flags.asFlags, c.properties.Clang_asflags...) flags.cppFlags = clangFilterUnknownCflags(flags.cppFlags) flags.conlyFlags = clangFilterUnknownCflags(flags.conlyFlags) flags.ldFlags = clangFilterUnknownCflags(flags.ldFlags) flags.cFlags = append(flags.cFlags, "${clangExtraCflags}") flags.conlyFlags = append(flags.conlyFlags, "${clangExtraConlyflags}") if arch.HostOrDevice.Device() { flags.cFlags = append(flags.cFlags, "${clangExtraTargetCflags}") } target := "-target " + toolchain.ClangTriple() gccPrefix := "-B" + filepath.Join(toolchain.GccRoot(), toolchain.GccTriple(), "bin") flags.cFlags = append(flags.cFlags, target, gccPrefix) flags.asFlags = append(flags.asFlags, target, gccPrefix) flags.ldFlags = append(flags.ldFlags, target, gccPrefix) if arch.HostOrDevice.Host() { gccToolchain := "--gcc-toolchain=" + toolchain.GccRoot() sysroot := "--sysroot=" + filepath.Join(toolchain.GccRoot(), "sysroot") // TODO: also need more -B, -L flags to make host builds hermetic flags.cFlags = append(flags.cFlags, gccToolchain, sysroot) flags.asFlags = append(flags.asFlags, gccToolchain, sysroot) flags.ldFlags = append(flags.ldFlags, gccToolchain, sysroot) } } flags.includeDirs = pathtools.PrefixPaths(c.properties.Include_dirs, ctx.Config().(Config).SrcDir()) localIncludeDirs := pathtools.PrefixPaths(c.properties.Local_include_dirs, common.ModuleSrcDir(ctx)) flags.includeDirs = append(flags.includeDirs, localIncludeDirs...) if !c.properties.No_default_compiler_flags { flags.includeDirs = append(flags.includeDirs, []string{ common.ModuleSrcDir(ctx), common.ModuleOutDir(ctx), common.ModuleGenDir(ctx), }...) if c.properties.Sdk_version == "" { flags.includeDirs = append(flags.includeDirs, "${SrcDir}/libnativehelper/include/nativehelper") } if arch.HostOrDevice.Device() && !c.properties.Allow_undefined_symbols { flags.ldFlags = append(flags.ldFlags, "-Wl,--no-undefined") } if flags.clang { flags.cppFlags = append(flags.cppFlags, "${commonClangGlobalCppflags}") flags.globalFlags = []string{ "${commonGlobalIncludes}", toolchain.IncludeFlags(), instructionSetFlags, toolchain.ClangCflags(), "${commonClangGlobalCflags}", fmt.Sprintf("${%sClangGlobalCflags}", arch.HostOrDevice), } } else { flags.cppFlags = append(flags.cppFlags, "${commonGlobalCppflags}") flags.globalFlags = []string{ "${commonGlobalIncludes}", toolchain.IncludeFlags(), instructionSetFlags, toolchain.Cflags(), "${commonGlobalCflags}", fmt.Sprintf("${%sGlobalCflags}", arch.HostOrDevice), } } if arch.HostOrDevice.Host() { flags.ldFlags = append(flags.ldFlags, c.properties.Host_ldlibs...) } if arch.HostOrDevice.Device() { if c.properties.Rtti { flags.cppFlags = append(flags.cppFlags, "-frtti") } else { flags.cppFlags = append(flags.cppFlags, "-fno-rtti") } } flags.asFlags = append(flags.asFlags, "-D__ASSEMBLY__") if flags.clang { flags.cppFlags = append(flags.cppFlags, toolchain.ClangCppflags()) flags.ldFlags = append(flags.ldFlags, toolchain.ClangLdflags()) } else { flags.cppFlags = append(flags.cppFlags, toolchain.Cppflags()) flags.ldFlags = append(flags.ldFlags, toolchain.Ldflags()) } } flags.cFlags = append(flags.cFlags, c.ccModuleType().moduleTypeCflags(ctx, toolchain)...) flags.ldFlags = append(flags.ldFlags, c.ccModuleType().moduleTypeLdflags(ctx, toolchain)...) // Optimization to reduce size of build.ninja // Replace the long list of flags for each file with a module-local variable ctx.Variable(pctx, "cflags", strings.Join(flags.cFlags, " ")) ctx.Variable(pctx, "cppflags", strings.Join(flags.cppFlags, " ")) ctx.Variable(pctx, "asflags", strings.Join(flags.asFlags, " ")) flags.cFlags = []string{"$cflags"} flags.cppFlags = []string{"$cppflags"} flags.asFlags = []string{"$asflags"} return flags } // Modify ccFlags structs with STL library info func (c *ccBase) addStlFlags(ctx common.AndroidModuleContext, flags ccFlags) ccFlags { if !c.properties.No_default_compiler_flags { arch := ctx.Arch() stl := "libc++" // TODO: mingw needs libstdc++ if c.properties.Stl != "" { stl = c.properties.Stl } stlStatic := false if strings.HasSuffix(stl, "_static") { stlStatic = true } switch stl { case "libc++", "libc++_static": flags.cFlags = append(flags.cFlags, "-D_USING_LIBCXX") flags.includeDirs = append(flags.includeDirs, "${SrcDir}/external/libcxx/include") if arch.HostOrDevice.Host() { flags.cppFlags = append(flags.cppFlags, "-nostdinc++") flags.ldFlags = append(flags.ldFlags, "-nodefaultlibs") flags.ldLibs = append(flags.ldLibs, "-lc", "-lm", "-lpthread") } if stlStatic { flags.extraStaticLibs = append(flags.extraStaticLibs, "libc++_static") } else { flags.extraSharedLibs = append(flags.extraSharedLibs, "libc++") } case "stlport", "stlport_static": if arch.HostOrDevice.Device() { flags.includeDirs = append(flags.includeDirs, "${SrcDir}/external/stlport/stlport", "${SrcDir}/bionic/libstdc++/include", "${SrcDir}/bionic") if stlStatic { flags.extraStaticLibs = append(flags.extraStaticLibs, "libstdc++", "libstlport_static") } else { flags.extraSharedLibs = append(flags.extraSharedLibs, "libstdc++", "libstlport") } } case "ndk": panic("TODO") case "libstdc++": // Using bionic's basic libstdc++. Not actually an STL. Only around until the // tree is in good enough shape to not need it. // Host builds will use GNU libstdc++. if arch.HostOrDevice.Device() { flags.includeDirs = append(flags.includeDirs, "${SrcDir}/bionic/libstdc++/include") flags.extraSharedLibs = append(flags.extraSharedLibs, "libstdc++") } case "none": if arch.HostOrDevice.Host() { flags.cppFlags = append(flags.cppFlags, "-nostdinc++") flags.ldFlags = append(flags.ldFlags, "-nodefaultlibs") flags.ldLibs = append(flags.ldLibs, "-lc", "-lm") } default: ctx.ModuleErrorf("stl: %q is not a supported STL", stl) } } return flags } // Compile a list of source files into objects a specified subdirectory func (c *ccBase) customCompileObjs(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, subdir string, srcFiles []string) []string { srcFiles = pathtools.PrefixPaths(srcFiles, common.ModuleSrcDir(ctx)) srcFiles = common.ExpandGlobs(ctx, srcFiles) return TransformSourceToObj(ctx, subdir, srcFiles, ccFlagsToBuilderFlags(flags)) } // Compile files listed in c.properties.Srcs into objects func (c *ccBase) compileObjs(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps) []string { if c.properties.SkipCompileObjs { return nil } return c.customCompileObjs(ctx, flags, deps, "", c.properties.Srcs) } // Compile generated source files from dependencies func (c *ccBase) compileGeneratedObjs(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps) []string { var srcs []string if c.properties.SkipCompileObjs { return nil } ctx.VisitDirectDeps(func(module blueprint.Module) { if gen, ok := module.(genrule.SourceFileGenerator); ok { srcs = append(srcs, gen.GeneratedSourceFiles()...) } }) if len(srcs) == 0 { return nil } return TransformSourceToObj(ctx, "", srcs, ccFlagsToBuilderFlags(flags)) } func (c *ccBase) outputFile() string { return "" } func (c *ccBase) collectDepsFromList(ctx common.AndroidModuleContext, names []string) (modules []common.AndroidModule, outputFiles []string, exportedIncludeDirs []string) { for _, n := range names { found := false ctx.VisitDirectDeps(func(m blueprint.Module) { otherName := ctx.OtherModuleName(m) if otherName != n { return } if a, ok := m.(ccModuleType); ok { if a.Disabled() { // If a cc_library host+device module depends on a library that exists as both // cc_library_shared and cc_library_host_shared, it will end up with two // dependencies with the same name, one of which is marked disabled for each // of host and device. Ignore the disabled one. return } if a.HostOrDevice() != ctx.Arch().HostOrDevice { ctx.ModuleErrorf("host/device mismatch between %q and %q", ctx.ModuleName(), otherName) return } if outputFile := a.outputFile(); outputFile != "" { if found { ctx.ModuleErrorf("multiple modules satisified dependency on %q", otherName) return } outputFiles = append(outputFiles, outputFile) modules = append(modules, a) if i, ok := a.(ccExportedIncludeDirsProducer); ok { exportedIncludeDirs = append(exportedIncludeDirs, i.exportedIncludeDirs()...) } found = true } else { ctx.ModuleErrorf("module %q missing output file", otherName) return } } else { ctx.ModuleErrorf("module %q not an android module", otherName) return } }) if !found { ctx.ModuleErrorf("unsatisified dependency on %q", n) } } return modules, outputFiles, exportedIncludeDirs } func (c *ccBase) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { var deps ccDeps var newIncludeDirs []string wholeStaticLibNames := c.properties.Whole_static_libs _, deps.wholeStaticLibs, newIncludeDirs = c.collectDepsFromList(ctx, wholeStaticLibNames) deps.includeDirs = append(deps.includeDirs, newIncludeDirs...) staticLibNames := c.properties.Static_libs staticLibNames = append(staticLibNames, flags.extraStaticLibs...) _, deps.staticLibs, newIncludeDirs = c.collectDepsFromList(ctx, staticLibNames) deps.includeDirs = append(deps.includeDirs, newIncludeDirs...) return deps, flags } // ccDynamic contains the properties and members used by shared libraries and dynamic executables type ccDynamic struct { ccBase } func newCCDynamic(dynamic *ccDynamic, module ccModuleType, hod common.HostOrDeviceSupported, multilib common.Multilib, props ...interface{}) (blueprint.Module, []interface{}) { dynamic.properties.System_shared_libs = []string{defaultSystemSharedLibraries} return newCCBase(&dynamic.ccBase, module, hod, multilib, props...) } const defaultSystemSharedLibraries = "__default__" func (c *ccDynamic) systemSharedLibs() []string { if len(c.properties.System_shared_libs) == 1 && c.properties.System_shared_libs[0] == defaultSystemSharedLibraries { if c.HostOrDevice().Host() { return []string{} } else { return []string{"libc", "libm"} } } return c.properties.System_shared_libs } var ( stlSharedLibs = []string{"libc++", "libstlport", "libstdc++"} stlSharedHostLibs = []string{"libc++"} stlStaticLibs = []string{"libc++_static", "libstlport_static", "libstdc++"} stlStaticHostLibs = []string{"libc++_static"} ) func (c *ccDynamic) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { deps := c.ccBase.AndroidDynamicDependencies(ctx) if c.HostOrDevice().Device() { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, c.systemSharedLibs()...) ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, "libcompiler_rt-extras", "libgcov", "libatomic", "libgcc") if c.properties.Stl != "none" { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, stlSharedLibs...) ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, stlStaticLibs...) } } else { if c.properties.Stl != "none" { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, stlSharedHostLibs...) ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, stlStaticHostLibs...) } } return deps } func (c *ccDynamic) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { var newIncludeDirs []string deps, flags := c.ccBase.collectDeps(ctx, flags) systemSharedLibs := c.systemSharedLibs() sharedLibNames := make([]string, 0, len(c.properties.Shared_libs)+len(systemSharedLibs)+ len(flags.extraSharedLibs)) sharedLibNames = append(sharedLibNames, c.properties.Shared_libs...) sharedLibNames = append(sharedLibNames, systemSharedLibs...) sharedLibNames = append(sharedLibNames, flags.extraSharedLibs...) _, deps.sharedLibs, newIncludeDirs = c.collectDepsFromList(ctx, sharedLibNames) deps.includeDirs = append(deps.includeDirs, newIncludeDirs...) if ctx.Arch().HostOrDevice.Device() { var staticLibs []string staticLibNames := []string{"libcompiler_rt-extras"} _, staticLibs, newIncludeDirs = c.collectDepsFromList(ctx, staticLibNames) deps.staticLibs = append(deps.staticLibs, staticLibs...) deps.includeDirs = append(deps.includeDirs, newIncludeDirs...) // libgcc and libatomic have to be last on the command line staticLibNames = []string{"libgcov", "libatomic", "libgcc"} _, staticLibs, newIncludeDirs = c.collectDepsFromList(ctx, staticLibNames) deps.lateStaticLibs = append(deps.lateStaticLibs, staticLibs...) deps.includeDirs = append(deps.includeDirs, newIncludeDirs...) } ctx.VisitDirectDeps(func(m blueprint.Module) { if obj, ok := m.(*ccObject); ok { otherName := ctx.OtherModuleName(m) if strings.HasPrefix(otherName, "crtbegin") { if !c.properties.Nocrt { deps.crtBegin = obj.outputFile() } } else if strings.HasPrefix(otherName, "crtend") { if !c.properties.Nocrt { deps.crtEnd = obj.outputFile() } } else { ctx.ModuleErrorf("object module type only support for crtbegin and crtend, found %q", ctx.OtherModuleName(m)) } } }) flags.includeDirs = append(flags.includeDirs, deps.includeDirs...) return deps, flags } type ccExportedIncludeDirsProducer interface { exportedIncludeDirs() []string } // // Combined static+shared libraries // type ccLibrary struct { ccDynamic primary *ccLibrary primaryObjFiles []string objFiles []string exportIncludeDirs []string out string libraryProperties struct { BuildStatic bool `blueprint:"mutated"` BuildShared bool `blueprint:"mutated"` IsShared bool `blueprint:"mutated"` IsStatic bool `blueprint:"mutated"` Static struct { Srcs []string `android:"arch_variant"` Cflags []string `android:"arch_variant"` } `android:"arch_variant"` Shared struct { Srcs []string `android:"arch_variant"` Cflags []string `android:"arch_variant"` } `android:"arch_variant"` } } func newCCLibrary(library *ccLibrary, hod common.HostOrDeviceSupported) (blueprint.Module, []interface{}) { return newCCDynamic(&library.ccDynamic, library, hod, common.MultilibBoth, &library.libraryProperties) } func NewCCLibrary() (blueprint.Module, []interface{}) { module := &ccLibrary{} module.libraryProperties.BuildShared = true module.libraryProperties.BuildStatic = true return newCCLibrary(module, common.HostAndDeviceSupported) } func (c *ccLibrary) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { if c.libraryProperties.IsShared { deps := c.ccDynamic.AndroidDynamicDependencies(ctx) if c.HostOrDevice().Device() { deps = append(deps, "crtbegin_so", "crtend_so") } return deps } else { return c.ccBase.AndroidDynamicDependencies(ctx) } } func (c *ccLibrary) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { if c.libraryProperties.IsStatic { deps, flags := c.ccBase.collectDeps(ctx, flags) wholeStaticLibNames := c.properties.Whole_static_libs wholeStaticLibs, _, _ := c.collectDepsFromList(ctx, wholeStaticLibNames) for _, m := range wholeStaticLibs { if staticLib, ok := m.(*ccLibrary); ok && staticLib.libraryProperties.IsStatic { deps.objFiles = append(deps.objFiles, staticLib.allObjFiles()...) } else { ctx.ModuleErrorf("module %q not a static library", ctx.OtherModuleName(m)) } } return deps, flags } else if c.libraryProperties.IsShared { return c.ccDynamic.collectDeps(ctx, flags) } else { panic("Not shared or static") } } func (c *ccLibrary) outputFile() string { return c.out } func (c *ccLibrary) allObjFiles() []string { return c.objFiles } func (c *ccLibrary) exportedIncludeDirs() []string { return c.exportIncludeDirs } func (c *ccLibrary) moduleTypeCflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { return []string{"-fPIC"} } func (c *ccLibrary) moduleTypeLdflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { if c.libraryProperties.IsShared { libName := ctx.ModuleName() // GCC for Android assumes that -shared means -Bsymbolic, use -Wl,-shared instead sharedFlag := "-Wl,-shared" if c.properties.Clang || ctx.Arch().HostOrDevice.Host() { sharedFlag = "-shared" } if ctx.Arch().HostOrDevice.Device() { return []string{ "-nostdlib", "-Wl,--gc-sections", sharedFlag, "-Wl,-soname," + libName + sharedLibraryExtension, } } else { return []string{ "-Wl,--gc-sections", sharedFlag, "-Wl,-soname," + libName + sharedLibraryExtension, } } } else { return nil } } func (c *ccLibrary) compileStaticLibrary(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { staticFlags := flags staticFlags.cFlags = append(staticFlags.cFlags, c.libraryProperties.Static.Cflags...) objFilesStatic := c.customCompileObjs(ctx, staticFlags, deps, common.DeviceStaticLibrary, c.libraryProperties.Static.Srcs) objFiles = append(objFiles, objFilesStatic...) var includeDirs []string wholeStaticLibNames := c.properties.Whole_static_libs wholeStaticLibs, _, newIncludeDirs := c.collectDepsFromList(ctx, wholeStaticLibNames) includeDirs = append(includeDirs, newIncludeDirs...) for _, m := range wholeStaticLibs { if staticLib, ok := m.(*ccLibrary); ok && staticLib.libraryProperties.IsStatic { objFiles = append(objFiles, staticLib.allObjFiles()...) } else { ctx.ModuleErrorf("module %q not a static library", ctx.OtherModuleName(m)) } } staticLibNames := c.properties.Static_libs _, _, newIncludeDirs = c.collectDepsFromList(ctx, staticLibNames) includeDirs = append(includeDirs, newIncludeDirs...) ctx.VisitDirectDeps(func(m blueprint.Module) { if obj, ok := m.(*ccObject); ok { otherName := ctx.OtherModuleName(m) if !strings.HasPrefix(otherName, "crtbegin") && !strings.HasPrefix(otherName, "crtend") { objFiles = append(objFiles, obj.outputFile()) } } }) outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+staticLibraryExtension) TransformObjToStaticLib(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile) c.objFiles = objFiles c.out = outputFile c.exportIncludeDirs = pathtools.PrefixPaths(c.properties.Export_include_dirs, common.ModuleSrcDir(ctx)) ctx.CheckbuildFile(outputFile) } func (c *ccLibrary) compileSharedLibrary(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { sharedFlags := flags sharedFlags.cFlags = append(sharedFlags.cFlags, c.libraryProperties.Shared.Cflags...) objFilesShared := c.customCompileObjs(ctx, sharedFlags, deps, common.DeviceSharedLibrary, c.libraryProperties.Shared.Srcs) objFiles = append(objFiles, objFilesShared...) outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+sharedLibraryExtension) TransformObjToDynamicBinary(ctx, objFiles, deps.sharedLibs, deps.staticLibs, deps.lateStaticLibs, deps.wholeStaticLibs, deps.crtBegin, deps.crtEnd, ccFlagsToBuilderFlags(flags), outputFile) c.out = outputFile c.exportIncludeDirs = pathtools.PrefixPaths(c.properties.Export_include_dirs, common.ModuleSrcDir(ctx)) } func (c *ccLibrary) compileModule(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { // Reuse the object files from the matching static library if it exists if c.primary == c { c.primaryObjFiles = objFiles } else { objFiles = append([]string(nil), c.primary.primaryObjFiles...) } if c.libraryProperties.IsStatic { c.compileStaticLibrary(ctx, flags, deps, objFiles) } else { c.compileSharedLibrary(ctx, flags, deps, objFiles) } } func (c *ccLibrary) installStaticLibrary(ctx common.AndroidModuleContext, flags ccFlags) { // Static libraries do not get installed. } func (c *ccLibrary) installSharedLibrary(ctx common.AndroidModuleContext, flags ccFlags) { installDir := "lib" if flags.toolchain.Is64Bit() { installDir = "lib64" } ctx.InstallFile(installDir, c.out) } func (c *ccLibrary) installModule(ctx common.AndroidModuleContext, flags ccFlags) { if c.libraryProperties.IsStatic { c.installStaticLibrary(ctx, flags) } else { c.installSharedLibrary(ctx, flags) } } // // Objects (for crt*.o) // type ccObject struct { ccBase out string } func NewCCObject() (blueprint.Module, []interface{}) { module := &ccObject{} return newCCBase(&module.ccBase, module, common.DeviceSupported, common.MultilibBoth) } func (*ccObject) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { // object files can't have any dynamic dependencies return nil } func (c *ccObject) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { deps, flags := c.ccBase.collectDeps(ctx, flags) ctx.VisitDirectDeps(func(m blueprint.Module) { if obj, ok := m.(*ccObject); ok { deps.objFiles = append(deps.objFiles, obj.outputFile()) } else { ctx.ModuleErrorf("Unknown module type for dependency %q", ctx.OtherModuleName(m)) } }) return deps, flags } func (c *ccObject) compileModule(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { objFiles = append(objFiles, deps.objFiles...) var outputFile string if len(objFiles) == 1 { outputFile = objFiles[0] } else { outputFile = filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+".o") TransformObjsToObj(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile) } c.out = outputFile ctx.CheckbuildFile(outputFile) } func (c *ccObject) installModule(ctx common.AndroidModuleContext, flags ccFlags) { // Object files do not get installed. } func (c *ccObject) outputFile() string { return c.out } // // Executables // type ccBinary struct { ccDynamic out string binaryProperties binaryProperties } type binaryProperties struct { // static_executable: compile executable with -static Static_executable bool // stem: set the name of the output Stem string `android:"arch_variant"` // prefix_symbols: if set, add an extra objcopy --prefix-symbols= step Prefix_symbols string } func (c *ccBinary) getStem(ctx common.AndroidModuleContext) string { if c.binaryProperties.Stem != "" { return c.binaryProperties.Stem } return ctx.ModuleName() } func (c *ccBinary) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { deps := c.ccDynamic.AndroidDynamicDependencies(ctx) if c.HostOrDevice().Device() { if c.binaryProperties.Static_executable { deps = append(deps, "crtbegin_static", "crtend_android") } else { deps = append(deps, "crtbegin_dynamic", "crtend_android") } } return deps } func NewCCBinary() (blueprint.Module, []interface{}) { module := &ccBinary{} return newCCDynamic(&module.ccDynamic, module, common.HostAndDeviceSupported, common.MultilibFirst, &module.binaryProperties) } func (c *ccBinary) moduleTypeCflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { return []string{"-fpie"} } func (c *ccBinary) moduleTypeLdflags(ctx common.AndroidModuleContext, toolchain toolchain) []string { if ctx.Arch().HostOrDevice.Device() { linker := "/system/bin/linker" if toolchain.Is64Bit() { linker = "/system/bin/linker64" } return []string{ "-nostdlib", "-Bdynamic", fmt.Sprintf("-Wl,-dynamic-linker,%s", linker), "-Wl,--gc-sections", "-Wl,-z,nocopyreloc", } } return nil } func (c *ccBinary) compileModule(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { if !c.binaryProperties.Static_executable && inList("libc", c.properties.Static_libs) { ctx.ModuleErrorf("statically linking libc to dynamic executable, please remove libc\n" + "from static libs or set static_executable: true") } outputFile := filepath.Join(common.ModuleOutDir(ctx), c.getStem(ctx)) c.out = outputFile TransformObjToDynamicBinary(ctx, objFiles, deps.sharedLibs, deps.staticLibs, deps.lateStaticLibs, deps.wholeStaticLibs, deps.crtBegin, deps.crtEnd, ccFlagsToBuilderFlags(flags), outputFile) } func (c *ccBinary) installModule(ctx common.AndroidModuleContext, flags ccFlags) { ctx.InstallFile("bin", c.out) } type ccTest struct { ccBinary } var ( gtestLibs = []string{"libgtest", "libgtest_main"} ) func (c *ccTest) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { deps, flags := c.ccBinary.collectDeps(ctx, flags) flags.cFlags = append(flags.cFlags, "-DGTEST_HAS_STD_STRING") if c.HostOrDevice().Host() { flags.cFlags = append(flags.cFlags, "-O0", "-g") flags.ldLibs = append(flags.ldLibs, "-lpthread") } // TODO(danalbert): Make gtest export its dependencies. flags.includeDirs = append(flags.includeDirs, filepath.Join(ctx.Config().(Config).SrcDir(), "external/gtest/include")) _, staticLibs, _ := c.collectDepsFromList(ctx, gtestLibs) deps.staticLibs = append(deps.staticLibs, staticLibs...) return deps, flags } func (c *ccTest) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, gtestLibs...) deps := c.ccBinary.AndroidDynamicDependencies(ctx) return append(deps, gtestLibs...) } func (c *ccTest) installModule(ctx common.AndroidModuleContext, flags ccFlags) { if c.HostOrDevice().Device() { ctx.InstallFile("../data/nativetest/"+ctx.ModuleName(), c.out) } else { c.ccBinary.installModule(ctx, flags) } } func NewCCTest() (blueprint.Module, []interface{}) { module := &ccTest{} return newCCDynamic(&module.ccDynamic, module, common.HostAndDeviceSupported, common.MultilibFirst, &module.binaryProperties) } // // Static library // func NewCCLibraryStatic() (blueprint.Module, []interface{}) { module := &ccLibrary{} module.libraryProperties.BuildStatic = true return newCCLibrary(module, common.HostAndDeviceSupported) } // // Shared libraries // func NewCCLibraryShared() (blueprint.Module, []interface{}) { module := &ccLibrary{} module.libraryProperties.BuildShared = true return newCCLibrary(module, common.HostAndDeviceSupported) } // // Host static library // func NewCCLibraryHostStatic() (blueprint.Module, []interface{}) { module := &ccLibrary{} module.libraryProperties.BuildStatic = true return newCCLibrary(module, common.HostSupported) } // // Host Shared libraries // func NewCCLibraryHostShared() (blueprint.Module, []interface{}) { module := &ccLibrary{} module.libraryProperties.BuildShared = true return newCCLibrary(module, common.HostSupported) } // // Host Binaries // func NewCCBinaryHost() (blueprint.Module, []interface{}) { module := &ccBinary{} return newCCDynamic(&module.ccDynamic, module, common.HostSupported, common.MultilibFirst) } // // Device libraries shipped with gcc // type toolchainLibrary struct { ccLibrary } func (*toolchainLibrary) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string { // toolchain libraries can't have any dependencies return nil } func (*toolchainLibrary) collectDeps(ctx common.AndroidModuleContext, flags ccFlags) (ccDeps, ccFlags) { // toolchain libraries can't have any dependencies return ccDeps{}, flags } func NewToolchainLibrary() (blueprint.Module, []interface{}) { module := &toolchainLibrary{} return newCCBase(&module.ccBase, module, common.DeviceSupported, common.MultilibBoth) } func (c *toolchainLibrary) compileModule(ctx common.AndroidModuleContext, flags ccFlags, deps ccDeps, objFiles []string) { libName := ctx.ModuleName() + staticLibraryExtension outputFile := filepath.Join(common.ModuleOutDir(ctx), libName) CopyGccLib(ctx, libName, ccFlagsToBuilderFlags(flags), outputFile) c.out = outputFile ctx.CheckbuildFile(outputFile) } func (c *toolchainLibrary) installModule(ctx common.AndroidModuleContext, flags ccFlags) { // Toolchain libraries do not get installed. } func LinkageMutator(mctx blueprint.EarlyMutatorContext) { if c, ok := mctx.Module().(*ccLibrary); ok { var modules []blueprint.Module if c.libraryProperties.BuildStatic && c.libraryProperties.BuildShared { modules = mctx.CreateLocalVariations("static", "shared") modules[0].(*ccLibrary).libraryProperties.IsStatic = true modules[1].(*ccLibrary).libraryProperties.IsShared = true } else if c.libraryProperties.BuildStatic { modules = mctx.CreateLocalVariations("static") modules[0].(*ccLibrary).libraryProperties.IsStatic = true } else if c.libraryProperties.BuildShared { modules = mctx.CreateLocalVariations("shared") modules[0].(*ccLibrary).libraryProperties.IsShared = true } else { panic("ccLibrary not static or shared") } primary := modules[0].(*ccLibrary) for _, m := range modules { m.(*ccLibrary).primary = primary if m != primary { m.(*ccLibrary).properties.SkipCompileObjs = true } } } else if _, ok := mctx.Module().(*toolchainLibrary); ok { mctx.CreateLocalVariations("static") } }