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 *Module) string { 24 family, _ := getNdkStlFamilyAndLinkType(m) 25 return family 26} 27 28func getNdkStlFamilyAndLinkType(m *Module) (string, string) { 29 stl := m.stl.Properties.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 "none": 119 return "" 120 case "": 121 if ctx.static() { 122 return "libc++_static" 123 } else { 124 return "libc++" 125 } 126 default: 127 ctx.ModuleErrorf("stl: %q is not a supported STL", s) 128 return "" 129 } 130 } 131 }() 132} 133 134func needsLibAndroidSupport(ctx BaseModuleContext) bool { 135 versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch()) 136 if err != nil { 137 ctx.PropertyErrorf("sdk_version", err.Error()) 138 } 139 140 if versionStr == "current" { 141 return false 142 } 143 144 version, err := strconv.Atoi(versionStr) 145 if err != nil { 146 panic(fmt.Sprintf( 147 "invalid API level returned from normalizeNdkApiLevel: %q", 148 versionStr)) 149 } 150 151 return version < 21 152} 153 154func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { 155 switch stl.Properties.SelectedStl { 156 case "libstdc++": 157 // Nothing 158 case "libc++", "libc++_static": 159 if stl.Properties.SelectedStl == "libc++" { 160 deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) 161 } else { 162 deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl) 163 } 164 if ctx.toolchain().Bionic() { 165 if ctx.Arch().ArchType == android.Arm { 166 deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm") 167 } 168 if ctx.staticBinary() { 169 deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl") 170 } 171 } 172 case "": 173 // None or error. 174 case "ndk_system": 175 // TODO: Make a system STL prebuilt for the NDK. 176 // The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have 177 // its own includes. The includes are handled in CCBase.Flags(). 178 deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...) 179 case "ndk_libc++_shared", "ndk_libc++_static": 180 if stl.Properties.SelectedStl == "ndk_libc++_shared" { 181 deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) 182 } else { 183 deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi") 184 } 185 if needsLibAndroidSupport(ctx) { 186 deps.StaticLibs = append(deps.StaticLibs, "ndk_libandroid_support") 187 } 188 if ctx.Arch().ArchType == android.Arm { 189 deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind") 190 } 191 default: 192 panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) 193 } 194 195 return deps 196} 197 198func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { 199 switch stl.Properties.SelectedStl { 200 case "libc++", "libc++_static": 201 flags.CFlags = append(flags.CFlags, "-D_USING_LIBCXX") 202 203 if ctx.Darwin() { 204 // libc++'s headers are annotated with availability macros that 205 // indicate which version of Mac OS was the first to ship with a 206 // libc++ feature available in its *system's* libc++.dylib. We do 207 // not use the system's library, but rather ship our own. As such, 208 // these availability attributes are meaningless for us but cause 209 // build breaks when we try to use code that would not be available 210 // in the system's dylib. 211 flags.CppFlags = append(flags.CppFlags, 212 "-D_LIBCPP_DISABLE_AVAILABILITY") 213 } 214 215 if !ctx.toolchain().Bionic() { 216 flags.CppFlags = append(flags.CppFlags, "-nostdinc++") 217 flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs") 218 if ctx.staticBinary() { 219 flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.Os()]...) 220 } else { 221 flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.Os()]...) 222 } 223 if ctx.Windows() { 224 // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj 225 // exception model for 32-bit. 226 if ctx.Arch().ArchType == android.X86 { 227 flags.CppFlags = append(flags.CppFlags, "-fsjlj-exceptions") 228 } 229 flags.CppFlags = append(flags.CppFlags, 230 // Disable visiblity annotations since we're using static 231 // libc++. 232 "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", 233 "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", 234 // Use Win32 threads in libc++. 235 "-D_LIBCPP_HAS_THREAD_API_WIN32") 236 } 237 } else { 238 if ctx.Arch().ArchType == android.Arm { 239 flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,libunwind_llvm.a") 240 } 241 } 242 case "libstdc++": 243 // Nothing 244 case "ndk_system": 245 ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include") 246 flags.CFlags = append(flags.CFlags, "-isystem "+ndkSrcRoot.String()) 247 case "ndk_libc++_shared", "ndk_libc++_static": 248 if ctx.Arch().ArchType == android.Arm { 249 // Make sure the _Unwind_XXX symbols are not re-exported. 250 flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,libunwind.a") 251 } 252 case "": 253 // None or error. 254 if !ctx.toolchain().Bionic() { 255 flags.CppFlags = append(flags.CppFlags, "-nostdinc++") 256 flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs") 257 if ctx.staticBinary() { 258 flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.Os()]...) 259 } else { 260 flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.Os()]...) 261 } 262 } 263 default: 264 panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) 265 } 266 267 return flags 268} 269 270var hostDynamicGccLibs, hostStaticGccLibs map[android.OsType][]string 271 272func init() { 273 hostDynamicGccLibs = map[android.OsType][]string{ 274 android.Fuchsia: []string{"-lc", "-lunwind"}, 275 android.Linux: []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"}, 276 android.Darwin: []string{"-lc", "-lSystem"}, 277 android.Windows: []string{"-Wl,--start-group", "-lmingw32", "-lgcc", "-lgcc_eh", 278 "-lmoldname", "-lmingwex", "-lmsvcrt", "-lucrt", "-lpthread", 279 "-ladvapi32", "-lshell32", "-luser32", "-lkernel32", "-lpsapi", 280 "-Wl,--end-group"}, 281 } 282 hostStaticGccLibs = map[android.OsType][]string{ 283 android.Linux: []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"}, 284 android.Darwin: []string{"NO_STATIC_HOST_BINARIES_ON_DARWIN"}, 285 android.Windows: []string{"NO_STATIC_HOST_BINARIES_ON_WINDOWS"}, 286 } 287} 288