4a42b46a99
Sometimes the launcher fails to compile with the following error messsage: ``` error: FileNotFound ``` We cannot reproduce this in a controlled environment, but see it happening in the wild often enough to receive repeated questions. Since this has been escalated to Zig Software Foundation, the most meaningful thing we can ask our users to do is apply a workaround and wait. Let's do just that.
337 lines
12 KiB
Python
337 lines
12 KiB
Python
load("@bazel_skylib//lib:paths.bzl", "paths")
|
|
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
|
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "read_user_netrc", "use_netrc")
|
|
load("@bazel-zig-cc//toolchain/private:defs.bzl", "target_structs", "zig_tool_path")
|
|
|
|
# Directories that `zig c++` includes behind the scenes.
|
|
_DEFAULT_INCLUDE_DIRECTORIES = [
|
|
"libcxx/include",
|
|
"libcxxabi/include",
|
|
"libunwind/include",
|
|
]
|
|
|
|
# Official recommended version. Should use this when we have a usable release.
|
|
URL_FORMAT_RELEASE = "https://ziglang.org/download/{version}/zig-{host_platform}-{version}.{_ext}"
|
|
|
|
# Caution: nightly releases are purged from ziglang.org after ~90 days. A real
|
|
# solution would be to allow the downstream project specify their own mirrors.
|
|
# This is explained in
|
|
# https://sr.ht/~motiejus/bazel-zig-cc/#alternative-download-urls and is
|
|
# awaiting my attention or your contribution.
|
|
URL_FORMAT_NIGHTLY = "https://ziglang.org/builds/zig-{host_platform}-{version}.{_ext}"
|
|
|
|
# Official Bazel's mirror with selected Zig SDK versions. Bazel community is
|
|
# generous enough to host the artifacts, which we use.
|
|
URL_FORMAT_BAZELMIRROR = "https://mirror.bazel.build/" + URL_FORMAT_NIGHTLY.lstrip("https://")
|
|
|
|
_VERSION = "0.11.0-dev.1796+c9e02d3e6"
|
|
|
|
_HOST_PLATFORM_SHA256 = {
|
|
"linux-aarch64": "5902b34b463635b25c11555650d095eb5030e2a05d8a4570c091313cd1a38b12",
|
|
"linux-x86_64": "aa9da2305fad89f648db2fd1fade9f0f9daf01d06f3b07887ad3098402794778",
|
|
"macos-aarch64": "51b4e88123d6cbb102f2a6665dd0d61467341f36b07bb0a8d46a37ea367b60d5",
|
|
"macos-x86_64": "dd8eeae5249aa21f9e51ff4ff536a3e7bf2c0686ee78bf6032d18e74c8416c56",
|
|
"windows-x86_64": "260f34d0d5312d2642097bb33c14ac552cd57c59a15383364df6764d01f0bfc9",
|
|
}
|
|
|
|
_HOST_PLATFORM_EXT = {
|
|
"linux-aarch64": "tar.xz",
|
|
"linux-x86_64": "tar.xz",
|
|
"macos-aarch64": "tar.xz",
|
|
"macos-x86_64": "tar.xz",
|
|
"windows-x86_64": "zip",
|
|
}
|
|
|
|
_compile_failed = """
|
|
Compilation of launcher.zig failed:
|
|
command={compile_cmd}
|
|
return_code={return_code}
|
|
stderr={stderr}
|
|
stdout={stdout}
|
|
|
|
You most likely hit a rare but known race in Zig SDK. Congratulations?
|
|
|
|
We are working on fixing it with Zig Software Foundation. If you are curious,
|
|
feel free to follow along in https://github.com/ziglang/zig/issues/14815
|
|
|
|
There isn't much to do now but wait. Now apply the following workaround:
|
|
$ rm -fr {cache_prefix}
|
|
$ <... re-run your command ...>
|
|
|
|
... and proceed with your life.
|
|
"""
|
|
|
|
def toolchains(
|
|
version = _VERSION,
|
|
url_formats = [URL_FORMAT_BAZELMIRROR, URL_FORMAT_NIGHTLY],
|
|
host_platform_sha256 = _HOST_PLATFORM_SHA256,
|
|
host_platform_ext = _HOST_PLATFORM_EXT):
|
|
"""
|
|
Download zig toolchain and declare bazel toolchains.
|
|
The platforms are not registered automatically, that should be done by
|
|
the user with register_toolchains() in the WORKSPACE file. See README
|
|
for possible choices.
|
|
"""
|
|
zig_repository(
|
|
name = "zig_sdk",
|
|
version = version,
|
|
url_formats = url_formats,
|
|
host_platform_sha256 = host_platform_sha256,
|
|
host_platform_ext = host_platform_ext,
|
|
)
|
|
|
|
_ZIG_TOOLS = [
|
|
"c++",
|
|
"ar",
|
|
]
|
|
|
|
_template_mapfile = """
|
|
%s {
|
|
%s;
|
|
};
|
|
"""
|
|
|
|
_template_linker = """
|
|
#ifdef __ASSEMBLER__
|
|
.symver {from_function}, {to_function_abi}
|
|
#else
|
|
__asm__(".symver {from_function}, {to_function_abi}");
|
|
#endif
|
|
"""
|
|
|
|
def _glibc_hack(from_function, to_function_abi):
|
|
# Cannot use .format(...) here, because starlark thinks
|
|
# that the byte 3 (the opening brace on the first line)
|
|
# is a nested { ... }, returning an error:
|
|
# Error in format: Nested replacement fields are not supported
|
|
to_function, to_abi = to_function_abi.split("@")
|
|
mapfile = _template_mapfile % (to_abi, to_function)
|
|
header = _template_linker.format(
|
|
from_function = from_function,
|
|
to_function_abi = to_function_abi,
|
|
)
|
|
return struct(
|
|
mapfile = mapfile,
|
|
header = header,
|
|
)
|
|
|
|
def _quote(s):
|
|
return "'" + s.replace("'", "'\\''") + "'"
|
|
|
|
def _zig_repository_impl(repository_ctx):
|
|
arch = repository_ctx.os.arch
|
|
if arch == "amd64":
|
|
arch = "x86_64"
|
|
|
|
os = repository_ctx.os.name.lower()
|
|
if os.startswith("mac os"):
|
|
os = "macos"
|
|
|
|
if os.startswith("windows"):
|
|
os = "windows"
|
|
|
|
host_platform = "{}-{}".format(os, arch)
|
|
|
|
zig_sha256 = repository_ctx.attr.host_platform_sha256[host_platform]
|
|
zig_ext = repository_ctx.attr.host_platform_ext[host_platform]
|
|
format_vars = {
|
|
"_ext": zig_ext,
|
|
"version": repository_ctx.attr.version,
|
|
"host_platform": host_platform,
|
|
}
|
|
|
|
# Fetch Label dependencies before doing download/extract.
|
|
# The Bazel docs are not very clear about this behavior but see:
|
|
# https://bazel.build/extending/repo#when_is_the_implementation_function_executed
|
|
# and a related rules_go PR:
|
|
# https://github.com/bazelbuild/bazel-gazelle/pull/1206
|
|
for dest, src in {
|
|
"platform/BUILD": "//toolchain/platform:BUILD",
|
|
"toolchain/BUILD": "//toolchain/toolchain:BUILD",
|
|
"libc/BUILD": "//toolchain/libc:BUILD",
|
|
"libc_aware/platform/BUILD": "//toolchain/libc_aware/platform:BUILD",
|
|
"libc_aware/toolchain/BUILD": "//toolchain/libc_aware/toolchain:BUILD",
|
|
}.items():
|
|
repository_ctx.symlink(Label(src), dest)
|
|
|
|
for dest, src in {
|
|
"BUILD": "//toolchain:BUILD.sdk.bazel",
|
|
# "private/BUILD": "//toolchain/private:BUILD.sdk.bazel",
|
|
}.items():
|
|
repository_ctx.template(
|
|
dest,
|
|
Label(src),
|
|
executable = False,
|
|
substitutions = {
|
|
"{zig_sdk_path}": _quote("external/zig_sdk"),
|
|
"{os}": _quote(os),
|
|
},
|
|
)
|
|
|
|
urls = [uf.format(**format_vars) for uf in repository_ctx.attr.url_formats]
|
|
repository_ctx.download_and_extract(
|
|
auth = use_netrc(read_user_netrc(repository_ctx), urls, {}),
|
|
url = urls,
|
|
stripPrefix = "zig-{host_platform}-{version}/".format(**format_vars),
|
|
sha256 = zig_sha256,
|
|
)
|
|
|
|
cache_prefix = repository_ctx.os.environ.get("BAZEL_ZIG_CC_CACHE_PREFIX", "")
|
|
if cache_prefix == "":
|
|
if os == "windows":
|
|
cache_prefix = "C:\\\\Temp\\\\bazel-zig-cc"
|
|
else:
|
|
cache_prefix = "/tmp/bazel-zig-cc"
|
|
|
|
repository_ctx.template(
|
|
"tools/launcher.zig",
|
|
Label("//toolchain:launcher.zig"),
|
|
executable = False,
|
|
substitutions = {
|
|
"{BAZEL_ZIG_CC_CACHE_PREFIX}": cache_prefix,
|
|
},
|
|
)
|
|
|
|
compile_env = {
|
|
"ZIG_LOCAL_CACHE_DIR": cache_prefix,
|
|
"ZIG_GLOBAL_CACHE_DIR": cache_prefix,
|
|
}
|
|
compile_cmd = [
|
|
paths.join("..", "zig"),
|
|
"build-exe",
|
|
"-OReleaseSafe",
|
|
"launcher.zig",
|
|
] + (["-static"] if os == "linux" else [])
|
|
|
|
ret = repository_ctx.execute(
|
|
compile_cmd,
|
|
working_directory = "tools",
|
|
environment = compile_env,
|
|
)
|
|
if ret.return_code != 0:
|
|
full_cmd = [k + "=" + v for k, v in compile_env.items()] + compile_cmd
|
|
fail(_compile_failed.format(
|
|
compile_cmd = " ".join(full_cmd),
|
|
return_code = ret.return_code,
|
|
stdout = ret.stdout,
|
|
stderr = ret.stderr,
|
|
cache_prefix = cache_prefix,
|
|
))
|
|
|
|
exe = ".exe" if os == "windows" else ""
|
|
for target_config in target_structs():
|
|
for zig_tool in _ZIG_TOOLS + target_config.tool_paths.values():
|
|
tool_path = zig_tool_path(os).format(
|
|
zig_tool = zig_tool,
|
|
zigtarget = target_config.zigtarget,
|
|
)
|
|
repository_ctx.symlink("tools/launcher{}".format(exe), tool_path)
|
|
|
|
fcntl_hack = _glibc_hack("fcntl64", "fcntl@GLIBC_2.2.5")
|
|
repository_ctx.file("glibc-hacks/fcntl.map", content = fcntl_hack.mapfile)
|
|
repository_ctx.file("glibc-hacks/fcntl.h", content = fcntl_hack.header)
|
|
res_search_amd64 = _glibc_hack("res_search", "__res_search@GLIBC_2.2.5")
|
|
repository_ctx.file("glibc-hacks/res_search-amd64.map", content = res_search_amd64.mapfile)
|
|
repository_ctx.file("glibc-hacks/res_search-amd64.h", content = res_search_amd64.header)
|
|
res_search_arm64 = _glibc_hack("res_search", "__res_search@GLIBC_2.17")
|
|
repository_ctx.file("glibc-hacks/res_search-arm64.map", content = res_search_arm64.mapfile)
|
|
repository_ctx.file("glibc-hacks/res_search-arm64.h", content = res_search_arm64.header)
|
|
|
|
zig_repository = repository_rule(
|
|
attrs = {
|
|
"version": attr.string(),
|
|
"host_platform_sha256": attr.string_dict(),
|
|
"url_formats": attr.string_list(allow_empty = False),
|
|
"host_platform_ext": attr.string_dict(),
|
|
},
|
|
environ = ["BAZEL_ZIG_CC_CACHE_PREFIX"],
|
|
implementation = _zig_repository_impl,
|
|
)
|
|
|
|
def filegroup(name, **kwargs):
|
|
native.filegroup(name = name, **kwargs)
|
|
return ":" + name
|
|
|
|
def declare_files(os):
|
|
filegroup(name = "all", srcs = native.glob(["**"]))
|
|
filegroup(name = "empty")
|
|
if os == "windows":
|
|
native.exports_files(["zig.exe"], visibility = ["//visibility:public"])
|
|
native.alias(name = "zig", actual = ":zig.exe")
|
|
else:
|
|
native.exports_files(["zig"], visibility = ["//visibility:public"])
|
|
filegroup(name = "lib/std", srcs = native.glob(["lib/std/**"]))
|
|
lazy_filegroups = {}
|
|
|
|
for target_config in target_structs():
|
|
all_includes = [native.glob(["lib/{}/**".format(i)]) for i in target_config.includes]
|
|
all_includes.append(getattr(target_config, "compiler_extra_includes", []))
|
|
|
|
cxx_tool_label = ":" + zig_tool_path(os).format(
|
|
zig_tool = "c++",
|
|
zigtarget = target_config.zigtarget,
|
|
)
|
|
|
|
filegroup(
|
|
name = "{}_includes".format(target_config.zigtarget),
|
|
srcs = _flatten(all_includes),
|
|
)
|
|
|
|
filegroup(
|
|
name = "{}_compiler_files".format(target_config.zigtarget),
|
|
srcs = [
|
|
":zig",
|
|
":{}_includes".format(target_config.zigtarget),
|
|
cxx_tool_label,
|
|
],
|
|
)
|
|
|
|
filegroup(
|
|
name = "{}_linker_files".format(target_config.zigtarget),
|
|
srcs = [
|
|
":zig",
|
|
":{}_includes".format(target_config.zigtarget),
|
|
cxx_tool_label,
|
|
] + native.glob([
|
|
"lib/libc/{}/**".format(target_config.libc),
|
|
"lib/libcxx/**",
|
|
"lib/libcxxabi/**",
|
|
"lib/libunwind/**",
|
|
"lib/compiler_rt/**",
|
|
"lib/std/**",
|
|
"lib/*.zig",
|
|
"lib/*.h",
|
|
]),
|
|
)
|
|
|
|
filegroup(
|
|
name = "{}_ar_files".format(target_config.zigtarget),
|
|
srcs = [
|
|
":zig",
|
|
":" + zig_tool_path(os).format(
|
|
zig_tool = "ar",
|
|
zigtarget = target_config.zigtarget,
|
|
),
|
|
],
|
|
)
|
|
|
|
filegroup(
|
|
name = "{}_all_files".format(target_config.zigtarget),
|
|
srcs = [
|
|
":{}_linker_files".format(target_config.zigtarget),
|
|
":{}_compiler_files".format(target_config.zigtarget),
|
|
":{}_ar_files".format(target_config.zigtarget),
|
|
],
|
|
)
|
|
|
|
for d in _DEFAULT_INCLUDE_DIRECTORIES + target_config.includes:
|
|
d = "lib/" + d
|
|
if d not in lazy_filegroups:
|
|
lazy_filegroups[d] = filegroup(name = d, srcs = native.glob([d + "/**"]))
|
|
|
|
def _flatten(iterable):
|
|
result = []
|
|
for element in iterable:
|
|
result += element
|
|
return result
|