Implement Bazel Clang toolchain
This commit is contained in:
113
bazel/clang_toolchain/config_detection.bzl
Normal file
113
bazel/clang_toolchain/config_detection.bzl
Normal file
@ -0,0 +1,113 @@
|
||||
# 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",
|
||||
),
|
||||
)
|
Reference in New Issue
Block a user