[libc-commits] [libc] [libc] Implement lit-based test execution for Libc (PR #178746)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Thu Feb 12 09:47:03 PST 2026
https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/178746
>From 49dc9b52b1fbeb4cdcfa1c84813f59a7178d8b4d Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jeffbailey at google.com>
Date: Mon, 19 Jan 2026 14:43:58 +0000
Subject: [PATCH 1/2] [libc] Implement lit-based test execution for Libc
This provides optional lit-based test execution for the LLVM
Libc tests, alongside the existing CMake-based test execution.
Usage:
ninja -C build check-libc-lit
cd build && bin/llvm-lit libc/test/src/
---
libc/cmake/modules/LLVMLibCLitTestRules.cmake | 85 ++++++++++++++++
libc/cmake/modules/LLVMLibCRules.cmake | 1 +
libc/cmake/modules/LLVMLibCTestRules.cmake | 8 ++
libc/test/CMakeLists.txt | 13 +++
libc/test/lit.cfg.py | 49 ++++++++++
libc/test/lit.site.cfg.py.in | 23 +++++
libc/utils/LibcTestFormat/__init__.py | 21 ++++
libc/utils/LibcTestFormat/format.py | 96 +++++++++++++++++++
8 files changed, 296 insertions(+)
create mode 100644 libc/cmake/modules/LLVMLibCLitTestRules.cmake
create mode 100644 libc/test/lit.cfg.py
create mode 100644 libc/test/lit.site.cfg.py.in
create mode 100644 libc/utils/LibcTestFormat/__init__.py
create mode 100644 libc/utils/LibcTestFormat/format.py
diff --git a/libc/cmake/modules/LLVMLibCLitTestRules.cmake b/libc/cmake/modules/LLVMLibCLitTestRules.cmake
new file mode 100644
index 0000000000000..bfe59239a1b51
--- /dev/null
+++ b/libc/cmake/modules/LLVMLibCLitTestRules.cmake
@@ -0,0 +1,85 @@
+#===============================================================================
+# Lit Test Infrastructure for LLVM libc
+#
+# This module provides functions to set up lit-based testing for libc.
+#
+# Lit discovers and runs the test executables created by the
+# add_libc_test() infrastructure. No separate build rules are needed.
+#===============================================================================
+
+# Guard against double inclusion
+if(LIBC_LIT_TEST_RULES_INCLUDED)
+ return()
+endif()
+set(LIBC_LIT_TEST_RULES_INCLUDED TRUE)
+
+# Include LLVM's lit infrastructure
+include(AddLLVM)
+
+#-------------------------------------------------------------------------------
+# configure_libc_lit_site_cfg()
+#
+# Configures the lit.site.cfg.py file from its template.
+# This should be called once from libc/test/CMakeLists.txt.
+#-------------------------------------------------------------------------------
+function(configure_libc_lit_site_cfg)
+ # Set variables for the template
+ set(LIBC_SOURCE_DIR "${LIBC_SOURCE_DIR}")
+ set(LIBC_BINARY_DIR "${LIBC_BUILD_DIR}")
+
+ # Configure the site config file
+ configure_lit_site_cfg(
+ ${LIBC_SOURCE_DIR}/test/lit.site.cfg.py.in
+ ${LIBC_BUILD_DIR}/test/lit.site.cfg.py
+ MAIN_CONFIG
+ ${LIBC_SOURCE_DIR}/test/lit.cfg.py
+ PATHS
+ "LLVM_SOURCE_DIR"
+ "LLVM_BINARY_DIR"
+ "LLVM_TOOLS_DIR"
+ "LLVM_LIBS_DIR"
+ "LIBC_SOURCE_DIR"
+ "LIBC_BINARY_DIR"
+ )
+endfunction()
+
+#-------------------------------------------------------------------------------
+# add_libc_lit_testsuite()
+#
+# Creates a lit test suite target for a specific test directory.
+#
+# Usage:
+# add_libc_lit_testsuite(check-libc-ctype
+# SUITE_NAME ctype
+# TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/ctype
+# DEPENDS libc-ctype-tests
+# )
+#
+# Note: TEST_DIR should be the build directory where test executables are
+# located, not the source directory.
+#-------------------------------------------------------------------------------
+function(add_libc_lit_testsuite target_name)
+ cmake_parse_arguments(
+ "LIT_SUITE"
+ "" # No optional arguments
+ "SUITE_NAME;TEST_DIR" # Single value arguments
+ "DEPENDS" # Multi value arguments
+ ${ARGN}
+ )
+
+ if(NOT LIT_SUITE_TEST_DIR)
+ message(FATAL_ERROR "add_libc_lit_testsuite requires TEST_DIR")
+ endif()
+
+ # Create the lit test target using LLVM's infrastructure
+ add_lit_testsuite(${target_name}
+ "Running ${LIT_SUITE_SUITE_NAME} libc tests"
+ ${LIT_SUITE_TEST_DIR}
+ DEPENDS ${LIT_SUITE_DEPENDS}
+ )
+
+ # Add to the umbrella check-libc-lit target if it exists
+ if(TARGET check-libc-lit)
+ add_dependencies(check-libc-lit ${target_name})
+ endif()
+endfunction()
diff --git a/libc/cmake/modules/LLVMLibCRules.cmake b/libc/cmake/modules/LLVMLibCRules.cmake
index 76f3892eeb32e..029ecc390128d 100644
--- a/libc/cmake/modules/LLVMLibCRules.cmake
+++ b/libc/cmake/modules/LLVMLibCRules.cmake
@@ -4,3 +4,4 @@ include(LLVMLibCFlagRules)
include(LLVMLibCObjectRules)
include(LLVMLibCLibraryRules)
include(LLVMLibCTestRules)
+include(LLVMLibCLitTestRules)
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index ba64933708760..e59f5447c5a0f 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -344,6 +344,10 @@ function(create_libc_unittest fq_target_name)
)
endif()
add_dependencies(libc-unit-tests ${fq_target_name})
+ # Also add dependency to build-only target for lit
+ if(TARGET libc-unit-tests-build)
+ add_dependencies(libc-unit-tests-build ${fq_build_target_name})
+ endif()
endfunction(create_libc_unittest)
function(add_libc_unittest target_name)
@@ -883,6 +887,10 @@ function(add_libc_hermetic test_name)
# If it is a benchmark, it will already have been added to the
# gpu-benchmark target
add_dependencies(libc-hermetic-tests ${fq_target_name})
+ # Also add dependency to build-only target for lit
+ if(TARGET libc-hermetic-tests-build)
+ add_dependencies(libc-hermetic-tests-build ${fq_build_target_name})
+ endif()
endif()
endfunction(add_libc_hermetic)
diff --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index 011ad6aeb34b7..30e4c4239174e 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -6,6 +6,19 @@ add_dependencies(check-libc libc-unit-tests libc-hermetic-tests)
add_custom_target(exhaustive-check-libc)
add_custom_target(libc-long-running-tests)
+# Build-only targets for lit (don't run tests, just build executables)
+add_custom_target(libc-unit-tests-build)
+add_custom_target(libc-hermetic-tests-build)
+
+# Configure lit test infrastructure
+# Lit depends on build-only targets so tests aren't run during build
+configure_libc_lit_site_cfg()
+add_lit_testsuite(check-libc-lit
+ "Running libc tests via lit"
+ ${LIBC_BUILD_DIR}/test
+ DEPENDS libc-unit-tests-build libc-hermetic-tests-build
+)
+
add_subdirectory(UnitTest)
if(LIBC_TARGET_OS_IS_GPU)
diff --git a/libc/test/lit.cfg.py b/libc/test/lit.cfg.py
new file mode 100644
index 0000000000000..9cc9f6be446cf
--- /dev/null
+++ b/libc/test/lit.cfg.py
@@ -0,0 +1,49 @@
+# -*- Python -*-
+#
+# 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
+#
+# ===----------------------------------------------------------------------===##
+#
+# This is the lit configuration for LLVM libc tests.
+#
+# ===----------------------------------------------------------------------===##
+
+import os
+import site
+import sys
+
+import lit.formats
+import lit.util
+
+# Add libc's utils directory to the path so we can import the test format
+site.addsitedir(os.path.join(config.libc_src_root, "utils"))
+import LibcTestFormat
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = "libc"
+
+# testFormat: Use libc's custom test format that discovers pre-built
+# test executables (Libc*Tests) in the build directory.
+config.test_format = LibcTestFormat.LibcTest()
+
+# suffixes: Not used by LibcTest format, but kept for compatibility
+config.suffixes = []
+
+# excludes: A list of directories to exclude from the testsuite.
+config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt", "UnitTest"]
+
+# test_source_root: The root path where tests are located.
+# test_exec_root: The root path where test executables are built.
+# Set both to the build directory so ExecutableTest finds executables correctly.
+config.test_exec_root = os.path.join(config.libc_obj_root, "test")
+config.test_source_root = config.test_exec_root
+
+# Add tool directories to PATH (in case we add FileCheck tests later)
+if hasattr(config, "llvm_tools_dir") and config.llvm_tools_dir:
+ config.environment["PATH"] = os.path.pathsep.join(
+ [config.llvm_tools_dir, config.environment.get("PATH", "")]
+ )
diff --git a/libc/test/lit.site.cfg.py.in b/libc/test/lit.site.cfg.py.in
new file mode 100644
index 0000000000000..b4fd7d07ba716
--- /dev/null
+++ b/libc/test/lit.site.cfg.py.in
@@ -0,0 +1,23 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+import sys
+import os
+
+# Configuration values from CMake
+config.llvm_src_root = path(r"@LLVM_SOURCE_DIR@")
+config.llvm_obj_root = path(r"@LLVM_BINARY_DIR@")
+config.llvm_tools_dir = lit_config.substitute(path(r"@LLVM_TOOLS_DIR@"))
+config.llvm_libs_dir = lit_config.substitute(path(r"@LLVM_LIBS_DIR@"))
+config.libc_src_root = path(r"@LIBC_SOURCE_DIR@")
+config.libc_obj_root = path(r"@LIBC_BINARY_DIR@")
+config.target_triple = "@LLVM_TARGET_TRIPLE@"
+config.host_triple = "@LLVM_HOST_TRIPLE@"
+config.python_executable = "@Python3_EXECUTABLE@"
+
+# Initialize lit.llvm module
+import lit.llvm
+lit.llvm.initialize(lit_config, config)
+
+# Let the main config do the real work.
+lit_config.load_config(
+ config, os.path.join(config.libc_src_root, "test/lit.cfg.py"))
diff --git a/libc/utils/LibcTestFormat/__init__.py b/libc/utils/LibcTestFormat/__init__.py
new file mode 100644
index 0000000000000..9472aa94e7f30
--- /dev/null
+++ b/libc/utils/LibcTestFormat/__init__.py
@@ -0,0 +1,21 @@
+# ===----------------------------------------------------------------------===##
+#
+# 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
+#
+# ===----------------------------------------------------------------------===##
+
+"""
+Lit test format for LLVM libc unit tests.
+
+This format extends lit.formats.ExecutableTest to discover pre-built test
+executables in the build directory. Test executables are expected to follow
+the naming pattern used by add_libc_test():
+ libc.test.src.<category>.<test_name>.__unit__.__build__
+ libc.test.src.<category>.<test_name>.__hermetic__.__build__
+"""
+
+from .format import LibcTest
+
+__all__ = ["LibcTest"]
diff --git a/libc/utils/LibcTestFormat/format.py b/libc/utils/LibcTestFormat/format.py
new file mode 100644
index 0000000000000..8b641f169e243
--- /dev/null
+++ b/libc/utils/LibcTestFormat/format.py
@@ -0,0 +1,96 @@
+# ===----------------------------------------------------------------------===##
+#
+# 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
+#
+# ===----------------------------------------------------------------------===##
+
+"""
+Lit test format for LLVM libc tests.
+
+This format discovers pre-built test executables in the build directory
+and runs them. It extends lit's ExecutableTest format.
+
+The lit config sets test_source_root == test_exec_root (both to the build
+directory), following the pattern used by llvm/test/Unit/lit.cfg.py.
+
+Test executables are discovered by looking for files matching:
+ libc.test.src.<category>.<test_name>.__unit__.__build__
+ libc.test.src.<category>.<test_name>.__hermetic__.__build__
+
+These are created by the add_libc_test() infrastructure.
+"""
+
+import os
+
+import lit.formats
+import lit.Test
+import lit.util
+
+
+class LibcTest(lit.formats.ExecutableTest):
+ """
+ Test format for libc unit tests.
+
+ Extends ExecutableTest to discover tests from the build directory
+ rather than the source directory. Test executables are named like:
+ libc.test.src.ctype.isalnum_test.__unit__.__build__
+ and return 0 on success.
+ """
+
+ def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
+ """
+ Discover test executables in the build directory.
+
+ Since test_source_root == test_exec_root (both point to build dir),
+ we use getSourcePath() to find test executables.
+ """
+ source_path = testSuite.getSourcePath(path_in_suite)
+
+ # Look for test executables in the build directory
+ if not os.path.isdir(source_path):
+ return
+
+ for filename in os.listdir(source_path):
+ filepath = os.path.join(source_path, filename)
+
+ # Match our test executable pattern
+ if self._isTestExecutable(filename, filepath):
+ # Create a test with the executable name
+ yield lit.Test.Test(testSuite, path_in_suite + (filename,), localConfig)
+
+ def _isTestExecutable(self, filename, filepath):
+ """Check if a file is a test executable we should run."""
+ # Pattern: libc.test.src.*.__unit__.__build__ or .__hermetic__.__build__
+ if not filename.startswith("libc.test."):
+ return False
+ if not (
+ filename.endswith(".__unit__.__build__")
+ or filename.endswith(".__hermetic__.__build__")
+ ):
+ return False
+ # Must be executable
+ if not os.path.isfile(filepath):
+ return False
+ if not os.access(filepath, os.X_OK):
+ return False
+ return True
+
+ def execute(self, test, litConfig):
+ """
+ Execute a test by running the test executable.
+
+ Runs from the executable's directory so relative paths (like
+ testdata/test.txt) work correctly.
+ """
+
+ testPath = test.getSourcePath()
+ execDir = os.path.dirname(testPath)
+
+ out, err, exitCode = lit.util.executeCommand(testPath, cwd=execDir)
+
+ if not exitCode:
+ return lit.Test.PASS, ""
+
+ return lit.Test.FAIL, out + err
>From de2b51f4266e716bbc14ce8a32bd863e6cfd9af4 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jeffbailey at google.com>
Date: Fri, 30 Jan 2026 17:31:36 +0000
Subject: [PATCH 2/2] [libc] Refactor lit configuration and add executor
support
Streamline the lit test infrastructure for `libc` by simplifying the
CMake logic, cleaning up the configuration files, and adding support for
test executors (e.g., QEMU).
Key changes:
- **Simplified CMake**: Inlined lit configuration logic into `libc/test/CMakeLists.txt`
and removed the separate `LLVMLibCLitTestRules.cmake` module.
- **Cleaned up lit configs**: Removed redundant configuration values and the
`lit.llvm.initialize()` call from `lit.site.cfg.py.in`.
- **Renamed test format**: Moved `LibcTestFormat` to `libctest` in `libc/utils/`
to follow Pythonic naming conventions while maintaining the `site.addsitedir`
pattern used by other LLVM runtimes.
- **Added executor support**: Introduced `LIBC_TEST_CMD` to allow tests to be
run via an external command. The `@BINARY@` placeholder in the command string
is automatically replaced with the path to the test executable.
- **Canary Guard**: Updated `libc/test/lit.cfg.py` to prevent direct execution
of lit in the source tree, ensuring users go through `llvm-lit` in the build
directory.
These changes address feedback from @boomanaiden154, @petrhosek, @michaelrj-google, and @voltur01.
---
libc/cmake/modules/LLVMLibCLitTestRules.cmake | 85 -------------------
libc/cmake/modules/LLVMLibCRules.cmake | 1 -
libc/test/CMakeLists.txt | 18 +++-
libc/test/lit.cfg.py | 52 +++---------
libc/test/lit.site.cfg.py.in | 46 ++++++----
.../{LibcTestFormat => libctest}/__init__.py | 0
.../{LibcTestFormat => libctest}/format.py | 20 +++--
7 files changed, 70 insertions(+), 152 deletions(-)
delete mode 100644 libc/cmake/modules/LLVMLibCLitTestRules.cmake
rename libc/utils/{LibcTestFormat => libctest}/__init__.py (100%)
rename libc/utils/{LibcTestFormat => libctest}/format.py (81%)
diff --git a/libc/cmake/modules/LLVMLibCLitTestRules.cmake b/libc/cmake/modules/LLVMLibCLitTestRules.cmake
deleted file mode 100644
index bfe59239a1b51..0000000000000
--- a/libc/cmake/modules/LLVMLibCLitTestRules.cmake
+++ /dev/null
@@ -1,85 +0,0 @@
-#===============================================================================
-# Lit Test Infrastructure for LLVM libc
-#
-# This module provides functions to set up lit-based testing for libc.
-#
-# Lit discovers and runs the test executables created by the
-# add_libc_test() infrastructure. No separate build rules are needed.
-#===============================================================================
-
-# Guard against double inclusion
-if(LIBC_LIT_TEST_RULES_INCLUDED)
- return()
-endif()
-set(LIBC_LIT_TEST_RULES_INCLUDED TRUE)
-
-# Include LLVM's lit infrastructure
-include(AddLLVM)
-
-#-------------------------------------------------------------------------------
-# configure_libc_lit_site_cfg()
-#
-# Configures the lit.site.cfg.py file from its template.
-# This should be called once from libc/test/CMakeLists.txt.
-#-------------------------------------------------------------------------------
-function(configure_libc_lit_site_cfg)
- # Set variables for the template
- set(LIBC_SOURCE_DIR "${LIBC_SOURCE_DIR}")
- set(LIBC_BINARY_DIR "${LIBC_BUILD_DIR}")
-
- # Configure the site config file
- configure_lit_site_cfg(
- ${LIBC_SOURCE_DIR}/test/lit.site.cfg.py.in
- ${LIBC_BUILD_DIR}/test/lit.site.cfg.py
- MAIN_CONFIG
- ${LIBC_SOURCE_DIR}/test/lit.cfg.py
- PATHS
- "LLVM_SOURCE_DIR"
- "LLVM_BINARY_DIR"
- "LLVM_TOOLS_DIR"
- "LLVM_LIBS_DIR"
- "LIBC_SOURCE_DIR"
- "LIBC_BINARY_DIR"
- )
-endfunction()
-
-#-------------------------------------------------------------------------------
-# add_libc_lit_testsuite()
-#
-# Creates a lit test suite target for a specific test directory.
-#
-# Usage:
-# add_libc_lit_testsuite(check-libc-ctype
-# SUITE_NAME ctype
-# TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/ctype
-# DEPENDS libc-ctype-tests
-# )
-#
-# Note: TEST_DIR should be the build directory where test executables are
-# located, not the source directory.
-#-------------------------------------------------------------------------------
-function(add_libc_lit_testsuite target_name)
- cmake_parse_arguments(
- "LIT_SUITE"
- "" # No optional arguments
- "SUITE_NAME;TEST_DIR" # Single value arguments
- "DEPENDS" # Multi value arguments
- ${ARGN}
- )
-
- if(NOT LIT_SUITE_TEST_DIR)
- message(FATAL_ERROR "add_libc_lit_testsuite requires TEST_DIR")
- endif()
-
- # Create the lit test target using LLVM's infrastructure
- add_lit_testsuite(${target_name}
- "Running ${LIT_SUITE_SUITE_NAME} libc tests"
- ${LIT_SUITE_TEST_DIR}
- DEPENDS ${LIT_SUITE_DEPENDS}
- )
-
- # Add to the umbrella check-libc-lit target if it exists
- if(TARGET check-libc-lit)
- add_dependencies(check-libc-lit ${target_name})
- endif()
-endfunction()
diff --git a/libc/cmake/modules/LLVMLibCRules.cmake b/libc/cmake/modules/LLVMLibCRules.cmake
index 029ecc390128d..76f3892eeb32e 100644
--- a/libc/cmake/modules/LLVMLibCRules.cmake
+++ b/libc/cmake/modules/LLVMLibCRules.cmake
@@ -4,4 +4,3 @@ include(LLVMLibCFlagRules)
include(LLVMLibCObjectRules)
include(LLVMLibCLibraryRules)
include(LLVMLibCTestRules)
-include(LLVMLibCLitTestRules)
diff --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index 30e4c4239174e..88663367feb04 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -10,9 +10,21 @@ add_custom_target(libc-long-running-tests)
add_custom_target(libc-unit-tests-build)
add_custom_target(libc-hermetic-tests-build)
-# Configure lit test infrastructure
-# Lit depends on build-only targets so tests aren't run during build
-configure_libc_lit_site_cfg()
+# Configure the site config file for lit
+configure_lit_site_cfg(
+ ${LIBC_SOURCE_DIR}/test/lit.site.cfg.py.in
+ ${LIBC_BUILD_DIR}/test/lit.site.cfg.py
+ MAIN_CONFIG
+ ${LIBC_SOURCE_DIR}/test/lit.cfg.py
+ PATHS
+ "LLVM_SOURCE_DIR"
+ "LLVM_BINARY_DIR"
+ "LLVM_TOOLS_DIR"
+ "LLVM_LIBS_DIR"
+ "LIBC_SOURCE_DIR"
+ "LIBC_BUILD_DIR"
+)
+
add_lit_testsuite(check-libc-lit
"Running libc tests via lit"
${LIBC_BUILD_DIR}/test
diff --git a/libc/test/lit.cfg.py b/libc/test/lit.cfg.py
index 9cc9f6be446cf..9791a24f9a56e 100644
--- a/libc/test/lit.cfg.py
+++ b/libc/test/lit.cfg.py
@@ -4,46 +4,14 @@
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
-# ===----------------------------------------------------------------------===##
+# All the Lit configuration is handled in the site config -- this file is only
+# left as a canary to catch invocations of Lit that do not go through llvm-lit.
#
-# This is the lit configuration for LLVM libc tests.
-#
-# ===----------------------------------------------------------------------===##
-
-import os
-import site
-import sys
-
-import lit.formats
-import lit.util
-
-# Add libc's utils directory to the path so we can import the test format
-site.addsitedir(os.path.join(config.libc_src_root, "utils"))
-import LibcTestFormat
-
-# Configuration file for the 'lit' test runner.
-
-# name: The name of this test suite.
-config.name = "libc"
-
-# testFormat: Use libc's custom test format that discovers pre-built
-# test executables (Libc*Tests) in the build directory.
-config.test_format = LibcTestFormat.LibcTest()
-
-# suffixes: Not used by LibcTest format, but kept for compatibility
-config.suffixes = []
-
-# excludes: A list of directories to exclude from the testsuite.
-config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt", "UnitTest"]
-
-# test_source_root: The root path where tests are located.
-# test_exec_root: The root path where test executables are built.
-# Set both to the build directory so ExecutableTest finds executables correctly.
-config.test_exec_root = os.path.join(config.libc_obj_root, "test")
-config.test_source_root = config.test_exec_root
-
-# Add tool directories to PATH (in case we add FileCheck tests later)
-if hasattr(config, "llvm_tools_dir") and config.llvm_tools_dir:
- config.environment["PATH"] = os.path.pathsep.join(
- [config.llvm_tools_dir, config.environment.get("PATH", "")]
- )
+# Invocations that go through llvm-lit will automatically use the right Lit
+# site configuration inside the build directory.
+
+lit_config.fatal(
+ "You seem to be running Lit directly -- you should be running Lit through "
+ "<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
+ "file is used."
+)
diff --git a/libc/test/lit.site.cfg.py.in b/libc/test/lit.site.cfg.py.in
index b4fd7d07ba716..87a5649e4ba6a 100644
--- a/libc/test/lit.site.cfg.py.in
+++ b/libc/test/lit.site.cfg.py.in
@@ -1,23 +1,37 @@
@LIT_SITE_CFG_IN_HEADER@
-import sys
import os
+import site
# Configuration values from CMake
-config.llvm_src_root = path(r"@LLVM_SOURCE_DIR@")
-config.llvm_obj_root = path(r"@LLVM_BINARY_DIR@")
config.llvm_tools_dir = lit_config.substitute(path(r"@LLVM_TOOLS_DIR@"))
-config.llvm_libs_dir = lit_config.substitute(path(r"@LLVM_LIBS_DIR@"))
config.libc_src_root = path(r"@LIBC_SOURCE_DIR@")
-config.libc_obj_root = path(r"@LIBC_BINARY_DIR@")
-config.target_triple = "@LLVM_TARGET_TRIPLE@"
-config.host_triple = "@LLVM_HOST_TRIPLE@"
-config.python_executable = "@Python3_EXECUTABLE@"
-
-# Initialize lit.llvm module
-import lit.llvm
-lit.llvm.initialize(lit_config, config)
-
-# Let the main config do the real work.
-lit_config.load_config(
- config, os.path.join(config.libc_src_root, "test/lit.cfg.py"))
+config.libc_obj_root = path(r"@LIBC_BUILD_DIR@")
+config.libc_test_cmd = "@LIBC_TEST_CMD@"
+
+# Add libc's utils directory to the path so we can import the test format.
+site.addsitedir(os.path.join(config.libc_src_root, "utils"))
+import libctest
+
+# name: The name of this test suite.
+config.name = "libc"
+
+# testFormat: Use libc's custom test format that discovers pre-built
+# test executables (Libc*Tests) in the build directory.
+config.test_format = libctest.LibcTest()
+
+# excludes: A list of directories to exclude from the testsuite.
+config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt", "UnitTest"]
+
+# test_source_root: The root path where tests are located.
+# test_exec_root: The root path where test executables are built.
+# Set both to the build directory so ExecutableTest finds executables correctly.
+config.test_exec_root = os.path.join(config.libc_obj_root, "test")
+config.test_source_root = config.test_exec_root
+
+# Add tool directories to PATH (in case we add FileCheck tests later).
+if hasattr(config, "llvm_tools_dir") and config.llvm_tools_dir:
+ config.environment["PATH"] = os.path.pathsep.join(
+ [config.llvm_tools_dir, config.environment.get("PATH", "")]
+ )
+
diff --git a/libc/utils/LibcTestFormat/__init__.py b/libc/utils/libctest/__init__.py
similarity index 100%
rename from libc/utils/LibcTestFormat/__init__.py
rename to libc/utils/libctest/__init__.py
diff --git a/libc/utils/LibcTestFormat/format.py b/libc/utils/libctest/format.py
similarity index 81%
rename from libc/utils/LibcTestFormat/format.py
rename to libc/utils/libctest/format.py
index 8b641f169e243..df7d402799762 100644
--- a/libc/utils/LibcTestFormat/format.py
+++ b/libc/utils/libctest/format.py
@@ -23,6 +23,7 @@
"""
import os
+import shlex
import lit.formats
import lit.Test
@@ -52,7 +53,8 @@ def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
if not os.path.isdir(source_path):
return
- for filename in os.listdir(source_path):
+ # Sort for deterministic test discovery/output ordering.
+ for filename in sorted(os.listdir(source_path)):
filepath = os.path.join(source_path, filename)
# Match our test executable pattern
@@ -85,12 +87,20 @@ def execute(self, test, litConfig):
testdata/test.txt) work correctly.
"""
- testPath = test.getSourcePath()
- execDir = os.path.dirname(testPath)
+ test_path = test.getSourcePath()
+ exec_dir = os.path.dirname(test_path)
- out, err, exitCode = lit.util.executeCommand(testPath, cwd=execDir)
+ test_cmd_template = getattr(test.config, "libc_test_cmd", "")
+ if test_cmd_template:
+ test_cmd = test_cmd_template.replace("@BINARY@", test_path)
+ cmd_args = shlex.split(test_cmd)
+ if not cmd_args:
+ cmd_args = [test_path]
+ out, err, exit_code = lit.util.executeCommand(cmd_args, cwd=exec_dir)
+ else:
+ out, err, exit_code = lit.util.executeCommand([test_path], cwd=exec_dir)
- if not exitCode:
+ if not exit_code:
return lit.Test.PASS, ""
return lit.Test.FAIL, out + err
More information about the libc-commits
mailing list