[llvm-branch-commits] [libunwind] 45bc9c1 - Revert "[libc++] Build GoogleBenchmark directly from Lit (#224192)"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Sep 23 00:30:42 PDT 2026


Author: Haowei
Date: 2026-09-23T00:30:36-07:00
New Revision: 45bc9c1acced1f6dfb20daf41a475433572dda8e

URL: https://github.com/llvm/llvm-project/commit/45bc9c1acced1f6dfb20daf41a475433572dda8e
DIFF: https://github.com/llvm/llvm-project/commit/45bc9c1acced1f6dfb20daf41a475433572dda8e.diff

LOG: Revert "[libc++] Build GoogleBenchmark directly from Lit (#224192)"

This reverts commit 1bfe9893f3dc12f1c0f9546564519f02601b2192.

Added: 
    libcxx/test/benchmarks/CMakeLists.txt

Modified: 
    libcxx/test/CMakeLists.txt
    libcxx/test/configs/harness-configuration.cfg.in
    libcxx/utils/libcxx/test/config.py
    libcxx/utils/libcxx/test/format.py
    libcxxabi/test/configs/cmake-bridge.cfg.in
    libunwind/test/configs/cmake-bridge.cfg.in

Removed: 
    libcxx/test/benchmarks/lit.local.cfg
    libcxx/utils/libcxx/test/googlebenchmark.py


################################################################################
diff  --git a/libcxx/test/CMakeLists.txt b/libcxx/test/CMakeLists.txt
index 85fa6aacc7796f..8fd34c086a9928 100644
--- a/libcxx/test/CMakeLists.txt
+++ b/libcxx/test/CMakeLists.txt
@@ -26,6 +26,7 @@ set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to pick
 serialize_lit_string_param(SERIALIZED_LIT_PARAMS compiler "${CMAKE_CXX_COMPILER}")
 
 if (LIBCXX_INCLUDE_BENCHMARKS)
+  add_subdirectory(benchmarks)
   set(_libcxx_benchmark_mode "dry-run")
 else()
   serialize_lit_string_param(SERIALIZED_LIT_PARAMS enable_benchmarks "no")

diff  --git a/libcxx/test/benchmarks/CMakeLists.txt b/libcxx/test/benchmarks/CMakeLists.txt
new file mode 100644
index 00000000000000..b3f881a008b808
--- /dev/null
+++ b/libcxx/test/benchmarks/CMakeLists.txt
@@ -0,0 +1,48 @@
+#==============================================================================
+# Build Google Benchmark
+#==============================================================================
+
+include(ExternalProject)
+set(BENCHMARK_COMPILE_FLAGS
+    -Wno-unused-command-line-argument
+    -nostdinc++
+    -isystem "${LIBCXX_GENERATED_INCLUDE_DIR}"
+    -L${LIBCXX_LIBRARY_DIR}
+    -Wl,-rpath,${LIBCXX_LIBRARY_DIR}
+    ${SANITIZER_FLAGS}
+    )
+if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
+  list(APPEND BENCHMARK_COMPILE_FLAGS
+    -isystem "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}")
+endif()
+if (DEFINED LIBCXX_CXX_ABI_LIBRARY_PATH)
+  list(APPEND BENCHMARK_COMPILE_FLAGS
+          -L${LIBCXX_CXX_ABI_LIBRARY_PATH}
+          -Wl,-rpath,${LIBCXX_CXX_ABI_LIBRARY_PATH})
+endif()
+split_list(BENCHMARK_COMPILE_FLAGS)
+
+set(BENCHMARK_CXX_LIBRARIES)
+list(APPEND BENCHMARK_CXX_LIBRARIES c++)
+if (NOT LIBCXX_ENABLE_SHARED)
+  list(APPEND BENCHMARK_CXX_LIBRARIES c++abi)
+endif()
+
+ExternalProject_Add(google-benchmark
+        EXCLUDE_FROM_ALL ON
+        DEPENDS cxx cxx-headers
+        PREFIX google-benchmark
+        SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
+        INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark
+        CMAKE_CACHE_ARGS
+          -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
+          -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
+          -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}
+          -DCMAKE_BUILD_TYPE:STRING=RELEASE
+          -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+          -DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_COMPILE_FLAGS}
+          -DBENCHMARK_USE_LIBCXX:BOOL=ON
+          -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
+          -DBENCHMARK_CXX_LIBRARIES:STRING=${BENCHMARK_CXX_LIBRARIES})
+
+add_dependencies(cxx-test-depends google-benchmark)

diff  --git a/libcxx/test/benchmarks/lit.local.cfg b/libcxx/test/benchmarks/lit.local.cfg
deleted file mode 100644
index 07a15e4ae5df95..00000000000000
--- a/libcxx/test/benchmarks/lit.local.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-# Build the GoogleBenchmark library using the current Lit configuration so
-# that benchmarks can link against it.
-
-import libcxx.test.googlebenchmark
-
-if "enable-benchmarks=no" in config.available_features:
-    config.substitutions.append(("%{benchmark_flags}", ""))
-else:
-    config.substitutions.append(
-        ("%{benchmark_flags}", libcxx.test.googlebenchmark.prepare(config, lit_config))
-    )

diff  --git a/libcxx/test/configs/harness-configuration.cfg.in b/libcxx/test/configs/harness-configuration.cfg.in
index fab0ee69255014..c527d60c64af5d 100644
--- a/libcxx/test/configs/harness-configuration.cfg.in
+++ b/libcxx/test/configs/harness-configuration.cfg.in
@@ -26,4 +26,5 @@ config.test_exec_root = os.path.join('@LIBCXX_BINARY_DIR@', 'test')
 
 # Add substitutions for bootstrapping the test suite configuration
 config.substitutions.append(('%{libcxx-dir}', '@LIBCXX_SOURCE_DIR@'))
+config.substitutions.append(('%{benchmark_flags}', '-I @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/include -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib64 -l benchmark'))
 config.substitutions.append(("%{python}", shlex.quote(sys.executable)))

diff  --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py
index c71e81cf9573ac..fd6f1bf5accd67 100644
--- a/libcxx/utils/libcxx/test/config.py
+++ b/libcxx/utils/libcxx/test/config.py
@@ -51,7 +51,7 @@ def configure(parameters, features, config, lit_config):
             )
 
     # Print the basic substitutions
-    for sub in ("%{cxx}", "%{flags}", "%{compile_flags}", "%{link_flags}", "%{exec}"):
+    for sub in ("%{cxx}", "%{flags}", "%{compile_flags}", "%{link_flags}", "%{benchmark_flags}", "%{exec}"):
         debug("Using {} substitution: '{}'".format(sub, _getSubstitution(sub, config.substitutions)))
 
     # Print all available features

diff  --git a/libcxx/utils/libcxx/test/format.py b/libcxx/utils/libcxx/test/format.py
index 3e24e435e7c07b..2f449e234e6d5e 100644
--- a/libcxx/utils/libcxx/test/format.py
+++ b/libcxx/utils/libcxx/test/format.py
@@ -31,7 +31,7 @@ def _getTempPaths(test):
 
 def _checkBaseSubstitutions(substitutions):
     substitutions = [s for (s, _) in substitutions]
-    for s in ["%{cxx}", "%{compile_flags}", "%{link_flags}", "%{flags}", "%{exec}"]:
+    for s in ["%{cxx}", "%{compile_flags}", "%{link_flags}", "%{benchmark_flags}", "%{flags}", "%{exec}"]:
         assert s in substitutions, "Required substitution {} was not provided".format(s)
 
 def _executeScriptInternal(test, litConfig, commands):
@@ -235,6 +235,10 @@ class CxxStandardLibraryTest(lit.formats.FileBasedTest):
         %{compile_flags}   - Flags to use when compiling a test case
         %{link_flags}      - Flags to use when linking a test case
         %{flags}           - Flags to use either when compiling or linking a test case
+        %{benchmark_flags} - Flags to use when compiling benchmarks. These flags should provide access to
+                             GoogleBenchmark but shouldn't hardcode any optimization level or other settings,
+                             since the benchmarks should be run under the same configuration as the rest of
+                             the test suite.
         %{exec}            - A command to prefix the execution of executables
 
     Note that when building an executable (as opposed to only compiling a source
@@ -355,13 +359,6 @@ def execute(self, test, litConfig):
                         test.getFullName()
                     ),
                 )
-            substitutions = [s for (s, _) in test.config.substitutions]
-            if "%{benchmark_flags}" not in substitutions:
-                return lit.Test.Result(
-                    lit.Test.UNRESOLVED,
-                    "Test {} is a benchmark, but the %{{benchmark_flags}} substitution "
-                    "isn't provided by the configuration.".format(test.getFullName()),
-                )
             steps = [
                 "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{benchmark_flags} %{link_flags} -o %t.exe",
             ]

diff  --git a/libcxx/utils/libcxx/test/googlebenchmark.py b/libcxx/utils/libcxx/test/googlebenchmark.py
deleted file mode 100644
index b5fe708e67f8cc..00000000000000
--- a/libcxx/utils/libcxx/test/googlebenchmark.py
+++ /dev/null
@@ -1,223 +0,0 @@
-# ===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-# ===----------------------------------------------------------------------===##
-
-"""
-Support for building GoogleBenchmark from the Lit configuration.
-
-The benchmarks in the test suite are linked against GoogleBenchmark, which must be
-built with the same Standard Library (and more generally with the same ABI-affecting
-flags) as the benchmarks themselves. This allows building GoogleBenchmark on-demand
-from Lit using the flags of the configuration being tested.
-
-The result is cached inside the build directory so that subsequent invocations are
-cheap.
-"""
-
-import hashlib
-import os
-import shlex
-import subprocess
-
-import lit.TestRunner
-
-import libcxx.test.config
-import libcxx.test.dsl
-
-THIS_FILE = os.path.abspath(__file__)
-LIBCXX_UTILS = os.path.dirname(os.path.dirname(os.path.dirname(THIS_FILE)))
-MONOREPO_ROOT = os.path.dirname(os.path.dirname(LIBCXX_UTILS))
-SOURCE_DIR = os.path.join(MONOREPO_ROOT, "third-party", "benchmark")
-
-# Flags used by the test suite that must not be used when building GoogleBenchmark.
-# Anything that isn't listed here is forwarded verbatim.
-#
-# -Werror
-#     Avoid failing GoogleBenchmark's build due to warnings.
-# -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
-#     Only relevant when testing libc++ itself.
-# -fmodules, -fcxx-modules, -fmodules-cache-path=
-#     Modules are irrelevant when building a third-party static library, and sharing a
-#     module cache with the test suite is undesirable.
-# -std=
-#     GoogleBenchmark sets CMAKE_CXX_STANDARD itself and requires C++17.
-_DROPPED_FLAGS = {
-    "-Werror",
-    "-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER",
-    "-fmodules",
-    "-fcxx-modules",
-}
-
-_DROPPED_FLAG_PREFIXES = (
-    "-std=",
-    "-fmodules-cache-path=",
-)
-
-# Flags that are dropped along with the '-Xclang' that introduces them.
-_DROPPED_XCLANG_FLAGS = {
-    "-fmodules-local-submodule-visibility",
-}
-
-
-def _expand(config, string):
-    """
-    Expand the Lit substitutions in the given string, recursively.
-    """
-    (expanded,) = lit.TestRunner.applySubstitutions(
-        [string],
-        config.substitutions,
-        recursion_limit=config.recursiveExpansionLimit,
-    )
-    return expanded
-
-
-def _filterFlags(flags):
-    """
-    Remove the flags that must not be used when building GoogleBenchmark.
-    """
-    result = []
-    flags = iter(flags)
-    for flag in flags:
-        if flag == "-Xclang":
-            arg = next(flags, None)
-            if arg is None:
-                result.append(flag)
-            elif arg not in _DROPPED_XCLANG_FLAGS:
-                result += [flag, arg]
-        elif flag not in _DROPPED_FLAGS and not flag.startswith(_DROPPED_FLAG_PREFIXES):
-            result.append(flag)
-    return result
-
-
-def _getFlags(config, substitutions):
-    """
-    Return the flags contained in the given substitutions, based on the flags used by the
-    configuration under test.
-    """
-    flags = []
-    for substitution in substitutions:
-        expanded = _expand(config, _getSubstitution(substitution, config))
-        flags += shlex.split(expanded)
-    return _filterFlags(flags)
-
-
-def _splitLibraries(flags):
-    """
-    Split the given link flags into (flags, libraries), where libraries contains the
-    name of the libraries that were being linked against.
-
-    We can't simply hand the libraries over to CMake as part of CMAKE_CXX_FLAGS, since
-    CMake puts those flags before the object files on the link line.
-    """
-    result = []
-    libraries = []
-    flags = iter(flags)
-    for flag in flags:
-        if flag == "-l":
-            library = next(flags, None)
-            if library is None:
-                result.append(flag)
-            else:
-                libraries.append(library)
-        elif flag.startswith("-l"):
-            libraries.append(flag[len("-l") :])
-        else:
-            result.append(flag)
-    return (result, libraries)
-
-
-def _getSubstitution(substitution, config):
-    return libcxx.test.config._getSubstitution(substitution, config.substitutions)
-
-
-def _fingerprint(config, flags, libraries):
-    """
-    Return an opaque value identifying this GoogleBenchmark build.
-
-    This changes whenever the compiler is rebuilt or whenever the flags used to build
-    GoogleBenchmark change.
-    """
-    compiler = libcxx.test.dsl._compilerFingerprint(config)
-    return hashlib.sha256(repr((compiler, flags, libraries)).encode()).hexdigest()[:16]
-
-
-def _run(litConfig, what, command, cwd):
-    result = subprocess.run(
-        command,
-        cwd=cwd,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.STDOUT,
-        universal_newlines=True,
-    )
-    if result.returncode != 0:
-        pretty = " ".join(shlex.quote(arg) for arg in command)
-        litConfig.fatal(
-            "Failed to {} GoogleBenchmark.\n"
-            "Command was:\n{}\n\n"
-            "Output was:\n{}".format(what, pretty, result.stdout)
-        )
-
-
-def prepare(config, litConfig):
-    """
-    Make GoogleBenchmark available to the test suite and return the flags required to
-    build the benchmarks against it.
-
-    GoogleBenchmark is built using the same flags as the rest of the test suite, and the
-    result is cached inside the build directory. The cache is keyed on the flags being
-    used, so 
diff erent Lit configurations do not interfere with each other.
-    """
-    flags, libraries = _splitLibraries(
-        _getFlags(config, ("%{flags}", "%{compile_flags}", "%{link_flags}"))
-    )
-    root = os.path.join(config.test_exec_root, "__gbench__")
-    prefix = os.path.join(root, _fingerprint(config, flags, libraries))
-    buildDir = os.path.join(prefix, "build")
-    installDir = os.path.join(prefix, "install")
-    os.makedirs(root, exist_ok=True)
-
-    cmake = os.environ.get("CMAKE", "cmake")
-
-    if not os.path.exists(os.path.join(buildDir, "CMakeCache.txt")):
-        litConfig.note("Configuring GoogleBenchmark in {}".format(buildDir))
-        compiler = _expand(config, _getSubstitution("%{cxx}", config))
-        _run(
-            litConfig,
-            "configure",
-            [
-                cmake,
-                "-S", SOURCE_DIR,
-                "-B", buildDir,
-                "-DCMAKE_BUILD_TYPE=Release",
-                "-DCMAKE_CXX_COMPILER={}".format(compiler),
-                "-DCMAKE_CXX_FLAGS={}".format(" ".join(flags)),
-                # Set CMAKE_EXE_LINKER_FLAGS in addition to BENCHMARK_CXX_LIBRARIES since we
-                # need CMake's own probe executables to have the right linker flags.
-                "-DCMAKE_EXE_LINKER_FLAGS={}".format(" ".join("-l{}".format(lib) for lib in libraries)),
-                "-DCMAKE_INSTALL_PREFIX={}".format(installDir),
-                "-DCMAKE_INSTALL_LIBDIR=lib",
-                "-DBENCHMARK_CXX_LIBRARIES={}".format(";".join(libraries)),
-                "-DBENCHMARK_ENABLE_TESTING=OFF",
-                "-DBENCHMARK_ENABLE_WERROR=OFF",
-                "-DBENCHMARK_INSTALL_DOCS=OFF",
-            ],
-            cwd=root,
-        )
-
-    # Always build: GoogleBenchmark is compiled against the headers of the library
-    # under test, so it must be rebuilt when those change. This is a no-op when
-    # nothing changed.
-    _run(
-        litConfig,
-        "build",
-        [cmake, "--build", buildDir, "--target", "install", "--parallel", str(os.cpu_count() or 1)],
-        cwd=root,
-    )
-
-    include = os.path.join(installDir, "include")
-    lib = os.path.join(installDir, "lib")
-    return "-isystem {} -L {} -l benchmark".format(include, lib)

diff  --git a/libcxxabi/test/configs/cmake-bridge.cfg.in b/libcxxabi/test/configs/cmake-bridge.cfg.in
index a2fa847f2d6c66..f81dd8afb10915 100644
--- a/libcxxabi/test/configs/cmake-bridge.cfg.in
+++ b/libcxxabi/test/configs/cmake-bridge.cfg.in
@@ -34,6 +34,7 @@ config.substitutions.append(('%{include}', '@LIBCXXABI_TESTING_INSTALL_PREFIX@/i
 config.substitutions.append(('%{cxx-include}', '@LIBCXXABI_TESTING_INSTALL_PREFIX@/@LIBCXXABI_INSTALL_INCLUDE_DIR@'))
 config.substitutions.append(('%{cxx-target-include}', '@LIBCXXABI_TESTING_INSTALL_PREFIX@/@LIBCXXABI_INSTALL_INCLUDE_TARGET_DIR@'))
 config.substitutions.append(('%{lib}', '@LIBCXXABI_TESTING_INSTALL_PREFIX@/@LIBCXXABI_INSTALL_LIBRARY_DIR@'))
+config.substitutions.append(('%{benchmark_flags}', ''))
 
 if @LIBCXXABI_USE_LLVM_UNWINDER@:
     config.substitutions.append(('%{maybe-include-libunwind}', '-I "@LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL@"'))

diff  --git a/libunwind/test/configs/cmake-bridge.cfg.in b/libunwind/test/configs/cmake-bridge.cfg.in
index 98e7d8d653f5dc..ed0b2afbc0c0d2 100644
--- a/libunwind/test/configs/cmake-bridge.cfg.in
+++ b/libunwind/test/configs/cmake-bridge.cfg.in
@@ -45,6 +45,7 @@ config.substitutions.append(('%{libcxx}', '@LIBUNWIND_LIBCXX_PATH@'))
 config.substitutions.append(('%{install-prefix}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@'))
 config.substitutions.append(('%{include}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/include'))
 config.substitutions.append(('%{lib}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/@LIBUNWIND_INSTALL_LIBRARY_DIR@'))
+config.substitutions.append(('%{benchmark_flags}', ''))
 
 # Check for objcopy tools
 objcopy_path = which('llvm-objcopy', '@LLVM_BUILD_BINARY_DIR@/bin')


        


More information about the llvm-branch-commits mailing list