114 lines
3.2 KiB
Python
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",
|
|
),
|
|
)
|