blob: 6a183fc648250cad0e2b11b73bce7341ae4b11e5 [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,
134 linkopts_dict = rctx.attr.linkopts,
Brian Silverman7d89e282021-11-17 17:36:54 -0800135 )
136 host_tools_info = dict([
137 pair
138 for (key, tool_path, features) in [
139 # This is used for macOS hosts:
140 ("libtool", "/usr/bin/libtool", [_host_tool_features.SUPPORTS_ARG_FILE]),
141 # This is used with old (pre 7) LLVM versions:
142 ("strip", "/usr/bin/strip", []),
143 # This is used when lld doesn't support the target platform (i.e.
144 # Mach-O for macOS):
145 ("ld", "/usr/bin/ld", []),
146 ]
147 for pair in _host_tools.get_tool_info(rctx, tool_path, features, key).items()
148 ])
149 cc_toolchains_str, toolchain_labels_str = _cc_toolchains_str(
150 workspace_name,
151 toolchain_info,
152 use_absolute_paths,
153 host_tools_info,
154 )
155
156 # Convenience macro to register all generated toolchains.
157 rctx.template(
158 "toolchains.bzl",
159 Label("//toolchain:toolchains.bzl.tpl"),
160 {
161 "%{toolchain_labels}": toolchain_labels_str,
162 },
163 )
164
165 # BUILD file with all the generated toolchain definitions.
166 rctx.template(
167 "BUILD.bazel",
168 Label("//toolchain:BUILD.toolchain.tpl"),
169 {
170 "%{cc_toolchains}": cc_toolchains_str,
171 "%{cc_toolchain_config_bzl}": str(rctx.attr._cc_toolchain_config_bzl),
172 },
173 )
174
175 # CC wrapper script; see comments near the definition of `wrapper_bin_prefix`.
176 if os == "darwin":
177 cc_wrapper_tpl = "//toolchain:osx_cc_wrapper.sh.tpl"
178 else:
179 cc_wrapper_tpl = "//toolchain:cc_wrapper.sh.tpl"
180 rctx.template(
181 "bin/cc_wrapper.sh",
182 Label(cc_wrapper_tpl),
183 {
184 "%{toolchain_path_prefix}": toolchain_path_prefix,
185 },
186 )
187
188 # libtool wrapper; used if the host libtool doesn't support arg files:
189 rctx.template(
190 "bin/host_libtool_wrapper.sh",
191 Label("//toolchain:host_libtool_wrapper.sh.tpl"),
192 {
193 "%{libtool_path}": "/usr/bin/libtool",
194 },
195 )
196
197def _cc_toolchains_str(
198 workspace_name,
199 toolchain_info,
200 use_absolute_paths,
201 host_tools_info):
202 # Since all the toolchains rely on downloading the right LLVM toolchain for
203 # the host architecture, we don't need to explicitly specify
204 # `exec_compatible_with` attribute. If the host and execution platform are
205 # not the same, then host auto-detection based LLVM download does not work
206 # and the user has to explicitly specify the distribution of LLVM they
207 # want.
208
209 # Note that for cross-compiling, the toolchain configuration will need
210 # appropriate sysroots. A recommended approach is to configure two
211 # `llvm_toolchain` repos, one without sysroots (for easy single platform
212 # builds) and register this one, and one with sysroots and provide
213 # `--extra_toolchains` flag when cross-compiling.
214
215 cc_toolchains_str = ""
216 toolchain_names = []
217 for (target_os, target_arch) in _supported_targets:
218 suffix = "{}-{}".format(target_arch, target_os)
219 cc_toolchain_str = _cc_toolchain_str(
220 suffix,
221 target_os,
222 target_arch,
223 toolchain_info,
224 use_absolute_paths,
225 host_tools_info,
226 )
227 if cc_toolchain_str:
228 cc_toolchains_str = cc_toolchains_str + cc_toolchain_str
229 toolchain_name = "@{}//:cc-toolchain-{}".format(workspace_name, suffix)
230 toolchain_names.append(toolchain_name)
231
232 sep = ",\n" + " " * 8 # 2 tabs with tabstop=4.
233 toolchain_labels_str = sep.join(["\"{}\"".format(d) for d in toolchain_names])
234 return cc_toolchains_str, toolchain_labels_str
235
236def _cc_toolchain_str(
237 suffix,
238 target_os,
239 target_arch,
240 toolchain_info,
241 use_absolute_paths,
242 host_tools_info):
243 host_os = toolchain_info.os
244 host_arch = toolchain_info.arch
245
246 host_os_bzl = _os_bzl(host_os)
247 target_os_bzl = _os_bzl(target_os)
248
249 sysroot_path, sysroot = _sysroot_path(
250 toolchain_info.sysroot_dict,
251 target_os,
252 target_arch,
253 )
254 if not sysroot_path:
255 if host_os == target_os and host_arch == target_arch:
256 # For darwin -> darwin, we can use the macOS SDK path.
257 sysroot_path = toolchain_info.default_sysroot_path
258 else:
259 # We are trying to cross-compile without a sysroot, let's bail.
260 # TODO: Are there situations where we can continue?
261 return ""
262
263 extra_files_str = ", \":llvm\", \":wrapper-files\""
264
Brian Silverman4c7235a2021-11-17 19:04:37 -0800265 key = _os_arch_pair(target_os, target_arch)
266 additional_include_dirs = toolchain_info.additional_include_dirs_dict.get(key)
Brian Silverman7d89e282021-11-17 17:36:54 -0800267 additional_include_dirs_str = "[]"
268 if additional_include_dirs:
269 additional_include_dirs_str = "[{}]".format(
270 ", ".join(["\"{}\"".format(d) for d in additional_include_dirs]),
271 )
272
273 sysroot_label_str = "\"%s\"" % str(sysroot) if sysroot else ""
274
275 # `struct` isn't allowed in `BUILD` files so we JSON encode + decode to turn
276 # them into `dict`s.
277 host_tools_info = json.decode(json.encode(host_tools_info))
278
Brian Silverman4c7235a2021-11-17 19:04:37 -0800279 standard_library = toolchain_info.standard_libraries_dict.get(key, "")
280 conlyopts = toolchain_info.conlyopts_dict.get(key, [])
281 cxxopts = toolchain_info.cxxopts_dict.get(key, [])
282 copts = toolchain_info.copts_dict.get(key, [])
283 opt_copts = toolchain_info.opt_copts_dict.get(key, [])
284 dbg_copts = toolchain_info.dbg_copts_dict.get(key, [])
285 linkopts = toolchain_info.linkopts_dict.get(key, [])
286 target_toolchain_root = toolchain_info.toolchain_root
287 if key in toolchain_info.target_toolchain_roots_dict:
288 target_toolchain_root = toolchain_info.target_toolchain_roots_dict[key]
289 elif "" in toolchain_info.target_toolchain_roots_dict:
290 target_toolchain_root = toolchain_info.target_toolchain_roots_dict[""]
291 target_toolchain_path_prefix = toolchain_info.toolchain_path_prefix
292 if key in toolchain_info.target_toolchain_path_prefixes_dict:
293 target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[key]
294 elif "" in toolchain_info.target_toolchain_roots_dict:
295 target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[""]
296 additional_target_compatible_with = toolchain_info.additional_target_compatible_with_dict.get(key, [])
297
Brian Silverman7d89e282021-11-17 17:36:54 -0800298 template = """
299# CC toolchain for cc-clang-{suffix}.
300
301cc_toolchain_config(
302 name = "local-{suffix}",
303 host_arch = "{host_arch}",
304 host_os = "{host_os}",
305 target_arch = "{target_arch}",
306 target_os = "{target_os}",
307 toolchain_path_prefix = "{toolchain_path_prefix}",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800308 target_toolchain_path_prefix = "{target_toolchain_path_prefix}",
Brian Silverman7d89e282021-11-17 17:36:54 -0800309 tools_path_prefix = "{tools_path_prefix}",
310 wrapper_bin_prefix = "{wrapper_bin_prefix}",
311 sysroot_path = "{sysroot_path}",
312 additional_include_dirs = {additional_include_dirs_str},
313 llvm_version = "{llvm_version}",
314 host_tools_info = {host_tools_info},
Brian Silverman4c7235a2021-11-17 19:04:37 -0800315 standard_library = "{standard_library}",
316 static_libstdcxx = {static_libstdcxx},
317 conlyopts = {conlyopts},
318 cxxopts = {cxxopts},
319 copts = {copts},
320 opt_copts = {opt_copts},
321 dbg_copts = {dbg_copts},
322 linkopts = {linkopts},
Brian Silverman7d89e282021-11-17 17:36:54 -0800323)
324
325toolchain(
326 name = "cc-toolchain-{suffix}",
327 exec_compatible_with = [
328 "@platforms//cpu:{host_arch}",
329 "@platforms//os:{host_os_bzl}",
330 ],
331 target_compatible_with = [
332 "@platforms//cpu:{target_arch}",
333 "@platforms//os:{target_os_bzl}",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800334 ] + {additional_target_compatible_with},
Brian Silverman7d89e282021-11-17 17:36:54 -0800335 toolchain = ":cc-clang-{suffix}",
336 toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
337)
338"""
339
340 if use_absolute_paths:
341 template = template + """
342cc_toolchain(
343 name = "cc-clang-{suffix}",
344 all_files = ":empty",
345 compiler_files = ":empty",
346 dwp_files = ":empty",
347 linker_files = ":empty",
348 objcopy_files = ":empty",
349 strip_files = ":empty",
350 toolchain_config = "local-{suffix}",
351)
352"""
353 else:
354 template = template + """
355filegroup(
356 name = "sysroot-components-{suffix}",
357 srcs = [{sysroot_label_str}],
358)
359
360filegroup(
361 name = "compiler-components-{suffix}",
362 srcs = [
363 "{toolchain_root}:clang",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800364 "{target_toolchain_root}:include",
Brian Silverman7d89e282021-11-17 17:36:54 -0800365 ":sysroot-components-{suffix}",
366 ],
367)
368
369filegroup(
370 name = "linker-components-{suffix}",
371 srcs = [
372 "{toolchain_root}:clang",
373 "{toolchain_root}:ld",
374 "{toolchain_root}:ar",
Brian Silverman4c7235a2021-11-17 19:04:37 -0800375 "{target_toolchain_root}:lib",
Brian Silverman7d89e282021-11-17 17:36:54 -0800376 ":sysroot-components-{suffix}",
377 ],
378)
379
380filegroup(
381 name = "all-components-{suffix}",
382 srcs = [
383 "{toolchain_root}:bin",
384 ":compiler-components-{suffix}",
385 ":linker-components-{suffix}",
386 ],
387)
388
389filegroup(name = "all-files-{suffix}", srcs = [":all-components-{suffix}"{extra_files_str}])
390filegroup(name = "archiver-files-{suffix}", srcs = ["{toolchain_root}:ar"{extra_files_str}])
391filegroup(name = "assembler-files-{suffix}", srcs = ["{toolchain_root}:as"{extra_files_str}])
392filegroup(name = "compiler-files-{suffix}", srcs = [":compiler-components-{suffix}"{extra_files_str}])
393filegroup(name = "dwp-files-{suffix}", srcs = ["{toolchain_root}:dwp"{extra_files_str}])
394filegroup(name = "linker-files-{suffix}", srcs = [":linker-components-{suffix}"{extra_files_str}])
395filegroup(name = "objcopy-files-{suffix}", srcs = ["{toolchain_root}:objcopy"{extra_files_str}])
396filegroup(name = "strip-files-{suffix}", srcs = ["{toolchain_root}:strip"{extra_files_str}])
397
398cc_toolchain(
399 name = "cc-clang-{suffix}",
400 all_files = "all-files-{suffix}",
401 ar_files = "archiver-files-{suffix}",
402 as_files = "assembler-files-{suffix}",
403 compiler_files = "compiler-files-{suffix}",
404 dwp_files = "dwp-files-{suffix}",
405 linker_files = "linker-files-{suffix}",
406 objcopy_files = "objcopy-files-{suffix}",
407 strip_files = "strip-files-{suffix}",
408 toolchain_config = "local-{suffix}",
409)
410"""
411
412 return template.format(
413 suffix = suffix,
414 target_os = target_os,
415 target_arch = target_arch,
416 host_os = host_os,
417 host_arch = host_arch,
418 target_os_bzl = target_os_bzl,
419 host_os_bzl = host_os_bzl,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800420 additional_target_compatible_with = additional_target_compatible_with,
Brian Silverman7d89e282021-11-17 17:36:54 -0800421 toolchain_root = toolchain_info.toolchain_root,
422 toolchain_path_prefix = toolchain_info.toolchain_path_prefix,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800423 target_toolchain_root = target_toolchain_root,
424 target_toolchain_path_prefix = target_toolchain_path_prefix,
Brian Silverman7d89e282021-11-17 17:36:54 -0800425 tools_path_prefix = toolchain_info.tools_path_prefix,
426 wrapper_bin_prefix = toolchain_info.wrapper_bin_prefix,
427 additional_include_dirs_str = additional_include_dirs_str,
428 sysroot_label_str = sysroot_label_str,
429 sysroot_path = sysroot_path,
430 llvm_version = toolchain_info.llvm_version,
431 extra_files_str = extra_files_str,
432 host_tools_info = host_tools_info,
Brian Silverman4c7235a2021-11-17 19:04:37 -0800433 standard_library = standard_library,
434 static_libstdcxx = toolchain_info.static_libstdcxx,
435 conlyopts = conlyopts,
436 cxxopts = cxxopts,
437 copts = copts,
438 opt_copts = opt_copts,
439 dbg_copts = dbg_copts,
440 linkopts = linkopts,
Brian Silverman7d89e282021-11-17 17:36:54 -0800441 )