[llvm] Introduce a new CMake option to test LLVM_WINDOWS_PREFER_FORWARD_SLASH behaviors (PR #207194)

Junji Watanabe via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 2 07:26:21 PDT 2026


https://github.com/Jwata created https://github.com/llvm/llvm-project/pull/207194

This PR introduces LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX which selectively enables tests with both LLVM_WINDOWS_PREFER_FORWARD_SLASH=1 and LLVM_WINDOWS_PREFER_FORWARD_SLASH=0.

>From 16db7ded36d08aa8799ec1484f9ff599b0f44a04 Mon Sep 17 00:00:00 2001
From: Junji Watanabe <jwata at google.com>
Date: Thu, 25 Jun 2026 17:03:19 +0900
Subject: [PATCH 1/2] Implement lit matrix testing for Windows path preferences

- Add LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX CMake option to support testing both backslash and forward-slash styles in a single lit invocation.

- Vary GTest configuration names in matrix mode to prevent JSON shard report collisions.
---
 llvm/CMakeLists.txt               |   1 +
 llvm/test/CMakeLists.txt          | 107 +++++++++++++++++++++++-------
 llvm/test/Unit/lit.cfg.py         |  16 ++++-
 llvm/test/Unit/lit.site.cfg.py.in |   2 +
 llvm/test/lit.cfg.py              |  15 ++++-
 llvm/test/lit.site.cfg.py.in      |   2 +
 6 files changed, 115 insertions(+), 28 deletions(-)

diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index cec5462ae02a1..e660db7d6ec83 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -643,6 +643,7 @@ if (MINGW)
   set(WINDOWS_PREFER_FORWARD_SLASH_DEFAULT ON)
 endif()
 option(LLVM_WINDOWS_PREFER_FORWARD_SLASH "Prefer path names with forward slashes on Windows." ${WINDOWS_PREFER_FORWARD_SLASH_DEFAULT})
+option(LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX "Test both forward and backward slashes on Windows during testing." OFF)
 
 option(LLVM_ENABLE_FFI "Use libffi to call external functions from the interpreter" OFF)
 set(FFI_LIBRARY_DIR "" CACHE PATH "Additional directory, where CMake should search for libffi.so")
diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt
index 201f0ee86d7ff..ad3a0be993afc 100644
--- a/llvm/test/CMakeLists.txt
+++ b/llvm/test/CMakeLists.txt
@@ -34,30 +34,89 @@ llvm_canonicalize_cmake_booleans(
   LLVM_HAVE_OPENCSD
   )
 
-configure_lit_site_cfg(
-  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
-  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
-  MAIN_CONFIG
-  ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
-  PATHS
-  "CMAKE_OSX_SYSROOT"
-  "LLVM_SOURCE_DIR"
-  "LLVM_BINARY_DIR"
-  "LLVM_TOOLS_DIR"
-  "LLVM_LIBS_DIR"
-  "SHLIBDIR"
-  )
-configure_lit_site_cfg(
-  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
-  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
-  MAIN_CONFIG
-  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
-  PATHS
-  "LLVM_SOURCE_DIR"
-  "LLVM_BINARY_DIR"
-  "LLVM_TOOLS_DIR"
-  "SHLIBDIR"
-  )
+if (LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX)
+  # Configure unit tests matrix
+  set(LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL "0")
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit/default/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
+    PATHS
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "SHLIBDIR"
+    )
+  set(LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL "1")
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit/forward_slash/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
+    PATHS
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "SHLIBDIR"
+    )
+
+  # Configure integration tests matrix
+  set(LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL "0")
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/default/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
+    PATHS
+    "CMAKE_OSX_SYSROOT"
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "LLVM_LIBS_DIR"
+    "SHLIBDIR"
+    )
+  set(LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL "1")
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/forward_slash/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
+    PATHS
+    "CMAKE_OSX_SYSROOT"
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "LLVM_LIBS_DIR"
+    "SHLIBDIR"
+    )
+else()
+  set(LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL "")
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
+    PATHS
+    "CMAKE_OSX_SYSROOT"
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "LLVM_LIBS_DIR"
+    "SHLIBDIR"
+    )
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
+    MAIN_CONFIG
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
+    PATHS
+    "LLVM_SOURCE_DIR"
+    "LLVM_BINARY_DIR"
+    "LLVM_TOOLS_DIR"
+    "SHLIBDIR"
+    )
+endif()
 
 # Set the depends list as a variable so that it can grow conditionally.
 # NOTE: Sync the substitutions in test/lit.cfg when adding to this list.
diff --git a/llvm/test/Unit/lit.cfg.py b/llvm/test/Unit/lit.cfg.py
index e29fd76bd8dcc..307bd7917bf29 100644
--- a/llvm/test/Unit/lit.cfg.py
+++ b/llvm/test/Unit/lit.cfg.py
@@ -8,7 +8,11 @@
 import lit.formats
 
 # name: The name of this test suite.
-config.name = "LLVM-Unit"
+suffix = getattr(config, "llvm_windows_prefer_forward_slash", "")
+if suffix in ("1", "ON", "True"):
+    config.name = "LLVM-Unit-ForwardSlash"
+else:
+    config.name = "LLVM-Unit"
 
 # suffixes: A list of file extensions to treat as test files.
 config.suffixes = []
@@ -37,6 +41,16 @@
 if "HOME" in os.environ:
     config.environment["HOME"] = os.environ["HOME"]
 
+prefer_forward_slash = getattr(config, "llvm_windows_prefer_forward_slash", "")
+if prefer_forward_slash in ("1", "ON", "True"):
+    config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "1"
+elif prefer_forward_slash in ("0", "OFF", "False"):
+    config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "0"
+elif "LLVM_WINDOWS_PREFER_FORWARD_SLASH" in os.environ:
+    config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = os.environ[
+        "LLVM_WINDOWS_PREFER_FORWARD_SLASH"
+    ]
+
 # Propagate sanitizer options.
 for var in [
     "ASAN_SYMBOLIZER_PATH",
diff --git a/llvm/test/Unit/lit.site.cfg.py.in b/llvm/test/Unit/lit.site.cfg.py.in
index 3536a34f796a2..bffec61b5b626 100644
--- a/llvm/test/Unit/lit.site.cfg.py.in
+++ b/llvm/test/Unit/lit.site.cfg.py.in
@@ -9,6 +9,8 @@ config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@")
 config.shlibdir = lit_config.substitute(path(r"@SHLIBDIR@"))
 config.gtest_run_under = lit_config.substitute(r"@LLVM_GTEST_RUN_UNDER@")
 
+config.llvm_windows_prefer_forward_slash = "@LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL@"
+
 # Let the main config do the real work.
 lit_config.load_config(
     config, os.path.join(config.llvm_src_root, "test/Unit/lit.cfg.py"))
diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index 09df1e3fd6281..2662566741d8d 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -15,7 +15,11 @@
 from lit.llvm.subst import ToolSubst
 
 # name: The name of this test suite.
-config.name = "LLVM"
+suffix = getattr(config, "llvm_windows_prefer_forward_slash", "")
+if suffix in ("1", "ON", "True"):
+    config.name = "LLVM-ForwardSlash"
+else:
+    config.name = "LLVM"
 
 # TODO: Consolidate the logic for turning on the internal shell by default for all LLVM test suites.
 # See https://github.com/llvm/llvm-project/issues/106636 for more details.
@@ -102,8 +106,13 @@
 # Tweak the PATH to include the tools dir.
 llvm_config.with_environment("PATH", config.llvm_tools_dir, append_path=True)
 
-# Propagate some variables from the host environment.
-llvm_config.with_system_environment(["HOME", "INCLUDE", "LIB", "TMP", "TEMP"])
+llvm_config.with_system_environment(["HOME", "INCLUDE", "LIB", "TMP", "TEMP", "LLVM_WINDOWS_PREFER_FORWARD_SLASH"])
+
+prefer_forward_slash = getattr(config, "llvm_windows_prefer_forward_slash", "")
+if prefer_forward_slash in ("1", "ON", "True"):
+    config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "1"
+elif prefer_forward_slash in ("0", "OFF", "False"):
+    config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "0"
 
 
 # Set up OCAMLPATH to include newly built OCaml libraries.
diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in
index 64679c2f64034..77919ae20068d 100644
--- a/llvm/test/lit.site.cfg.py.in
+++ b/llvm/test/lit.site.cfg.py.in
@@ -74,6 +74,8 @@ config.have_opencsd = @LLVM_HAVE_OPENCSD@
 import lit.llvm
 lit.llvm.initialize(lit_config, config)
 
+config.llvm_windows_prefer_forward_slash = "@LLVM_WINDOWS_PREFER_FORWARD_SLASH_VAL@"
+
 # Let the main config do the real work.
 lit_config.load_config(
     config, os.path.join(config.llvm_src_root, "test/lit.cfg.py"))

>From 7c4cdb46176d60c2930432c841951710f81a85fc Mon Sep 17 00:00:00 2001
From: Junji Watanabe <jwata at google.com>
Date: Thu, 2 Jul 2026 23:12:55 +0900
Subject: [PATCH 2/2] Improve lit matrix testing stability and speed on Windows

---
 llvm/CMakeLists.txt              |  1 +
 llvm/test/CMakeLists.txt         | 13 ++++++++++++-
 llvm/test/Unit/CMakeLists.txt    | 13 ++++++++++++-
 llvm/test/lit.cfg.py             | 16 +++++++++++++++-
 llvm/utils/lit/lit/TestRunner.py |  4 +++-
 5 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index c2752e2b73c1d..4bb4492211df2 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -652,6 +652,7 @@ endif()
 option(LLVM_WINDOWS_PREFER_FORWARD_SLASH "Prefer path names with forward slashes on Windows." ${WINDOWS_PREFER_FORWARD_SLASH_DEFAULT})
 option(LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX "Test both forward and backward slashes on Windows during testing." OFF)
 
+
 option(LLVM_ENABLE_FFI "Use libffi to call external functions from the interpreter" OFF)
 set(FFI_LIBRARY_DIR "" CACHE PATH "Additional directory, where CMake should search for libffi.so")
 set(FFI_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should search for ffi.h or ffi/ffi.h")
diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt
index ad3a0be993afc..fefaf74b88f6c 100644
--- a/llvm/test/CMakeLists.txt
+++ b/llvm/test/CMakeLists.txt
@@ -323,8 +323,19 @@ else()
   set(exclude_from_check_all "EXCLUDE_FROM_CHECK_ALL")
 endif()
 
+if (LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX)
+  set(LLVM_TEST_PATHS
+    ${CMAKE_CURRENT_BINARY_DIR}/default
+    ${CMAKE_CURRENT_BINARY_DIR}/forward_slash
+    )
+else()
+  set(LLVM_TEST_PATHS
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+endif()
+
 add_lit_testsuite(check-llvm "Running the LLVM regression tests"
-  ${CMAKE_CURRENT_BINARY_DIR}
+  ${LLVM_TEST_PATHS}
   ${exclude_from_check_all}
   DEPENDS ${LLVM_TEST_DEPENDS} UnitTests
   )
diff --git a/llvm/test/Unit/CMakeLists.txt b/llvm/test/Unit/CMakeLists.txt
index 6b0abe199673f..01e97b6d45c8e 100644
--- a/llvm/test/Unit/CMakeLists.txt
+++ b/llvm/test/Unit/CMakeLists.txt
@@ -1,5 +1,16 @@
+if (LLVM_TEST_WINDOWS_PREFER_FORWARD_SLASH_MATRIX)
+  set(LLVM_UNIT_TEST_PATHS
+    ${CMAKE_CURRENT_BINARY_DIR}/default
+    ${CMAKE_CURRENT_BINARY_DIR}/forward_slash
+    )
+else()
+  set(LLVM_UNIT_TEST_PATHS
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+endif()
+
 add_lit_testsuite(check-llvm-unit "Running lit suite for LLVM unit tests"
-  ${CMAKE_CURRENT_BINARY_DIR}
+  ${LLVM_UNIT_TEST_PATHS}
   EXCLUDE_FROM_CHECK_ALL
   DEPENDS UnitTests
   )
diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index 0fc0359d520c3..df2e8ccc50fea 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -101,7 +101,13 @@
 config.test_source_root = os.path.dirname(__file__)
 
 # test_exec_root: The root path where tests should be run.
-config.test_exec_root = os.path.join(config.llvm_obj_root, "test")
+prefer_forward_slash = getattr(config, "llvm_windows_prefer_forward_slash", "")
+if prefer_forward_slash != "":
+    # In matrix mode, test_exec_root is already set by the site config
+    # loading path, e.g. build_all/test/default or build_all/test/forward_slash.
+    pass
+else:
+    config.test_exec_root = os.path.join(config.llvm_obj_root, "test")
 
 # Tweak the PATH to include the tools dir.
 llvm_config.with_environment("PATH", config.llvm_tools_dir, append_path=True)
@@ -111,6 +117,14 @@
 prefer_forward_slash = getattr(config, "llvm_windows_prefer_forward_slash", "")
 if prefer_forward_slash in ("1", "ON", "True"):
     config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "1"
+    
+    # Restrict forward-slash testing to a reasonable subset
+    # by excluding directories that don't deal with file paths or formatting
+    forward_slash_subsets = {"DebugInfo", "MC", "Support", "tools", "Unit"}
+    for subdir in os.listdir(config.test_source_root):
+        subdir_path = os.path.join(config.test_source_root, subdir)
+        if os.path.isdir(subdir_path) and subdir not in forward_slash_subsets:
+            config.excludes.append(subdir)
 elif prefer_forward_slash in ("0", "OFF", "False"):
     config.environment["LLVM_WINDOWS_PREFER_FORWARD_SLASH"] = "0"
 
diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
index 1b0f4ad4eebef..54cc25379c744 100644
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -708,7 +708,8 @@ def make_tree(cmds):
 
     results = []
     timeoutInfo = None
-    normalize_slashes = litConfig.params.get("use_normalized_slashes", False)
+    prefer_fs = getattr(test.config, "llvm_windows_prefer_forward_slash", "")
+    normalize_slashes = (prefer_fs in ("1", "ON", "True")) or litConfig.params.get("use_normalized_slashes", False)
     shenv = ShellEnvironment(
         cwd, test.config.environment, normalize_slashes=normalize_slashes
     )
@@ -1937,6 +1938,7 @@ def executeShTest(
         tmpDir,
         tmpBase,
         normalize_slashes=useExternalSh
+        or (getattr(test.config, "llvm_windows_prefer_forward_slash", "") in ("1", "ON", "True"))
         or litConfig.params.get("use_normalized_slashes", False),
     )
     conditions = {feature: True for feature in test.config.available_features}



More information about the llvm-commits mailing list