1// Copyright 2015 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 config
16
17import (
18	"fmt"
19	"path/filepath"
20
21	"android/soong/android"
22)
23
24type toolchainFactory func(arch android.Arch) Toolchain
25
26var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
27
28func registerToolchainFactory(os android.OsType, arch android.ArchType, factory toolchainFactory) {
29	if toolchainFactories[os] == nil {
30		toolchainFactories[os] = make(map[android.ArchType]toolchainFactory)
31	}
32	toolchainFactories[os][arch] = factory
33}
34
35type toolchainContext interface {
36	Os() android.OsType
37	Arch() android.Arch
38}
39
40type conversionContext interface {
41	BazelConversionMode() bool
42}
43
44func FindToolchainWithContext(ctx toolchainContext) Toolchain {
45	t, err := findToolchain(ctx.Os(), ctx.Arch())
46	if err != nil {
47		if c, ok := ctx.(conversionContext); ok && c.BazelConversionMode() {
48			// TODO(b/179123288): determine conversion for toolchain
49			return &toolchainX86_64{}
50		} else {
51			panic(err)
52		}
53	}
54	return t
55}
56
57func FindToolchain(os android.OsType, arch android.Arch) Toolchain {
58	t, err := findToolchain(os, arch)
59	if err != nil {
60		panic(err)
61	}
62	return t
63}
64
65func findToolchain(os android.OsType, arch android.Arch) (Toolchain, error) {
66	factory := toolchainFactories[os][arch.ArchType]
67	if factory == nil {
68		return nil, fmt.Errorf("Toolchain not found for %s arch %q", os.String(), arch.String())
69	}
70	return factory(arch), nil
71}
72
73type Toolchain interface {
74	Name() string
75
76	GccRoot() string
77	GccTriple() string
78	// GccVersion should return a real value, not a ninja reference
79	GccVersion() string
80	ToolPath() string
81
82	IncludeFlags() string
83
84	ClangTriple() string
85	ToolchainClangCflags() string
86	ToolchainClangLdflags() string
87	ClangAsflags() string
88	ClangCflags() string
89	ClangCppflags() string
90	ClangLdflags() string
91	ClangLldflags() string
92	ClangInstructionSetFlags(string) (string, error)
93
94	ndkTriple() string
95
96	YasmFlags() string
97
98	WindresFlags() string
99
100	Is64Bit() bool
101
102	ShlibSuffix() string
103	ExecutableSuffix() string
104
105	LibclangRuntimeLibraryArch() string
106
107	AvailableLibraries() []string
108
109	Bionic() bool
110}
111
112type toolchainBase struct {
113}
114
115func (t *toolchainBase) ndkTriple() string {
116	return ""
117}
118
119func NDKTriple(toolchain Toolchain) string {
120	triple := toolchain.ndkTriple()
121	if triple == "" {
122		// Use the clang triple if there is no explicit NDK triple
123		triple = toolchain.ClangTriple()
124	}
125	return triple
126}
127
128func (toolchainBase) ClangInstructionSetFlags(s string) (string, error) {
129	if s != "" {
130		return "", fmt.Errorf("instruction_set: %s is not a supported instruction set", s)
131	}
132	return "", nil
133}
134
135func (toolchainBase) ToolchainClangCflags() string {
136	return ""
137}
138
139func (toolchainBase) ToolchainClangLdflags() string {
140	return ""
141}
142
143func (toolchainBase) ShlibSuffix() string {
144	return ".so"
145}
146
147func (toolchainBase) ExecutableSuffix() string {
148	return ""
149}
150
151func (toolchainBase) ClangAsflags() string {
152	return ""
153}
154
155func (toolchainBase) YasmFlags() string {
156	return ""
157}
158
159func (toolchainBase) WindresFlags() string {
160	return ""
161}
162
163func (toolchainBase) LibclangRuntimeLibraryArch() string {
164	return ""
165}
166
167func (toolchainBase) AvailableLibraries() []string {
168	return []string{}
169}
170
171func (toolchainBase) Bionic() bool {
172	return true
173}
174
175func (t toolchainBase) ToolPath() string {
176	return ""
177}
178
179type toolchain64Bit struct {
180	toolchainBase
181}
182
183func (toolchain64Bit) Is64Bit() bool {
184	return true
185}
186
187type toolchain32Bit struct {
188	toolchainBase
189}
190
191func (toolchain32Bit) Is64Bit() bool {
192	return false
193}
194
195func variantOrDefault(variants map[string]string, choice string) string {
196	if ret, ok := variants[choice]; ok {
197		return ret
198	}
199	return variants[""]
200}
201
202func addPrefix(list []string, prefix string) []string {
203	for i := range list {
204		list[i] = prefix + list[i]
205	}
206	return list
207}
208
209func LibclangRuntimeLibrary(t Toolchain, library string) string {
210	arch := t.LibclangRuntimeLibraryArch()
211	if arch == "" {
212		return ""
213	}
214	if !t.Bionic() {
215		return "libclang_rt." + library + "-" + arch
216	}
217	return "libclang_rt." + library + "-" + arch + "-android"
218}
219
220func BuiltinsRuntimeLibrary(t Toolchain) string {
221	return LibclangRuntimeLibrary(t, "builtins")
222}
223
224func AddressSanitizerRuntimeLibrary(t Toolchain) string {
225	return LibclangRuntimeLibrary(t, "asan")
226}
227
228func HWAddressSanitizerRuntimeLibrary(t Toolchain) string {
229	return LibclangRuntimeLibrary(t, "hwasan")
230}
231
232func HWAddressSanitizerStaticLibrary(t Toolchain) string {
233	return LibclangRuntimeLibrary(t, "hwasan_static")
234}
235
236func UndefinedBehaviorSanitizerRuntimeLibrary(t Toolchain) string {
237	return LibclangRuntimeLibrary(t, "ubsan_standalone")
238}
239
240func UndefinedBehaviorSanitizerMinimalRuntimeLibrary(t Toolchain) string {
241	return LibclangRuntimeLibrary(t, "ubsan_minimal")
242}
243
244func ThreadSanitizerRuntimeLibrary(t Toolchain) string {
245	return LibclangRuntimeLibrary(t, "tsan")
246}
247
248func ScudoRuntimeLibrary(t Toolchain) string {
249	return LibclangRuntimeLibrary(t, "scudo")
250}
251
252func ScudoMinimalRuntimeLibrary(t Toolchain) string {
253	return LibclangRuntimeLibrary(t, "scudo_minimal")
254}
255
256func LibFuzzerRuntimeLibrary(t Toolchain) string {
257	return LibclangRuntimeLibrary(t, "fuzzer")
258}
259
260func ToolPath(t Toolchain) string {
261	if p := t.ToolPath(); p != "" {
262		return p
263	}
264	return filepath.Join(t.GccRoot(), t.GccTriple(), "bin")
265}
266
267var inList = android.InList
268