Files
asl/bazel/clang_toolchain/config_detection.bzl

114 lines
3.2 KiB
Python

# Copyright 2025 Steven Le Rouzic
#
# SPDX-License-Identifier: BSD-3-Clause
def _copy_file(ctx, from_path, to_path):
content = ctx.read(from_path)
ctx.file(to_path, content = content)
def _get_clang_info(ctx, clang_path, line_prefix):
result = ctx.execute([clang_path, "--version"])
if result.return_code != 0:
return None
for l in result.stdout.splitlines():
if l.startswith(line_prefix):
l = l[len(line_prefix):]
return l.split(" ")[0]
return None
def _get_clang_version(ctx, clang_path):
return _get_clang_info(ctx, clang_path, "clang version ")
def _get_clang_lib_dir(ctx, clang_path):
result = ctx.execute([clang_path, "-no-canonical-prefixes", "--print-resource-dir"])
if result.return_code != 0:
return None
return result.stdout
def _get_include_dirs(ctx, clang_path):
ctx.file("detect.cpp", content = "")
detect_path = ctx.path("detect.cpp")
res = ctx.execute([
clang_path,
"-v",
"-no-canonical-prefixes",
"-fsyntax-only",
"-x", "c++",
detect_path,
])
lines = res.stderr.splitlines()
listing_include_dirs = False
include_dirs = []
for l in lines:
if l.startswith("#include <...> search starts here:"):
listing_include_dirs = True
elif l.startswith("End of search list."):
listing_include_dirs = False
elif listing_include_dirs:
include_dirs.append(l.strip())
return include_dirs
def _impl(ctx):
_copy_file(ctx, ctx.attr._build_bazel, "BUILD.bazel")
_copy_file(ctx, ctx.attr._toolchain_config_bzl, "toolchain_config.bzl")
clang_path = ctx.which("clang")
if not clang_path:
fail("Could not find clang")
clang_version = _get_clang_version(ctx, clang_path)
if not clang_version:
fail("Could not detect clang version")
clang_lib_dir = _get_clang_lib_dir(ctx, clang_path)
if not clang_lib_dir:
fail("Could not detect clang lib dir")
include_dirs = _get_include_dirs(ctx, clang_path)
if not include_dirs:
fail("Could not detect include dirs")
ctx.template(
"clang_config.bzl",
ctx.attr._clang_config_bzl_tpl,
executable = False,
substitutions = {
"{CLANG_BINDIR}": str(clang_path.dirname),
"{CLANG_LIBDIR}": str(clang_lib_dir).strip().replace("\\", "/"),
"{CLANG_INCLUDE_DIRS}": str(include_dirs),
},
)
_config_detection = repository_rule(
implementation = _impl,
local = True,
configure = True,
attrs = {
"_build_bazel": attr.label(
default = Label("//bazel/clang_toolchain:clang_toolchain.BUILD.bazel"),
allow_single_file = True,
),
"_toolchain_config_bzl": attr.label(
default = Label("//bazel/clang_toolchain:toolchain_config.bzl"),
allow_single_file = True,
),
"_clang_config_bzl_tpl": attr.label(
default = Label("//bazel/clang_toolchain:clang_config.bzl.tpl"),
allow_single_file = True,
),
},
)
clang_toolchain = module_extension(
implementation = lambda ctx: _config_detection(
name = "clang_toolchain",
),
)