4d41304def
This can successfully build a C library: bazel build --config=clang //third_party:libpng This can build and run a statically-linked executable: bazel test --config=clang //:bazel_test For more verbose compile and linking output, add the `--features diagnostic` flag to a Bazel command (see _make_diagnostic_flags() in toolchain/clang_toolchain_config.bzl. Similarly, a `--features print_search_dirs` can be used to show where clang is looking for libraries etc to link against. These features are made available for easier debugging. Suggested review order: - Read https://docs.bazel.build/versions/4.2.1/tutorial/cc-toolchain-config.html if unfamiliar with setting up C++ toolchains in Bazel - .bazelrc and WORKSPACE.bazel that configure use and download of the toolchain (Clang 13, musl 1.2.2) - toolchain/build_toolchain.bzl which downloads and assembles the toolchain (w/o installing anything on the host machine) - toolchain/BUILD.bazel and toolchain/*trampoline.sh to see the setup of the toolchain rules. - toolchain/clang_toolchain_config.bzl to see the configuration of the toolchain. Pay special attention to the various command line flags that are set. - See that tools/bazel_test.cc has made a new home in experimental/bazel_test/bazel_test.cpp, with a companion BUILD.bazel. Note the addition of some function calls that test use of the C++ standard library. The number being used to test the PNG library is the latest and greatest that verifies we are compiling the one brought in via DEPS (and not a local one). - third_party/* to see how png (and its dependent zlib) have been built. Pay special attention to the musl_compat hack to fix static linking (any idea what the real cause is?) - //BUILD.bazel to see definition of the bazel_test executable. Change-Id: I7b0922d0d45cb9be8df2fd5fa5a1f48492654d5f Bug: skia:12541 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/461178 Reviewed-by: Ben Wagner <bungeman@google.com> Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
327 lines
12 KiB
Python
327 lines
12 KiB
Python
"""
|
|
This file specifies a clang toolchain that can run on a Linux host which does depend on any
|
|
installed packages from the host machine.
|
|
|
|
See build_toolchain.bzl for more details on the creation of the toolchain.
|
|
|
|
It uses the usr subfolder of the built toolchain as a sysroot
|
|
|
|
It follows the example of:
|
|
- https://docs.bazel.build/versions/4.2.1/tutorial/cc-toolchain-config.html
|
|
- https://github.com/emscripten-core/emsdk/blob/7f39d100d8cd207094decea907121df72065517e/bazel/emscripten_toolchain/crosstool.bzl
|
|
"""
|
|
|
|
load(
|
|
"@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
|
|
"action_config",
|
|
"feature",
|
|
"flag_group",
|
|
"flag_set",
|
|
"tool",
|
|
"variable_with_value",
|
|
)
|
|
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
|
|
|
|
# The location of the created clang toolchain.
|
|
EXTERNAL_TOOLCHAIN = "external/clang_linux_amd64_musl"
|
|
|
|
def _clang_impl(ctx):
|
|
action_configs = _make_action_configs()
|
|
features = []
|
|
features += _make_default_flags()
|
|
features += _make_diagnostic_flags()
|
|
|
|
# https://docs.bazel.build/versions/main/skylark/lib/cc_common.html#create_cc_toolchain_config_info
|
|
# Note, this rule is defined in Java code, not Starlark
|
|
# https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java
|
|
return cc_common.create_cc_toolchain_config_info(
|
|
ctx = ctx,
|
|
features = features,
|
|
abi_libc_version = "unknown",
|
|
abi_version = "unknown",
|
|
action_configs = action_configs,
|
|
builtin_sysroot = EXTERNAL_TOOLCHAIN + "/usr",
|
|
compiler = "clang",
|
|
host_system_name = "local",
|
|
target_cpu = "k8",
|
|
target_libc = "musl",
|
|
target_system_name = "local",
|
|
toolchain_identifier = "clang-toolchain",
|
|
)
|
|
|
|
provide_clang_toolchain_config = rule(
|
|
attrs = {},
|
|
provides = [CcToolchainConfigInfo],
|
|
implementation = _clang_impl,
|
|
)
|
|
|
|
def _make_action_configs():
|
|
"""
|
|
This function sets up the tools needed to perform the various compile/link actions.
|
|
|
|
Bazel normally restricts us to referring to (and therefore running) executables/scripts
|
|
that are in this directory (That is EXEC_ROOT/toolchain). However, the executables we want
|
|
to run are brought in via WORKSPACE.bazel and are located in EXEC_ROOT/external/clang....
|
|
Therefore, we make use of "trampoline scripts" that will call the binaries from the
|
|
toolchain directory.
|
|
|
|
These action_configs also let us dynamically specify arguments from the Bazel
|
|
environment if necessary (see cpp_link_static_library_action).
|
|
"""
|
|
|
|
# https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=435;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da
|
|
clang_tool = tool(path = "clang_trampoline.sh")
|
|
lld_tool = tool(path = "lld_trampoline.sh")
|
|
ar_tool = tool(path = "ar_trampoline.sh")
|
|
|
|
# https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=488;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da
|
|
assemble_action = action_config(
|
|
action_name = ACTION_NAMES.assemble,
|
|
tools = [clang_tool],
|
|
)
|
|
c_compile_action = action_config(
|
|
action_name = ACTION_NAMES.c_compile,
|
|
tools = [clang_tool],
|
|
)
|
|
cpp_compile_action = action_config(
|
|
action_name = ACTION_NAMES.cpp_compile,
|
|
tools = [clang_tool],
|
|
)
|
|
linkstamp_compile_action = action_config(
|
|
action_name = ACTION_NAMES.linkstamp_compile,
|
|
tools = [clang_tool],
|
|
)
|
|
preprocess_assemble_action = action_config(
|
|
action_name = ACTION_NAMES.preprocess_assemble,
|
|
tools = [clang_tool],
|
|
)
|
|
|
|
cpp_link_dynamic_library_action = action_config(
|
|
action_name = ACTION_NAMES.cpp_link_dynamic_library,
|
|
tools = [lld_tool],
|
|
)
|
|
cpp_link_executable_action = action_config(
|
|
action_name = ACTION_NAMES.cpp_link_executable,
|
|
# Bazel assumes it is talking to clang when building an executable. There are
|
|
# "-Wl" flags on the command: https://releases.llvm.org/6.0.1/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-Wl
|
|
tools = [clang_tool],
|
|
)
|
|
cpp_link_nodeps_dynamic_library_action = action_config(
|
|
action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library,
|
|
tools = [lld_tool],
|
|
)
|
|
|
|
# This is the same rule as
|
|
# https://github.com/emscripten-core/emsdk/blob/7f39d100d8cd207094decea907121df72065517e/bazel/emscripten_toolchain/crosstool.bzl#L143
|
|
# By default, there are no flags or libraries passed to the llvm-ar tool, so
|
|
# we need to specify them. The variables mentioned by expand_if_available are defined
|
|
# https://docs.bazel.build/versions/main/cc-toolchain-config-reference.html#cctoolchainconfiginfo-build-variables
|
|
cpp_link_static_library_action = action_config(
|
|
action_name = ACTION_NAMES.cpp_link_static_library,
|
|
flag_sets = [
|
|
flag_set(
|
|
flag_groups = [
|
|
flag_group(
|
|
# https://llvm.org/docs/CommandGuide/llvm-ar.html
|
|
# replace existing files or insert them if they already exist,
|
|
# create the file if it doesn't already exist
|
|
# symbol table should be added
|
|
# Deterministic timestamps should be used
|
|
flags = ["rcsD", "%{output_execpath}"],
|
|
# Despite the name, output_execpath just refers to linker output,
|
|
# e.g. libFoo.a
|
|
expand_if_available = "output_execpath",
|
|
),
|
|
],
|
|
),
|
|
flag_set(
|
|
flag_groups = [
|
|
flag_group(
|
|
iterate_over = "libraries_to_link",
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = ["%{libraries_to_link.name}"],
|
|
expand_if_equal = variable_with_value(
|
|
name = "libraries_to_link.type",
|
|
value = "object_file",
|
|
),
|
|
),
|
|
flag_group(
|
|
flags = ["%{libraries_to_link.object_files}"],
|
|
iterate_over = "libraries_to_link.object_files",
|
|
expand_if_equal = variable_with_value(
|
|
name = "libraries_to_link.type",
|
|
value = "object_file_group",
|
|
),
|
|
),
|
|
],
|
|
expand_if_available = "libraries_to_link",
|
|
),
|
|
],
|
|
),
|
|
flag_set(
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = ["@%{linker_param_file}"],
|
|
expand_if_available = "linker_param_file",
|
|
),
|
|
],
|
|
),
|
|
],
|
|
tools = [ar_tool],
|
|
)
|
|
|
|
action_configs = [
|
|
assemble_action,
|
|
c_compile_action,
|
|
cpp_compile_action,
|
|
cpp_link_dynamic_library_action,
|
|
cpp_link_executable_action,
|
|
cpp_link_nodeps_dynamic_library_action,
|
|
cpp_link_static_library_action,
|
|
linkstamp_compile_action,
|
|
preprocess_assemble_action,
|
|
]
|
|
return action_configs
|
|
|
|
def _make_default_flags():
|
|
"""Here we define the flags for certain actions that are always applied."""
|
|
cxx_compile_includes = flag_set(
|
|
actions = [
|
|
ACTION_NAMES.c_compile,
|
|
ACTION_NAMES.cpp_compile,
|
|
],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
# THIS ORDER MATTERS GREATLY. If these are in the wrong order, the
|
|
# #include_next directives will walk off the end of the specified system
|
|
# folders here and look in the absolute path that happens to contain
|
|
# the clang executable. Because that looks like an absolute path to
|
|
# Bazel, it will declare the Build is not properly specified (that is,
|
|
# it appears to use headers outside of Bazel's control/view) and fail.
|
|
"-isystem",
|
|
EXTERNAL_TOOLCHAIN + "/include/c++/v1",
|
|
"-isystem",
|
|
EXTERNAL_TOOLCHAIN + "/lib/clang/13.0.0/include",
|
|
"-isystem",
|
|
EXTERNAL_TOOLCHAIN + "/usr/include/x86_64-linux-musl",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
cpp_compile_includes = flag_set(
|
|
actions = [
|
|
ACTION_NAMES.cpp_compile,
|
|
],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
"-std=c++14",
|
|
# This define allows libc++ to work with musl. They were discovered by
|
|
# trying to compile without them, reading errors and source code, e.g.
|
|
# https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__locale#L513
|
|
# https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__config#L1155
|
|
# https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__support/musl/xlocale.h
|
|
"-D_LIBCPP_HAS_MUSL_LIBC",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
link_exe_flags = flag_set(
|
|
actions = [ACTION_NAMES.cpp_link_executable],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
"-fuse-ld=lld",
|
|
# This is the path to libc.a and other libraries.
|
|
"-L" + EXTERNAL_TOOLCHAIN + "/usr/lib/x86_64-linux-musl",
|
|
"-L" + EXTERNAL_TOOLCHAIN + "/lib",
|
|
# We chose to use the llvm runtime, not the gcc one because it is already
|
|
# included in the clang binary
|
|
"--rtlib=compiler-rt",
|
|
# In order to run our executables, they need to be statically linked,
|
|
# otherwise, the libc++.so and friends will not be found if they are
|
|
# not installed on the user's machine.
|
|
"-static",
|
|
"-std=c++14",
|
|
"-lc++abi",
|
|
"-lunwind",
|
|
"-lc++",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
return [feature(
|
|
"default_flags",
|
|
enabled = True,
|
|
flag_sets = [
|
|
cxx_compile_includes,
|
|
cpp_compile_includes,
|
|
link_exe_flags,
|
|
],
|
|
)]
|
|
|
|
def _make_diagnostic_flags():
|
|
"""Here we define the flags that can be turned on via features to yield debug info."""
|
|
cxx_diagnostic = flag_set(
|
|
actions = [
|
|
ACTION_NAMES.c_compile,
|
|
ACTION_NAMES.cpp_compile,
|
|
],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
"--trace-includes",
|
|
"-v",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
link_diagnostic = flag_set(
|
|
actions = [ACTION_NAMES.cpp_link_executable],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
"-Wl,--verbose",
|
|
"-v",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
link_search_dirs = flag_set(
|
|
actions = [ACTION_NAMES.cpp_link_executable],
|
|
flag_groups = [
|
|
flag_group(
|
|
flags = [
|
|
"--print-search-dirs",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
return [
|
|
# Running a Bazel command with --features diagnostic will cause the compilation and
|
|
# link steps to be more verbose.
|
|
feature(
|
|
"diagnostic",
|
|
enabled = False,
|
|
flag_sets = [
|
|
cxx_diagnostic,
|
|
link_diagnostic,
|
|
],
|
|
),
|
|
# Running a Bazel command with --features print_search_dirs will cause the link to fail
|
|
# but directories searched for libraries, etc will be displayed.
|
|
feature(
|
|
"print_search_dirs",
|
|
enabled = False,
|
|
flag_sets = [
|
|
link_search_dirs,
|
|
],
|
|
),
|
|
]
|