• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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