Преглед изворни кода

Modify clang configuration to make llvm-15 work better. (#2186)

The debug flag change is discussed at https://github.com/llvm/llvm-project/issues/57637

This modifies the devcontainer Dockerfile to switch to an ubuntu and apt-based llvm-15. That was used in testing of these changes. The move away from brew is partly necessary if we want llvm-15, but also installs much faster (roughly 90s setup).

This was based in part on #1618
Jon Ross-Perkins пре 3 година
родитељ
комит
aba77b12b9

+ 30 - 12
.devcontainer/Dockerfile

@@ -2,19 +2,37 @@
 # Exceptions. See /LICENSE for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-ARG TAG=3.5.6
-FROM docker.io/homebrew/brew:${TAG}
+FROM ubuntu:22.04
 
-# Install libxcrypt using Homebrew.
-RUN brew install libxcrypt --overwrite
+# Install apt tools:
+#   git: Used by VS Code.
+#   golang: Used for Bazelisk and Buildifier.
+#   python3: For Carbon tools.
+#   gnupg, software-properties-common, wget: For llvm.sh.
+RUN apt-get update
+RUN apt-get install -y \
+  git \
+  gnupg \
+  golang \
+  python3-pip \
+  python3.9 \
+  software-properties-common \
+  wget
 
-# Install all other dependencies using Homebrew.
-RUN brew install bazelisk node python@3.9
+ENV PATH="/root/go/bin:${PATH}"
+# Bazelisk is used for Carbon builds.
+RUN go install github.com/bazelbuild/bazelisk@v1.14.0
+RUN ln -s /root/go/bin/bazelisk /root/go/bin/bazel
+# Buildifier is used by the Bazel VS Code extension.
+RUN go install github.com/bazelbuild/buildtools/buildifier@5.1.0
 
-# Install all python dependencies modules using Pip.
-RUN pip3 install -U pip
-RUN pip3 install pre-commit black codespell
+# Install LLVM from apt.llvm.org.
+RUN wget https://apt.llvm.org/llvm.sh
+RUN chmod +x llvm.sh
+RUN ./llvm.sh 15 all
+RUN rm llvm.sh
+ENV CC="/usr/bin/clang-15"
 
-# Install Clang/LLVM using Homebrew.
-# Many Clang/LLVM releases aren't built with options we rely on.
-RUN brew install llvm
+# Update pip and install black and pre-commit.
+RUN pip3 install -U pip
+RUN pip3 install black pre-commit

+ 9 - 4
bazel/cc_toolchains/clang_cc_toolchain_config.bzl

@@ -20,6 +20,7 @@ load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
 load(
     ":clang_detected_variables.bzl",
     "clang_bindir",
+    "clang_version",
     "clang_include_dirs_list",
     "clang_resource_dir",
     "llvm_bindir",
@@ -496,6 +497,13 @@ def _impl(ctx):
         implies = ["fuzzer"],
     )
 
+    # With clang 14 and lower, we expect it to be built with libc++ debug
+    # support. In later LLVM versions, we expect the assertions define to work.
+    if clang_version and clang_version <= 14:
+        libcpp_debug_flags = ["-D_LIBCPP_DEBUG=1"]
+    else:
+        libcpp_debug_flags = ["-D_LIBCPP_ENABLE_ASSERTIONS=1"]
+
     linux_flags_feature = feature(
         name = "linux_flags",
         enabled = True,
@@ -537,10 +545,7 @@ def _impl(ctx):
             ),
             flag_set(
                 actions = all_compile_actions,
-                flag_groups = [flag_group(flags = [
-                    # Enable libc++'s debug features.
-                    "-D_LIBCPP_DEBUG=1",
-                ])],
+                flag_groups = [flag_group(flags = libcpp_debug_flags)],
                 with_features = [
                     with_feature_set(not_features = ["opt"]),
                 ],

+ 27 - 5
bazel/cc_toolchains/clang_configuration.bzl

@@ -17,6 +17,27 @@ def _run(repository_ctx, cmd):
 
     return exec_result
 
+def _clang_version(version_output):
+    """Returns clang's major version number, or None if not found."""
+    version_prefix = "clang version "
+    version_start = version_output.find(version_prefix)
+    if version_start == -1:
+        # No version
+        return None
+    version_start += len(version_prefix)
+
+    # Find a dot to indicate something like 'clang version 14.0.6'.
+    version_dot = version_output.find(".", version_start)
+    if version_dot == -1:
+        return None
+
+    # Make sure the dot was on the same line as the version.
+    if version_output.find("\n", version_start) < version_dot:
+        return None
+
+    # Return the version as int.
+    return int(version_output[version_start:version_dot])
+
 def _detect_system_clang(repository_ctx):
     """Detects whether the system-provided clang can be used.
 
@@ -38,7 +59,7 @@ def _detect_system_clang(repository_ctx):
     version_output = _run(repository_ctx, [cc_path, "--version"]).stdout
     if "clang" not in version_output:
         fail("Searching for clang or CC (%s), and found (%s), which is not a Clang compiler" % (cc, cc_path))
-    return cc_path
+    return (cc_path, _clang_version(version_output))
 
 def _compute_clang_resource_dir(repository_ctx, clang):
     """Runs the `clang` binary to get its resource dir."""
@@ -66,14 +87,14 @@ def _compute_clang_cpp_include_search_paths(repository_ctx, clang, sysroot):
 
     # Create an empty temp file for Clang to use
     if repository_ctx.os.name.lower().startswith("windows"):
-        repository_ctx.file('_temp', '')
+        repository_ctx.file("_temp", "")
 
     # Read in an empty input file. If we are building from
     # Windows, then we create an empty temp file. Clang
     # on Windows does not like it when you pass a non-existent file.
     if repository_ctx.os.name.lower().startswith("windows"):
-        repository_ctx.file('_temp', '')
-        input_file = repository_ctx.path('_temp')
+        repository_ctx.file("_temp", "")
+        input_file = repository_ctx.path("_temp")
     else:
         input_file = "/dev/null"
 
@@ -131,7 +152,7 @@ def _configure_clang_toolchain_impl(repository_ctx):
     # here as the other LLVM tools may not be symlinked into the PATH even if
     # `clang` is. We also insist on finding the basename of `clang++` as that is
     # important for C vs. C++ compiles.
-    clang = _detect_system_clang(repository_ctx)
+    (clang, clang_version) = _detect_system_clang(repository_ctx)
     clang = clang.realpath.dirname.get_child("clang++")
 
     # Compute the various directories used by Clang.
@@ -168,6 +189,7 @@ def _configure_clang_toolchain_impl(repository_ctx):
         substitutions = {
             "{LLVM_BINDIR}": str(arpath.dirname),
             "{CLANG_BINDIR}": str(clang.dirname),
+            "{CLANG_VERSION}": str(clang_version),
             "{CLANG_RESOURCE_DIR}": resource_dir,
             "{CLANG_INCLUDE_DIRS_LIST}": str(
                 [str(path) for path in include_dirs],

+ 1 - 0
bazel/cc_toolchains/clang_detected_variables.tpl.bzl

@@ -10,6 +10,7 @@ This file gets processed by a repository rule, substituting the
 
 llvm_bindir = "{LLVM_BINDIR}"
 clang_bindir = "{CLANG_BINDIR}"
+clang_version = {CLANG_VERSION}
 clang_resource_dir = "{CLANG_RESOURCE_DIR}"
 clang_include_dirs_list = {CLANG_INCLUDE_DIRS_LIST}
 sysroot_dir = "{SYSROOT}"