Author: Haowei
Date: 2026-09-23T01:14:51-07:00
New Revision: 62ea87e542c3fea716875953b9427896f345f7d1

URL: 
https://github.com/llvm/llvm-project/commit/62ea87e542c3fea716875953b9427896f345f7d1
DIFF: 
https://github.com/llvm/llvm-project/commit/62ea87e542c3fea716875953b9427896f345f7d1.diff

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

Reverts llvm/llvm-project#224192

The original PR introduce implict dependency on cmake from path. Further
more, the cmake invocation from googlebenchmark.py didn't inherit
CMAKE_MAKE_PROGRAM and cmake generator flags from the parent LLVM build,
causing implicit dependency on make. It causes test failures on systems
that do not have these installed or config in their default path.

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')


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to