Home | History | Annotate | Download | only in cc
      1 // Copyright 2016 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package cc
     16 
     17 import (
     18 	"path/filepath"
     19 
     20 	"github.com/google/blueprint"
     21 	"github.com/google/blueprint/proptools"
     22 
     23 	"android/soong/android"
     24 )
     25 
     26 type BinaryLinkerProperties struct {
     27 	// compile executable with -static
     28 	Static_executable *bool `android:"arch_variant"`
     29 
     30 	// set the name of the output
     31 	Stem string `android:"arch_variant"`
     32 
     33 	// append to the name of the output
     34 	Suffix string `android:"arch_variant"`
     35 
     36 	// if set, add an extra objcopy --prefix-symbols= step
     37 	Prefix_symbols string
     38 
     39 	// if set, install a symlink to the preferred architecture
     40 	Symlink_preferred_arch bool
     41 
     42 	// install symlinks to the binary.  Symlink names will have the suffix and the binary
     43 	// extension (if any) appended
     44 	Symlinks []string `android:"arch_variant"`
     45 
     46 	// do not pass -pie
     47 	No_pie *bool `android:"arch_variant"`
     48 
     49 	DynamicLinker string `blueprint:"mutated"`
     50 }
     51 
     52 func init() {
     53 	android.RegisterModuleType("cc_binary", binaryFactory)
     54 	android.RegisterModuleType("cc_binary_host", binaryHostFactory)
     55 }
     56 
     57 // Module factory for binaries
     58 func binaryFactory() (blueprint.Module, []interface{}) {
     59 	module, _ := NewBinary(android.HostAndDeviceSupported)
     60 	return module.Init()
     61 }
     62 
     63 // Module factory for host binaries
     64 func binaryHostFactory() (blueprint.Module, []interface{}) {
     65 	module, _ := NewBinary(android.HostSupported)
     66 	return module.Init()
     67 }
     68 
     69 //
     70 // Executables
     71 //
     72 
     73 type binaryDecorator struct {
     74 	*baseLinker
     75 	*baseInstaller
     76 	stripper
     77 
     78 	Properties BinaryLinkerProperties
     79 
     80 	toolPath android.OptionalPath
     81 
     82 	// Names of symlinks to be installed for use in LOCAL_MODULE_SYMLINKS
     83 	symlinks []string
     84 
     85 	// Output archive of gcno coverage information
     86 	coverageOutputFile android.OptionalPath
     87 }
     88 
     89 var _ linker = (*binaryDecorator)(nil)
     90 
     91 func (binary *binaryDecorator) linkerProps() []interface{} {
     92 	return append(binary.baseLinker.linkerProps(),
     93 		&binary.Properties,
     94 		&binary.stripper.StripProperties)
     95 
     96 }
     97 
     98 func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
     99 	stem := ctx.baseModuleName()
    100 	if binary.Properties.Stem != "" {
    101 		stem = binary.Properties.Stem
    102 	}
    103 
    104 	return stem + binary.Properties.Suffix
    105 }
    106 
    107 func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
    108 	deps = binary.baseLinker.linkerDeps(ctx, deps)
    109 	if ctx.toolchain().Bionic() {
    110 		if !Bool(binary.baseLinker.Properties.Nocrt) {
    111 			if !ctx.sdk() {
    112 				if binary.static() {
    113 					deps.CrtBegin = "crtbegin_static"
    114 				} else {
    115 					deps.CrtBegin = "crtbegin_dynamic"
    116 				}
    117 				deps.CrtEnd = "crtend_android"
    118 			} else {
    119 				// TODO(danalbert): Add generation of crt objects.
    120 				// For `sdk_version: "current"`, we don't actually have a
    121 				// freshly generated set of CRT objects. Use the last stable
    122 				// version.
    123 				version := ctx.sdkVersion()
    124 				if version == "current" {
    125 					version = ctx.AConfig().PlatformSdkVersion()
    126 				}
    127 
    128 				if binary.static() {
    129 					deps.CrtBegin = "ndk_crtbegin_static." + version
    130 				} else {
    131 					if binary.static() {
    132 						deps.CrtBegin = "ndk_crtbegin_static." + version
    133 					} else {
    134 						deps.CrtBegin = "ndk_crtbegin_dynamic." + version
    135 					}
    136 					deps.CrtEnd = "ndk_crtend_android." + version
    137 				}
    138 			}
    139 		}
    140 
    141 		if binary.static() {
    142 			if ctx.selectedStl() == "libc++_static" {
    143 				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
    144 			}
    145 			// static libraries libcompiler_rt, libc and libc_nomalloc need to be linked with
    146 			// --start-group/--end-group along with libgcc.  If they are in deps.StaticLibs,
    147 			// move them to the beginning of deps.LateStaticLibs
    148 			var groupLibs []string
    149 			deps.StaticLibs, groupLibs = filterList(deps.StaticLibs,
    150 				[]string{"libc", "libc_nomalloc", "libcompiler_rt"})
    151 			deps.LateStaticLibs = append(groupLibs, deps.LateStaticLibs...)
    152 		}
    153 	}
    154 
    155 	if !binary.static() && inList("libc", deps.StaticLibs) {
    156 		ctx.ModuleErrorf("statically linking libc to dynamic executable, please remove libc\n" +
    157 			"from static libs or set static_executable: true")
    158 	}
    159 	return deps
    160 }
    161 
    162 func (binary *binaryDecorator) isDependencyRoot() bool {
    163 	return true
    164 }
    165 
    166 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
    167 	module := newModule(hod, android.MultilibFirst)
    168 	binary := &binaryDecorator{
    169 		baseLinker:    NewBaseLinker(),
    170 		baseInstaller: NewBaseInstaller("bin", "", InstallInSystem),
    171 	}
    172 	module.compiler = NewBaseCompiler()
    173 	module.linker = binary
    174 	module.installer = binary
    175 	return module, binary
    176 }
    177 
    178 func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) {
    179 	binary.baseLinker.linkerInit(ctx)
    180 
    181 	if !ctx.toolchain().Bionic() {
    182 		if ctx.Os() == android.Linux {
    183 			if binary.Properties.Static_executable == nil && Bool(ctx.AConfig().ProductVariables.HostStaticBinaries) {
    184 				binary.Properties.Static_executable = proptools.BoolPtr(true)
    185 			}
    186 		} else {
    187 			// Static executables are not supported on Darwin or Windows
    188 			binary.Properties.Static_executable = nil
    189 		}
    190 	}
    191 }
    192 
    193 func (binary *binaryDecorator) static() bool {
    194 	return Bool(binary.Properties.Static_executable)
    195 }
    196 
    197 func (binary *binaryDecorator) staticBinary() bool {
    198 	return binary.static()
    199 }
    200 
    201 func (binary *binaryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
    202 	flags = binary.baseLinker.linkerFlags(ctx, flags)
    203 
    204 	if ctx.Host() && !binary.static() {
    205 		if !ctx.AConfig().IsEnvTrue("DISABLE_HOST_PIE") {
    206 			flags.LdFlags = append(flags.LdFlags, "-pie")
    207 			if ctx.Os() == android.Windows {
    208 				flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup")
    209 			}
    210 		}
    211 	}
    212 
    213 	// MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because
    214 	// all code is position independent, and then those warnings get promoted to
    215 	// errors.
    216 	if ctx.Os() != android.Windows {
    217 		flags.CFlags = append(flags.CFlags, "-fpie")
    218 	}
    219 
    220 	if ctx.toolchain().Bionic() {
    221 		if binary.static() {
    222 			// Clang driver needs -static to create static executable.
    223 			// However, bionic/linker uses -shared to overwrite.
    224 			// Linker for x86 targets does not allow coexistance of -static and -shared,
    225 			// so we add -static only if -shared is not used.
    226 			if !inList("-shared", flags.LdFlags) {
    227 				flags.LdFlags = append(flags.LdFlags, "-static")
    228 			}
    229 
    230 			flags.LdFlags = append(flags.LdFlags,
    231 				"-nostdlib",
    232 				"-Bstatic",
    233 				"-Wl,--gc-sections",
    234 			)
    235 
    236 		} else {
    237 			if flags.DynamicLinker == "" {
    238 				if binary.Properties.DynamicLinker != "" {
    239 					flags.DynamicLinker = binary.Properties.DynamicLinker
    240 				} else {
    241 					switch ctx.Os() {
    242 					case android.Android:
    243 						flags.DynamicLinker = "/system/bin/linker"
    244 					case android.LinuxBionic:
    245 						// The linux kernel expects the linker to be an
    246 						// absolute path
    247 						path := android.PathForOutput(ctx,
    248 							"host", "linux_bionic-x86", "bin", "linker")
    249 						if p, err := filepath.Abs(path.String()); err == nil {
    250 							flags.DynamicLinker = p
    251 						} else {
    252 							ctx.ModuleErrorf("can't find path to dynamic linker: %q", err)
    253 						}
    254 					default:
    255 						ctx.ModuleErrorf("unknown dynamic linker")
    256 					}
    257 					if flags.Toolchain.Is64Bit() {
    258 						flags.DynamicLinker += "64"
    259 					}
    260 				}
    261 			}
    262 
    263 			flags.LdFlags = append(flags.LdFlags,
    264 				"-pie",
    265 				"-nostdlib",
    266 				"-Bdynamic",
    267 				"-Wl,--gc-sections",
    268 				"-Wl,-z,nocopyreloc",
    269 			)
    270 		}
    271 	} else {
    272 		if binary.static() {
    273 			flags.LdFlags = append(flags.LdFlags, "-static")
    274 		}
    275 		if ctx.Darwin() {
    276 			flags.LdFlags = append(flags.LdFlags, "-Wl,-headerpad_max_install_names")
    277 		}
    278 	}
    279 
    280 	return flags
    281 }
    282 
    283 func (binary *binaryDecorator) link(ctx ModuleContext,
    284 	flags Flags, deps PathDeps, objs Objects) android.Path {
    285 
    286 	fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
    287 	outputFile := android.PathForModuleOut(ctx, fileName)
    288 	ret := outputFile
    289 
    290 	var linkerDeps android.Paths
    291 
    292 	sharedLibs := deps.SharedLibs
    293 	sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
    294 
    295 	if flags.DynamicLinker != "" {
    296 		flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
    297 	}
    298 
    299 	builderFlags := flagsToBuilderFlags(flags)
    300 
    301 	if binary.stripper.needsStrip(ctx) {
    302 		strippedOutputFile := outputFile
    303 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
    304 		binary.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
    305 	}
    306 
    307 	if binary.Properties.Prefix_symbols != "" {
    308 		afterPrefixSymbols := outputFile
    309 		outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName)
    310 		TransformBinaryPrefixSymbols(ctx, binary.Properties.Prefix_symbols, outputFile,
    311 			flagsToBuilderFlags(flags), afterPrefixSymbols)
    312 	}
    313 
    314 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
    315 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
    316 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
    317 
    318 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
    319 		deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
    320 		builderFlags, outputFile)
    321 
    322 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
    323 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
    324 	binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx))
    325 
    326 	return ret
    327 }
    328 
    329 func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
    330 	binary.baseInstaller.install(ctx, file)
    331 	for _, symlink := range binary.Properties.Symlinks {
    332 		binary.symlinks = append(binary.symlinks,
    333 			symlink+binary.Properties.Suffix+ctx.toolchain().ExecutableSuffix())
    334 	}
    335 
    336 	if binary.Properties.Symlink_preferred_arch {
    337 		if binary.Properties.Stem == "" && binary.Properties.Suffix == "" {
    338 			ctx.PropertyErrorf("symlink_preferred_arch", "must also specify stem or suffix")
    339 		}
    340 		if ctx.TargetPrimary() {
    341 			binary.symlinks = append(binary.symlinks, ctx.baseModuleName())
    342 		}
    343 	}
    344 
    345 	for _, symlink := range binary.symlinks {
    346 		ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
    347 	}
    348 
    349 	if ctx.Os().Class == android.Host {
    350 		binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
    351 	}
    352 }
    353 
    354 func (binary *binaryDecorator) hostToolPath() android.OptionalPath {
    355 	return binary.toolPath
    356 }
    357