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 15package cc 16 17import ( 18 "android/soong/android" 19 "fmt" 20 "strconv" 21) 22 23func getNdkStlFamily(m LinkableInterface) string { 24 family, _ := getNdkStlFamilyAndLinkType(m) 25 return family 26} 27 28func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) { 29 stl := m.SelectedStl() 30 switch stl { 31 case "ndk_libc++_shared": 32 return "libc++", "shared" 33 case "ndk_libc++_static": 34 return "libc++", "static" 35 case "ndk_system": 36 return "system", "shared" 37 case "": 38 return "none", "none" 39 default: 40 panic(fmt.Errorf("stl: %q is not a valid STL", stl)) 41 } 42} 43 44type StlProperties struct { 45 // Select the STL library to use. Possible values are "libc++", 46 // "libc++_static", "libstdc++", or "none". Leave blank to select the 47 // default. 48 Stl *string `android:"arch_variant"` 49 50 SelectedStl string `blueprint:"mutated"` 51} 52 53type stl struct { 54 Properties StlProperties 55} 56 57func (stl *stl) props() []interface{} { 58 return []interface{}{&stl.Properties} 59} 60 61func (stl *stl) begin(ctx BaseModuleContext) { 62 stl.Properties.SelectedStl = func() string { 63 s := "" 64 if stl.Properties.Stl != nil { 65 s = *stl.Properties.Stl 66 } 67 if ctx.useSdk() && ctx.Device() { 68 switch s { 69 case "", "system": 70 return "ndk_system" 71 case "c++_shared", "c++_static": 72 return "ndk_lib" + s 73 case "libc++": 74 return "ndk_libc++_shared" 75 case "libc++_static": 76 return "ndk_libc++_static" 77 case "none": 78 return "" 79 default: 80 ctx.ModuleErrorf("stl: %q is not a supported STL with sdk_version set", s) 81 return "" 82 } 83 } else if ctx.Windows() { 84 switch s { 85 case "libc++", "libc++_static", "": 86 // Only use static libc++ for Windows. 87 return "libc++_static" 88 case "none": 89 return "" 90 default: 91 ctx.ModuleErrorf("stl: %q is not a supported STL for windows", s) 92 return "" 93 } 94 } else if ctx.Fuchsia() { 95 switch s { 96 case "c++_static": 97 return "libc++_static" 98 case "c++_shared": 99 return "libc++" 100 case "libc++", "libc++_static": 101 return s 102 case "none": 103 return "" 104 case "": 105 if ctx.static() { 106 return "libc++_static" 107 } else { 108 return "libc++" 109 } 110 default: 111 ctx.ModuleErrorf("stl: %q is not a supported STL on Fuchsia", s) 112 return "" 113 } 114 } else { 115 switch s { 116 case "libc++", "libc++_static": 117 return s 118 case "c++_shared": 119 return "libc++" 120 case "c++_static": 121 return "libc++_static" 122 case "none": 123 return "" 124 case "", "system": 125 if ctx.static() { 126 return "libc++_static" 127 } else { 128 return "libc++" 129 } 130 default: 131 ctx.ModuleErrorf("stl: %q is not a supported STL", s) 132 return "" 133 } 134 } 135 }() 136} 137 138func needsLibAndroidSupport(ctx BaseModuleContext) bool { 139 versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch()) 140 if err != nil { 141 ctx.PropertyErrorf("sdk_version", err.Error()) 142 } 143 144 if versionStr == "current" { 145 return false 146 } 147 148 version, err := strconv.Atoi(versionStr) 149 if err != nil { 150 panic(fmt.Sprintf( 151 "invalid API level returned from normalizeNdkApiLevel: %q", 152 versionStr)) 153 } 154 155 return version < 21 156} 157 158func staticUnwinder(ctx android.BaseModuleContext) string { 159 if ctx.Arch().ArchType == android.Arm { 160 return "libunwind_llvm" 161 } else { 162 return "libgcc_stripped" 163 } 164} 165 166func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { 167 switch stl.Properties.SelectedStl { 168 case "libstdc++": 169 // Nothing 170 case "libc++", "libc++_static": 171 if stl.Properties.SelectedStl == "libc++" { 172 deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) 173 } else { 174 deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl) 175 } 176 if ctx.Device() && !ctx.useSdk() { 177 // __cxa_demangle is not a part of libc++.so on the device since 178 // it's large and most processes don't need it. Statically link 179 // libc++demangle into every process so that users still have it if 180 // needed, but the linker won't include this unless it is actually 181 // called. 182 // http://b/138245375 183 deps.StaticLibs = append(deps.StaticLibs, "libc++demangle") 184 } 185 if ctx.toolchain().Bionic() { 186 if ctx.staticBinary() { 187 deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx)) 188 } else { 189 deps.StaticUnwinderIfLegacy = true 190 } 191 } 192 case "": 193 // None or error. 194 if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" { 195 deps.StaticUnwinderIfLegacy = true 196 } 197 case "ndk_system": 198 // TODO: Make a system STL prebuilt for the NDK. 199 // The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have 200 // its own includes. The includes are handled in CCBase.Flags(). 201 deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...) 202 case "ndk_libc++_shared", "ndk_libc++_static": 203 if stl.Properties.SelectedStl == "ndk_libc++_shared" { 204 deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) 205 } else { 206 deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi") 207 } 208 if needsLibAndroidSupport(ctx) { 209 deps.StaticLibs = append(deps.StaticLibs, "ndk_libandroid_support") 210 } 211 if ctx.Arch().ArchType == android.Arm { 212 deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind") 213 } else { 214 deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped") 215 } 216 default: 217 panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) 218 } 219 220 return deps 221} 222 223func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { 224 switch stl.Properties.SelectedStl { 225 case "libc++", "libc++_static": 226 if ctx.Darwin() { 227 // libc++'s headers are annotated with availability macros that 228 // indicate which version of Mac OS was the first to ship with a 229 // libc++ feature available in its *system's* libc++.dylib. We do 230 // not use the system's library, but rather ship our own. As such, 231 // these availability attributes are meaningless for us but cause 232 // build breaks when we try to use code that would not be available 233 // in the system's dylib. 234 flags.Local.CppFlags = append(flags.Local.CppFlags, 235 "-D_LIBCPP_DISABLE_AVAILABILITY") 236 } 237 238 if !ctx.toolchain().Bionic() { 239 flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++") 240 flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") 241 if ctx.Windows() { 242 // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj 243 // exception model for 32-bit. 244 if ctx.Arch().ArchType == android.X86 { 245 flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions") 246 } 247 flags.Local.CppFlags = append(flags.Local.CppFlags, 248 // Disable visiblity annotations since we're using static 249 // libc++. 250 "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", 251 "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", 252 // Use Win32 threads in libc++. 253 "-D_LIBCPP_HAS_THREAD_API_WIN32") 254 } 255 } else { 256 if ctx.Arch().ArchType == android.Arm { 257 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,libunwind_llvm.a") 258 } 259 } 260 case "libstdc++": 261 // Nothing 262 case "ndk_system": 263 ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include") 264 flags.Local.CFlags = append(flags.Local.CFlags, "-isystem "+ndkSrcRoot.String()) 265 case "ndk_libc++_shared", "ndk_libc++_static": 266 if ctx.Arch().ArchType == android.Arm { 267 // Make sure the _Unwind_XXX symbols are not re-exported. 268 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,libunwind.a") 269 } 270 case "": 271 // None or error. 272 if !ctx.toolchain().Bionic() { 273 flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++") 274 flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") 275 } 276 default: 277 panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) 278 } 279 280 return flags 281} 282