blob: 2d8124d06e28ee0a597ec05371ce9167c1399bf7 [file] [log] [blame]
Brian Silverman7d89e282021-11-17 17:36:54 -08001# Copyright 2018 The Bazel Authors.
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
15load(
16 "//toolchain/internal:common.bzl",
17 _arch = "arch",
18 _canonical_dir_path = "canonical_dir_path",
19 _check_os_arch_keys = "check_os_arch_keys",
20 _host_tool_features = "host_tool_features",
21 _host_tools = "host_tools",
22 _os = "os",
23 _os_arch_pair = "os_arch_pair",
24 _os_bzl = "os_bzl",
25 _pkg_path_from_label = "pkg_path_from_label",
26 _supported_targets = "SUPPORTED_TARGETS",
27)
28load(
29 "//toolchain/internal:sysroot.bzl",
30 _default_sysroot_path = "default_sysroot_path",
31 _sysroot_path = "sysroot_path",
32)
33
34def _include_dirs_str(rctx, key):
35 dirs = rctx.attr.cxx_builtin_include_directories.get(key)
36 if not dirs:
37 return ""
38 return ("\n" + 12 * " ").join(["\"%s\"," % d for d in dirs])
39
Brian Silverman4c7235a2021-11-17 19:04:37 -080040def _is_absolute(path):
41 return path[0] == "/" and (len(path) == 1 or path[1] != "/")
42
Brian Silverman7d89e282021-11-17 17:36:54 -080043def llvm_config_impl(rctx):
44 _check_os_arch_keys(rctx.attr.toolchain_roots)
Brian Silverman4c7235a2021-11-17 19:04:37 -080045 _check_os_arch_keys(rctx.attr.target_toolchain_roots)
Brian Silverman7d89e282021-11-17 17:36:54 -080046 _check_os_arch_keys(rctx.attr.sysroot)
47 _check_os_arch_keys(rctx.attr.cxx_builtin_include_directories)
Brian Silverman4c7235a2021-11-17 19:04:37 -080048 _check_os_arch_keys(rctx.attr.standard_libraries)
Brian Silverman7d89e282021-11-17 17:36:54 -080049
50 os = _os(rctx)
51 if os == "windows":
52 rctx.file("BUILD.bazel")
53 rctx.file("toolchains.bzl", """\
54def llvm_register_toolchains():
55 pass
56""")
57 return
58 arch = _arch(rctx)
59
60 key = _os_arch_pair(os, arch)
61 toolchain_root = rctx.attr.toolchain_roots.get(key)
62 if not toolchain_root:
63 toolchain_root = rctx.attr.toolchain_roots.get("")
64 if not toolchain_root:
65 fail("LLVM toolchain root missing for ({}, {})", os, arch)
66
67 # Check if the toolchain root is an absolute path.
68 use_absolute_paths = rctx.attr.absolute_paths
Brian Silverman4c7235a2021-11-17 19:04:37 -080069 for target_toolchain_root in rctx.attr.target_toolchain_roots.values():
70 if _is_absolute(toolchain_root) != _is_absolute(target_toolchain_root):
71 fail("Host and target toolchain roots must both be absolute or not")
72 if _is_absolute(toolchain_root):
Brian Silverman7d89e282021-11-17 17:36:54 -080073 use_absolute_paths = True
74
Brian Silverman4c7235a2021-11-17 19:04:37 -080075 target_llvm_repo_paths = {}
Brian Silverman7d89e282021-11-17 17:36:54 -080076 if use_absolute_paths:
77 llvm_repo_label = Label(toolchain_root + ":BUILD.bazel") # Exact target does not matter.
78 llvm_repo_path = _canonical_dir_path(str(rctx.path(llvm_repo_label).dirname))
Brian Silverman4c7235a2021-11-17 19:04:37 -080079 for a_key in rctx.attr.target_toolchain_roots:
80 target_llvm_repo_label = Label(rctx.attr.target_toolchain_roots[a_key] + ":BUILD.bazel")
81 target_llvm_repo_paths[a_key] = _canonical_dir_path(str(rctx.path(target_llvm_repo_label).dirname))
Brian Silverman7d89e282021-11-17 17:36:54 -080082 config_repo_path = _canonical_dir_path(str(rctx.path("")))
83 toolchain_path_prefix = llvm_repo_path
84 tools_path_prefix = llvm_repo_path
85 wrapper_bin_prefix = config_repo_path
86 else:
87 llvm_repo_path = _pkg_path_from_label(Label(toolchain_root + ":BUILD.bazel"))
Brian Silverman4c7235a2021-11-17 19:04:37 -080088 for a_key in rctx.attr.target_toolchain_roots:
89 target_llvm_repo_paths[a_key] = _pkg_path_from_label(Label(rctx.attr.target_toolchain_roots[a_key] + ":BUILD.bazel"))
Brian Silverman7d89e282021-11-17 17:36:54 -080090 config_repo_path = "external/%s/" % rctx.name
91
92 # tools can only be defined in a subdirectory of config_repo_path,
93 # because their paths are relative to the package defining
94 # cc_toolchain, and cannot contain '..'.
95 # https://github.com/bazelbuild/bazel/issues/7746. To work around
96 # this, we symlink the llvm repo under the package so all tools (except
97 # clang) can be called with normalized relative paths. For clang
98 # however, using a path with symlinks interferes with the header file
99 # inclusion validation checks, because clang frontend will infer the
100 # InstalledDir to be the symlinked path, and will look for header files
101 # in the symlinked path, but that seems to fail the inclusion
102 # validation check. So we always use a cc_wrapper (which is called
103 # through a normalized relative path), and then call clang with the not
104 # symlinked path from the wrapper.
105 rctx.symlink("../../" + llvm_repo_path, "llvm")
106 toolchain_path_prefix = llvm_repo_path
107 tools_path_prefix = "llvm/"
108 wrapper_bin_prefix = ""
109
110 default_sysroot_path = _default_sysroot_path(rctx, os)
111
112 workspace_name = rctx.name
113 toolchain_info = struct(
114 os = os,
115 arch = arch,
116 toolchain_root = toolchain_root,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800117 additional_target_compatible_with_dict = rctx.attr.additional_target_compatible_with,
118 target_toolchain_roots_dict = rctx.attr.target_toolchain_roots,
Brian Silverman7d89e282021-11-17 17:36:54 -0800119 toolchain_path_prefix = toolchain_path_prefix,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800120 target_toolchain_path_prefixes_dict = target_llvm_repo_paths,
Brian Silverman7d89e282021-11-17 17:36:54 -0800121 tools_path_prefix = tools_path_prefix,
122 wrapper_bin_prefix = wrapper_bin_prefix,
123 additional_include_dirs_dict = rctx.attr.cxx_builtin_include_directories,
124 sysroot_dict = rctx.attr.sysroot,
125 default_sysroot_path = default_sysroot_path,
126 llvm_version = rctx.attr.llvm_version,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800127 standard_libraries_dict = rctx.attr.standard_libraries,
128 static_libstdcxx = rctx.attr.static_libstdcxx,
129 conlyopts_dict = rctx.attr.conlyopts,
130 cxxopts_dict = rctx.attr.cxxopts,
131 copts_dict = rctx.attr.copts,
132 opt_copts_dict = rctx.attr.opt_copts,
133 dbg_copts_dict = rctx.attr.dbg_copts,
Brian Silverman1e7c8972022-02-03 23:15:41 -0800134 fastbuild_copts_dict = rctx.attr.fastbuild_copts,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800135 linkopts_dict = rctx.attr.linkopts,
Brian Silverman7d89e282021-11-17 17:36:54 -0800136 )
137 host_tools_info = dict([
138 pair
139 for (key, tool_path, features) in [
140 # This is used for macOS hosts:
141 ("libtool", "/usr/bin/libtool", [_host_tool_features.SUPPORTS_ARG_FILE]),
142 # This is used with old (pre 7) LLVM versions:
143 ("strip", "/usr/bin/strip", []),
144 # This is used when lld doesn't support the target platform (i.e.
145 # Mach-O for macOS):
146 ("ld", "/usr/bin/ld", []),
147 ]
148 for pair in _host_tools.get_tool_info(rctx, tool_path, features, key).items()
149 ])
150 cc_toolchains_str, toolchain_labels_str = _cc_toolchains_str(
151 workspace_name,
152 toolchain_info,
153 use_absolute_paths,
154 host_tools_info,
155 )
156
157 # Convenience macro to register all generated toolchains.
158 rctx.template(
159 "toolchains.bzl",
160 Label("//toolchain:toolchains.bzl.tpl"),
161 {
162 "%{toolchain_labels}": toolchain_labels_str,
163 },
164 )
165
166 # BUILD file with all the generated toolchain definitions.
167 rctx.template(
168 "BUILD.bazel",
169 Label("//toolchain:BUILD.toolchain.tpl"),
170 {
171 "%{cc_toolchains}": cc_toolchains_str,
172 "%{cc_toolchain_config_bzl}": str(rctx.attr._cc_toolchain_config_bzl),
173 },
174 )
175
176 # CC wrapper script; see comments near the definition of `wrapper_bin_prefix`.
177 if os == "darwin":
178 cc_wrapper_tpl = "//toolchain:osx_cc_wrapper.sh.tpl"
179 else:
180 cc_wrapper_tpl = "//toolchain:cc_wrapper.sh.tpl"
181 rctx.template(
182 "bin/cc_wrapper.sh",
183 Label(cc_wrapper_tpl),
184 {
185 "%{toolchain_path_prefix}": toolchain_path_prefix,
186 },
187 )
188
189 # libtool wrapper; used if the host libtool doesn't support arg files:
190 rctx.template(
191 "bin/host_libtool_wrapper.sh",
192 Label("//toolchain:host_libtool_wrapper.sh.tpl"),
193 {
194 "%{libtool_path}": "/usr/bin/libtool",
195 },
196 )
197
198def _cc_toolchains_str(
199 workspace_name,
200 toolchain_info,
201 use_absolute_paths,
202 host_tools_info):
203 # Since all the toolchains rely on downloading the right LLVM toolchain for
204 # the host architecture, we don't need to explicitly specify
205 # `exec_compatible_with` attribute. If the host and execution platform are
206 # not the same, then host auto-detection based LLVM download does not work
207 # and the user has to explicitly specify the distribution of LLVM they
208 # want.
209
210 # Note that for cross-compiling, the toolchain configuration will need
211 # appropriate sysroots. A recommended approach is to configure two
212 # `llvm_toolchain` repos, one without sysroots (for easy single platform
213 # builds) and register this one, and one with sysroots and provide
214 # `--extra_toolchains` flag when cross-compiling.
215
216 cc_toolchains_str = ""
217 toolchain_names = []
218 for (target_os, target_arch) in _supported_targets:
219 suffix = "{}-{}".format(target_arch, target_os)
220 cc_toolchain_str = _cc_toolchain_str(
221 suffix,
222 target_os,
223 target_arch,
224 toolchain_info,
225 use_absolute_paths,
226 host_tools_info,
227 )
228 if cc_toolchain_str:
229 cc_toolchains_str = cc_toolchains_str + cc_toolchain_str
230 toolchain_name = "@{}//:cc-toolchain-{}".format(workspace_name, suffix)
231 toolchain_names.append(toolchain_name)
232
233 sep = ",\n" + " " * 8 # 2 tabs with tabstop=4.
234 toolchain_labels_str = sep.join(["\"{}\"".format(d) for d in toolchain_names])
235 return cc_toolchains_str, toolchain_labels_str
236
237def _cc_toolchain_str(
238 suffix,
239 target_os,
240 target_arch,
241 toolchain_info,
242 use_absolute_paths,
243 host_tools_info):
244 host_os = toolchain_info.os
245 host_arch = toolchain_info.arch
246
247 host_os_bzl = _os_bzl(host_os)
248 target_os_bzl = _os_bzl(target_os)
249
250 sysroot_path, sysroot = _sysroot_path(
251 toolchain_info.sysroot_dict,
252 target_os,
253 target_arch,
254 )
255 if not sysroot_path:
256 if host_os == target_os and host_arch == target_arch:
257 # For darwin -> darwin, we can use the macOS SDK path.
258 sysroot_path = toolchain_info.default_sysroot_path
259 else:
260 # We are trying to cross-compile without a sysroot, let's bail.
261 # TODO: Are there situations where we can continue?
262 return ""
263
264 extra_files_str = ", \":llvm\", \":wrapper-files\""
265
Brian Silverman4c7235a2021-11-17 19:04:37 -0800266 key = _os_arch_pair(target_os, target_arch)
267 additional_include_dirs = toolchain_info.additional_include_dirs_dict.get(key)
Brian Silverman7d89e282021-11-17 17:36:54 -0800268 additional_include_dirs_str = "[]"
269 if additional_include_dirs:
270 additional_include_dirs_str = "[{}]".format(
271 ", ".join(["\"{}\"".format(d) for d in additional_include_dirs]),
272 )
273
274 sysroot_label_str = "\"%s\"" % str(sysroot) if sysroot else ""
275
276 # `struct` isn't allowed in `BUILD` files so we JSON encode + decode to turn
277 # them into `dict`s.
278 host_tools_info = json.decode(json.encode(host_tools_info))
279
Brian Silverman4c7235a2021-11-17 19:04:37 -0800280 standard_library = toolchain_info.standard_libraries_dict.get(key, "")
281 conlyopts = toolchain_info.conlyopts_dict.get(key, [])
282 cxxopts = toolchain_info.cxxopts_dict.get(key, [])
283 copts = toolchain_info.copts_dict.get(key, [])
284 opt_copts = toolchain_info.opt_copts_dict.get(key, [])
285 dbg_copts = toolchain_info.dbg_copts_dict.get(key, [])
Brian Silverman1e7c8972022-02-03 23:15:41 -0800286 fastbuild_copts = toolchain_info.fastbuild_copts_dict.get(key, [])
Brian Silverman4c7235a2021-11-17 19:04:37 -0800287 linkopts = toolchain_info.linkopts_dict.get(key, [])
288 target_toolchain_root = toolchain_info.toolchain_root
289 if key in toolchain_info.target_toolchain_roots_dict:
290 target_toolchain_root = toolchain_info.target_toolchain_roots_dict[key]
291 elif "" in toolchain_info.target_toolchain_roots_dict:
292 target_toolchain_root = toolchain_info.target_toolchain_roots_dict[""]
293 target_toolchain_path_prefix = toolchain_info.toolchain_path_prefix
294 if key in toolchain_info.target_toolchain_path_prefixes_dict:
295 target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[key]
296 elif "" in toolchain_info.target_toolchain_roots_dict:
297 target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[""]
298 additional_target_compatible_with = toolchain_info.additional_target_compatible_with_dict.get(key, [])
299
Brian Silverman7d89e282021-11-17 17:36:54 -0800300 template = """
301# CC toolchain for cc-clang-{suffix}.
302
303cc_toolchain_config(
304 name = "local-{suffix}",
305 host_arch = "{host_arch}",
306 host_os = "{host_os}",
307 target_arch = "{target_arch}",
308 target_os = "{target_os}",
309 toolchain_path_prefix = "{toolchain_path_prefix}",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800310 target_toolchain_path_prefix = "{target_toolchain_path_prefix}",
Brian Silverman7d89e282021-11-17 17:36:54 -0800311 tools_path_prefix = "{tools_path_prefix}",
312 wrapper_bin_prefix = "{wrapper_bin_prefix}",
313 sysroot_path = "{sysroot_path}",
314 additional_include_dirs = {additional_include_dirs_str},
315 llvm_version = "{llvm_version}",
316 host_tools_info = {host_tools_info},
Brian Silverman4c7235a2021-11-17 19:04:37 -0800317 standard_library = "{standard_library}",
318 static_libstdcxx = {static_libstdcxx},
319 conlyopts = {conlyopts},
320 cxxopts = {cxxopts},
321 copts = {copts},
322 opt_copts = {opt_copts},
323 dbg_copts = {dbg_copts},
Brian Silverman1e7c8972022-02-03 23:15:41 -0800324 fastbuild_copts = {fastbuild_copts},
Brian Silverman4c7235a2021-11-17 19:04:37 -0800325 linkopts = {linkopts},
Brian Silverman7d89e282021-11-17 17:36:54 -0800326)
327
328toolchain(
329 name = "cc-toolchain-{suffix}",
330 exec_compatible_with = [
331 "@platforms//cpu:{host_arch}",
332 "@platforms//os:{host_os_bzl}",
333 ],
334 target_compatible_with = [
335 "@platforms//cpu:{target_arch}",
336 "@platforms//os:{target_os_bzl}",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800337 ] + {additional_target_compatible_with},
Brian Silverman7d89e282021-11-17 17:36:54 -0800338 toolchain = ":cc-clang-{suffix}",
339 toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
340)
341"""
342
343 if use_absolute_paths:
344 template = template + """
345cc_toolchain(
346 name = "cc-clang-{suffix}",
347 all_files = ":empty",
348 compiler_files = ":empty",
349 dwp_files = ":empty",
350 linker_files = ":empty",
351 objcopy_files = ":empty",
352 strip_files = ":empty",
353 toolchain_config = "local-{suffix}",
354)
355"""
356 else:
357 template = template + """
358filegroup(
359 name = "sysroot-components-{suffix}",
360 srcs = [{sysroot_label_str}],
361)
362
363filegroup(
364 name = "compiler-components-{suffix}",
365 srcs = [
366 "{toolchain_root}:clang",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800367 "{target_toolchain_root}:include",
Brian Silverman7d89e282021-11-17 17:36:54 -0800368 ":sysroot-components-{suffix}",
369 ],
370)
371
372filegroup(
373 name = "linker-components-{suffix}",
374 srcs = [
375 "{toolchain_root}:clang",
376 "{toolchain_root}:ld",
377 "{toolchain_root}:ar",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800378 "{target_toolchain_root}:lib",
Brian Silverman7d89e282021-11-17 17:36:54 -0800379 ":sysroot-components-{suffix}",
380 ],
381)
382
383filegroup(
384 name = "all-components-{suffix}",
385 srcs = [
386 "{toolchain_root}:bin",
387 ":compiler-components-{suffix}",
388 ":linker-components-{suffix}",
389 ],
390)
391
392filegroup(name = "all-files-{suffix}", srcs = [":all-components-{suffix}"{extra_files_str}])
393filegroup(name = "archiver-files-{suffix}", srcs = ["{toolchain_root}:ar"{extra_files_str}])
394filegroup(name = "assembler-files-{suffix}", srcs = ["{toolchain_root}:as"{extra_files_str}])
395filegroup(name = "compiler-files-{suffix}", srcs = [":compiler-components-{suffix}"{extra_files_str}])
396filegroup(name = "dwp-files-{suffix}", srcs = ["{toolchain_root}:dwp"{extra_files_str}])
397filegroup(name = "linker-files-{suffix}", srcs = [":linker-components-{suffix}"{extra_files_str}])
398filegroup(name = "objcopy-files-{suffix}", srcs = ["{toolchain_root}:objcopy"{extra_files_str}])
399filegroup(name = "strip-files-{suffix}", srcs = ["{toolchain_root}:strip"{extra_files_str}])
400
401cc_toolchain(
402 name = "cc-clang-{suffix}",
403 all_files = "all-files-{suffix}",
404 ar_files = "archiver-files-{suffix}",
405 as_files = "assembler-files-{suffix}",
406 compiler_files = "compiler-files-{suffix}",
407 dwp_files = "dwp-files-{suffix}",
408 linker_files = "linker-files-{suffix}",
409 objcopy_files = "objcopy-files-{suffix}",
410 strip_files = "strip-files-{suffix}",
411 toolchain_config = "local-{suffix}",
412)
413"""
414
415 return template.format(
416 suffix = suffix,
417 target_os = target_os,
418 target_arch = target_arch,
419 host_os = host_os,
420 host_arch = host_arch,
421 target_os_bzl = target_os_bzl,
422 host_os_bzl = host_os_bzl,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800423 additional_target_compatible_with = additional_target_compatible_with,
Brian Silverman7d89e282021-11-17 17:36:54 -0800424 toolchain_root = toolchain_info.toolchain_root,
425 toolchain_path_prefix = toolchain_info.toolchain_path_prefix,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800426 target_toolchain_root = target_toolchain_root,
427 target_toolchain_path_prefix = target_toolchain_path_prefix,
Brian Silverman7d89e282021-11-17 17:36:54 -0800428 tools_path_prefix = toolchain_info.tools_path_prefix,
429 wrapper_bin_prefix = toolchain_info.wrapper_bin_prefix,
430 additional_include_dirs_str = additional_include_dirs_str,
431 sysroot_label_str = sysroot_label_str,
432 sysroot_path = sysroot_path,
433 llvm_version = toolchain_info.llvm_version,
434 extra_files_str = extra_files_str,
435 host_tools_info = host_tools_info,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800436 standard_library = standard_library,
437 static_libstdcxx = toolchain_info.static_libstdcxx,
438 conlyopts = conlyopts,
439 cxxopts = cxxopts,
440 copts = copts,
441 opt_copts = opt_copts,
442 dbg_copts = dbg_copts,
Brian Silverman1e7c8972022-02-03 23:15:41 -0800443 fastbuild_copts = fastbuild_copts,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800444 linkopts = linkopts,
Brian Silverman7d89e282021-11-17 17:36:54 -0800445 )