[Bazel] Use `LLVM_VERSION` from `llvm/CMakeLists.txt`
authorNAKAMURA Takumi <geek4civic@gmail.com>
Sun, 8 Jan 2023 11:39:09 +0000 (20:39 +0900)
committerNAKAMURA Takumi <geek4civic@gmail.com>
Sat, 14 Jan 2023 01:26:01 +0000 (10:26 +0900)
* Generate `//:vars.bzl` from `llvm/CMakeLists.txt`

`_extract_cmake_settings()` generates `//:vars.bzl` in `llvm_configure()`.
It would be easier to use external commands like sed(1) and python.
For portability, I think the parser should run on Starlark.

`@llvm-project//:vars.bzl` may be loaded from both WORKSPACE and BUILD.
At the moment, `vars.bzl` provides some values as string.

- CMAKE_CXX_STANDARD = "17"
- LLVM_VERSION_MAJOR = "16"
- LLVM_VERSION_MINOR = "0"
- LLVM_VERSION_PATCH = "0"
- LLVM_VERSION = "16.0.0"
- llvm_vars = (dict of these values)

`CMAKE_CXX_STANDARD` may be used to configure toolchain.

* Use `//vars.bzl` for each BUILD files

It would be smarter if the BUILD phase could generate `llvm-config.h`.
Since I am afraid of the discussion in D126581, I just remove
LLVM_VERSION stuff out of the static `llvm-config.h`.

* Eliminate Bazel stuff in 'bump-version.py'

Current version of `bump-version.py` tries to substitute CLANG_VERSION.
It is the reason why I modify bump-version in this change rather than
incoming patch.

Differential Revision: https://reviews.llvm.org/D136392

llvm/utils/release/bump-version.py
utils/bazel/configure.bzl
utils/bazel/llvm-project-overlay/clang/BUILD.bazel
utils/bazel/llvm-project-overlay/lld/BUILD.bazel
utils/bazel/llvm-project-overlay/llvm/config.bzl
utils/bazel/llvm-project-overlay/llvm/include/llvm/Config/llvm-config.h

index e508bd1..f064e4e 100755 (executable)
@@ -88,43 +88,6 @@ class CMakeProcessor(Processor):
         return nline
 
 
-# Process the many bazel files.
-class BazelProcessor(Processor):
-    def process_line(self, line: str) -> str:
-        # This matches the CLANG_VERSION line of clang/Config/config.h
-        nline = line
-        if "CLANG_VERSION " in line:
-            nline = re.sub(
-                r"#define CLANG_VERSION (.*)'",
-                f"#define CLANG_VERSION {self.version_str(include_suffix=False)}'",
-                line,
-            )
-        # Match version strings of LLVM, Clang and LLD overlay headers
-        elif "LLVM_VERSION_STRING" in line or "CLANG_VERSION_STRING" in line or "LLD_VERSION_STRING" in line:
-            nline = re.sub(
-                r"#define (LLVM|CLANG|LLD)_VERSION_STRING ([\\\"]+)[0-9\.rcgit-]+([\\\"]+)",
-                rf"#define \g<1>_VERSION_STRING \g<2>{self.version_str()}\g<3>",
-                line,
-            )
-        # Match the split out MAJOR/MINOR/PATCH versions of LLVM and Clang overlay headers
-        # in LLVM the define is called _PATCH and in clang it's called _PATCHLEVEL
-        elif "LLVM_VERSION_" in line or "CLANG_VERSION_" in line:
-            for c, cver in (
-                ("(MAJOR)", self.major),
-                ("(MINOR)", self.minor),
-                ("(PATCH|PATCHLEVEL)", self.patch),
-            ):
-                nline = re.sub(
-                    fr"(LLVM|CLANG)_VERSION_{c} \d+",
-                    rf"\g<1>_VERSION_\g<2> {cver}",
-                    line,
-                )
-                if nline != line:
-                    break
-
-        return nline
-
-
 # GN build system
 class GNIProcessor(Processor):
     def process_line(self, line: str) -> str:
@@ -214,23 +177,6 @@ if __name__ == "__main__":
             "llvm/utils/gn/secondary/llvm/version.gni",
             GNIProcessor(),
         ),
-        # Bazel build system
-        (
-            "utils/bazel/llvm-project-overlay/llvm/include/llvm/Config/llvm-config.h",
-            BazelProcessor(),
-        ),
-        (
-            "utils/bazel/llvm-project-overlay/clang/BUILD.bazel",
-            BazelProcessor(),
-        ),
-        (
-            "utils/bazel/llvm-project-overlay/clang/include/clang/Config/config.h",
-            BazelProcessor(),
-        ),
-        (
-            "utils/bazel/llvm-project-overlay/lld/BUILD.bazel",
-            BazelProcessor(),
-        ),
         (
             "libcxx/include/__config",
             LibCXXProcessor(),
index 0a731a8..b4d2785 100644 (file)
@@ -71,9 +71,89 @@ def _overlay_directories(repository_ctx):
             stderr = exec_result.stderr,
         ))
 
+def _extract_cmake_settings(repository_ctx, llvm_cmake):
+    # The list to be written to vars.bzl
+    # `CMAKE_CXX_STANDARD` may be used from WORKSPACE for the toolchain.
+    c = {
+        "CMAKE_CXX_STANDARD": None,
+        "LLVM_VERSION_MAJOR": None,
+        "LLVM_VERSION_MINOR": None,
+        "LLVM_VERSION_PATCH": None,
+    }
+
+    # It would be easier to use external commands like sed(1) and python.
+    # For portability, the parser should run on Starlark.
+    llvm_cmake_path = repository_ctx.path(Label("//:" + llvm_cmake))
+    for line in repository_ctx.read(llvm_cmake_path).splitlines():
+        # Extract "set ( FOO bar ... "
+        setfoo = line.partition("(")
+        if setfoo[1] != "(":
+            continue
+        if setfoo[0].strip().lower() != "set":
+            continue
+        # `kv` is assumed as \s*KEY\s+VAL\s*\).*
+        # Typical case is like
+        #   LLVM_REQUIRED_CXX_STANDARD 17)
+        # Possible case -- It should be ignored.
+        #   CMAKE_CXX_STANDARD ${...} CACHE STRING "...")
+        kv = setfoo[2].strip()
+        i = kv.find(" ")
+        if i < 0:
+            continue
+        k = kv[:i]
+        # Prefer LLVM_REQUIRED_CXX_STANDARD instead of CMAKE_CXX_STANDARD
+        if k == "LLVM_REQUIRED_CXX_STANDARD":
+            k = "CMAKE_CXX_STANDARD"
+            c[k] = None
+        if k not in c:
+            continue
+        # Skip if `CMAKE_CXX_STANDARD` is set with
+        # `LLVM_REQUIRED_CXX_STANDARD`.
+        # Then `v` will not be desired form, like "${...} CACHE"
+        if c[k] != None:
+            continue
+        # Pick up 1st word as the value.
+        # Note: It assumes unquoted word.
+        v = kv[i:].strip().partition(")")[0].partition(" ")[0]
+        c[k] = v
+
+    # Synthesize `LLVM_VERSION` for convenience.
+    c["LLVM_VERSION"] = "{}.{}.{}".format(
+        c["LLVM_VERSION_MAJOR"],
+        c["LLVM_VERSION_MINOR"],
+        c["LLVM_VERSION_PATCH"],
+    )
+
+    return c
+
+def _write_dict_to_file(repository_ctx, filepath, header, vars):
+    # (fci + individual vars) + (fcd + dict items) + (fct)
+    fci = header
+    fcd = "\nllvm_vars={\n"
+    fct = "}\n"
+
+    for k, v in vars.items():
+        fci += '{} = "{}"\n'.format(k, v)
+        fcd += '    "{}": "{}",\n'.format(k, v)
+
+    repository_ctx.file(filepath, content=fci + fcd + fct)
+
 def _llvm_configure_impl(repository_ctx):
     _overlay_directories(repository_ctx)
 
+    llvm_cmake = "llvm/CMakeLists.txt"
+    vars = _extract_cmake_settings(
+        repository_ctx,
+        llvm_cmake,
+    )
+
+    _write_dict_to_file(
+        repository_ctx,
+        filepath="vars.bzl",
+        header="# Generated from {}\n\n".format(llvm_cmake),
+        vars=vars,
+    )
+
     # Create a starlark file with the requested LLVM targets.
     targets = repository_ctx.attr.targets
     repository_ctx.file(
index 0ec1690..8764739 100644 (file)
@@ -7,6 +7,14 @@ load("//llvm:tblgen.bzl", "gentbl")
 load("//llvm:binary_alias.bzl", "binary_alias")
 load("//llvm:cc_plugin_library.bzl", "cc_plugin_library")
 
+load(
+    "//:vars.bzl",
+    "LLVM_VERSION",
+    "LLVM_VERSION_MAJOR",
+    "LLVM_VERSION_MINOR",
+    "LLVM_VERSION_PATCH",
+)
+
 package(
     default_visibility = ["//visibility:public"],
     features = ["layering_check"],
@@ -360,12 +368,17 @@ genrule(
     name = "basic_version_gen",
     outs = ["include/clang/Basic/Version.inc"],
     cmd = (
-        "echo '#define CLANG_VERSION 16.0.0' >> $@\n" +
-        "echo '#define CLANG_VERSION_MAJOR 16' >> $@\n" +
-        "echo '#define CLANG_VERSION_MAJOR_STRING \"16\"' >> $@\n" +
-        "echo '#define CLANG_VERSION_MINOR 0' >> $@\n" +
-        "echo '#define CLANG_VERSION_PATCHLEVEL 0' >> $@\n" +
-        "echo '#define CLANG_VERSION_STRING \"16.0.0\"' >> $@\n"
+        "echo '#define CLANG_VERSION {vers}' >> $@\n" +
+        "echo '#define CLANG_VERSION_MAJOR {major}' >> $@\n" +
+        "echo '#define CLANG_VERSION_MAJOR_STRING \"{major}\"' >> $@\n" +
+        "echo '#define CLANG_VERSION_MINOR {minor}' >> $@\n" +
+        "echo '#define CLANG_VERSION_PATCHLEVEL {patch}' >> $@\n" +
+        "echo '#define CLANG_VERSION_STRING \"{vers}\"' >> $@\n"
+    ).format(
+        vers=LLVM_VERSION,
+        major=LLVM_VERSION_MAJOR,
+        minor=LLVM_VERSION_MINOR,
+        patch=LLVM_VERSION_PATCH,
     ),
 )
 
index 87041f3..729a33d 100644 (file)
@@ -5,6 +5,11 @@
 load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
 load("//llvm:tblgen.bzl", "gentbl")
 
+load(
+    "//:vars.bzl",
+    "LLVM_VERSION",
+)
+
 package(
     default_visibility = ["//visibility:public"],
     features = ["layering_check"],
@@ -16,7 +21,7 @@ licenses(["notice"])
 genrule(
     name = "config_version_gen",
     outs = ["include/lld/Common/Version.inc"],
-    cmd = "echo '#define LLD_VERSION_STRING \"16.0.0\"' > $@",
+    cmd = "echo '#define LLD_VERSION_STRING \"{}\"' > $@".format(LLVM_VERSION),
 )
 
 genrule(
index 5beb3cc..5507f80 100644 (file)
@@ -4,6 +4,14 @@
 
 """Defines variables that use selects to configure LLVM based on platform."""
 
+load(
+    "//:vars.bzl",
+    "LLVM_VERSION",
+    "LLVM_VERSION_MAJOR",
+    "LLVM_VERSION_MINOR",
+    "LLVM_VERSION_PATCH",
+)
+
 def native_arch_defines(arch, triple):
     return [
         r'LLVM_NATIVE_ARCH=\"{}\"'.format(arch),
@@ -89,6 +97,10 @@ llvm_config_defines = os_defines + select({
     "@bazel_tools//src/conditions:linux_s390x": native_arch_defines("SystemZ", "systemz-unknown-linux_gnu"),
     "//conditions:default": native_arch_defines("X86", "x86_64-unknown-linux-gnu"),
 }) + [
+    "LLVM_VERSION_MAJOR={}".format(LLVM_VERSION_MAJOR),
+    "LLVM_VERSION_MINOR={}".format(LLVM_VERSION_MINOR),
+    "LLVM_VERSION_PATCH={}".format(LLVM_VERSION_PATCH),
+    r'LLVM_VERSION_STRING=\"{}git\"'.format(LLVM_VERSION),
     # These shouldn't be needed by the C++11 standard, but are for some
     # platforms (e.g. glibc < 2.18. See
     # https://sourceware.org/bugzilla/show_bug.cgi?id=15366). These are also
index 60d915e..5240b82 100644 (file)
 #define LLVM_USE_PERF 0
 
 /* Major version of the LLVM API */
-#define LLVM_VERSION_MAJOR 16
+/* #undef LLVM_VERSION_MAJOR */
 
 /* Minor version of the LLVM API */
-#define LLVM_VERSION_MINOR 0
+/* #undef LLVM_VERSION_MINOR */
 
 /* Patch version of the LLVM API */
-#define LLVM_VERSION_PATCH 0
+/* #undef LLVM_VERSION_PATCH */
 
 /* LLVM version string */
-#define LLVM_VERSION_STRING "16.0.0git"
+/* #undef LLVM_VERSION_STRING */
 
 /* Whether LLVM records statistics for use with GetStatistics(),
  * PrintStatistics() or PrintStatisticsJSON()