xref: /aosp_15_r20/build/soong/cc/stl.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"fmt"
19
20	"android/soong/android"
21)
22
23func getNdkStlFamily(m LinkableInterface) string {
24	family, _ := getNdkStlFamilyAndLinkType(m)
25	return family
26}
27
28func deduplicateStlInput(stl string) string {
29	switch stl {
30	case "c++_shared":
31		return "libc++"
32	case "c++_static":
33		return "libc++_static"
34	}
35	return stl
36}
37
38func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) {
39	stl := m.SelectedStl()
40	switch stl {
41	case "ndk_libc++_shared", "libc++":
42		return "libc++", "shared"
43	case "ndk_libc++_static", "libc++_static":
44		return "libc++", "static"
45	case "ndk_system":
46		return "system", "shared"
47	case "":
48		return "none", "none"
49	default:
50		panic(fmt.Errorf("stl: %q is not a valid STL", stl))
51	}
52}
53
54type StlProperties struct {
55	// Select the STL library to use.  Possible values are "libc++",
56	// "libc++_static", "libstdc++", or "none". Leave blank to select the
57	// default.
58	Stl *string `android:"arch_variant"`
59
60	SelectedStl string `blueprint:"mutated"`
61}
62
63type stl struct {
64	Properties StlProperties
65}
66
67func (stl *stl) props() []interface{} {
68	return []interface{}{&stl.Properties}
69}
70
71func (stl *stl) begin(ctx BaseModuleContext) {
72	stl.Properties.SelectedStl = func() string {
73		s := ""
74		if stl.Properties.Stl != nil {
75			s = *stl.Properties.Stl
76		} else if ctx.header() {
77			s = "none"
78		}
79		if s == "none" {
80			return ""
81		}
82		s = deduplicateStlInput(s)
83		if ctx.useSdk() && ctx.Device() {
84			switch s {
85			case "", "system":
86				return "ndk_system"
87			case "libc++":
88				return "ndk_libc++_shared"
89			case "libc++_static":
90				return "ndk_libc++_static"
91			default:
92				ctx.ModuleErrorf("stl: %q is not a supported STL with sdk_version set", s)
93				return ""
94			}
95		} else if ctx.Windows() {
96			switch s {
97			case "libc++", "libc++_static", "":
98				// Only use static libc++ for Windows.
99				return "libc++_static"
100			default:
101				ctx.ModuleErrorf("stl: %q is not a supported STL for windows", s)
102				return ""
103			}
104		} else {
105			switch s {
106			case "libc++", "libc++_static":
107				return s
108			case "", "system":
109				if ctx.static() {
110					return "libc++_static"
111				} else {
112					return "libc++"
113				}
114			default:
115				ctx.ModuleErrorf("stl: %q is not a supported STL", s)
116				return ""
117			}
118		}
119	}()
120}
121
122func staticUnwinder(ctx android.BaseModuleContext) string {
123	vndkVersion := ctx.Module().(*Module).VndkVersion()
124
125	// Modules using R vndk use different unwinder
126	if vndkVersion == "30" {
127		if ctx.Arch().ArchType == android.Arm {
128			return "libunwind_llvm"
129		} else {
130			return "libgcc_stripped"
131		}
132	}
133
134	return "libunwind"
135}
136
137func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
138	switch stl.Properties.SelectedStl {
139	case "libstdc++":
140		// Nothing
141	case "libc++", "libc++_static":
142		if stl.Properties.SelectedStl == "libc++" {
143			deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl)
144		} else {
145			deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl)
146		}
147		if ctx.Device() && !ctx.useSdk() {
148			// __cxa_demangle is not a part of libc++.so on the device since
149			// it's large and most processes don't need it. Statically link
150			// libc++demangle into every process so that users still have it if
151			// needed, but the linker won't include this unless it is actually
152			// called.
153			// http://b/138245375
154			deps.StaticLibs = append(deps.StaticLibs, "libc++demangle")
155		}
156		if ctx.toolchain().Bionic() {
157			if ctx.staticBinary() {
158				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx))
159			} else {
160				deps.StaticUnwinderIfLegacy = true
161			}
162		}
163	case "":
164		// None or error.
165		if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" {
166			deps.StaticUnwinderIfLegacy = true
167		}
168	case "ndk_system":
169		// TODO: Make a system STL prebuilt for the NDK.
170		// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
171		// its own includes. The includes are handled in CCBase.Flags().
172		deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...)
173		deps.HeaderLibs = append([]string{"ndk_system"}, deps.HeaderLibs...)
174	case "ndk_libc++_shared", "ndk_libc++_static":
175		if stl.Properties.SelectedStl == "ndk_libc++_shared" {
176			deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl)
177		} else {
178			deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi")
179		}
180		deps.StaticLibs = append(deps.StaticLibs, "libunwind")
181	default:
182		panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
183	}
184
185	return deps
186}
187
188func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags {
189	switch stl.Properties.SelectedStl {
190	case "libc++", "libc++_static":
191		if ctx.Darwin() {
192			// libc++'s headers are annotated with availability macros that
193			// indicate which version of Mac OS was the first to ship with a
194			// libc++ feature available in its *system's* libc++.dylib. We do
195			// not use the system's library, but rather ship our own. As such,
196			// these availability attributes are meaningless for us but cause
197			// build breaks when we try to use code that would not be available
198			// in the system's dylib.
199			flags.Local.CppFlags = append(flags.Local.CppFlags,
200				"-D_LIBCPP_DISABLE_AVAILABILITY")
201		}
202
203		if !ctx.toolchain().Bionic() {
204			flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
205			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
206			if ctx.Windows() {
207				flags.Local.CppFlags = append(flags.Local.CppFlags,
208					// These macros can also be defined by libc++'s __config
209					// or __config_site headers so define them the same way
210					// (i.e. to nothing). Disable visibility annotations since
211					// we're using static libc++.
212					"-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=",
213					"-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS=",
214					// Use Win32 threads in libc++.
215					"-D_LIBCPP_HAS_THREAD_API_WIN32=")
216			}
217		}
218	case "libstdc++":
219		// Nothing
220	case "ndk_system":
221		// Nothing: The exports of ndk_system will be added automatically to the local cflags
222	case "ndk_libc++_shared", "ndk_libc++_static":
223		if ctx.Arch().ArchType == android.Arm {
224			// Make sure the _Unwind_XXX symbols are not re-exported.
225			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,libunwind.a")
226		}
227	case "":
228		// None or error.
229		if !ctx.toolchain().Bionic() {
230			flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
231			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
232		}
233	default:
234		panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
235	}
236
237	return flags
238}
239