From 86201a8bc3d1af4643bfa878010bf631b02d0811 Mon Sep 17 00:00:00 2001 From: Xinya Zhang Date: Wed, 2 Sep 2026 16:53:09 +0000 Subject: [PATCH 1/4] [Build] Find ROCm through rocm-sdk before falling back to /opt/rocm* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `find_package(hip)` was pointed at a `/opt/rocm*` glob, so a pip-installed ROCm SDK inside a virtualenv was invisible and the build either picked up an unrelated system ROCm or failed outright. Order is now `ROCM_PATH`, then `rocm-sdk path --root` — the SDK's own query, whose root carries `lib/cmake/hip/hip-config.cmake` — then the original glob. `ERROR_QUIET` plus the empty-output check covers "rocm-sdk absent" and "rocm-sdk failed" the same way, since both fall through. Verified in a scratch project against the real file: resolves via `rocm-sdk`, resolves via `ROCM_PATH` and takes precedence, and with neither available falls back to the glob and then fails at `find_package` — which is right on a host with no system ROCm. This was the only `/opt/rocm` hardcode in the repo's CMake. Co-Authored-By: Claude Opus 5 (1M context) --- lib/Runtime/ROCm/CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Runtime/ROCm/CMakeLists.txt b/lib/Runtime/ROCm/CMakeLists.txt index c4f118c16..627fea28b 100644 --- a/lib/Runtime/ROCm/CMakeLists.txt +++ b/lib/Runtime/ROCm/CMakeLists.txt @@ -3,8 +3,17 @@ # # FlyJitRuntime — thin ROCm runtime with GPU module caching. -file(GLOB _rocm_paths LIST_DIRECTORIES true "/opt/rocm*") -list(SORT _rocm_paths ORDER DESCENDING) +# ROCM_PATH, else the SDK's own answer, else whatever is in /opt. +if(DEFINED ENV{ROCM_PATH}) + set(_rocm_paths "$ENV{ROCM_PATH}") +else() + execute_process(COMMAND rocm-sdk path --root + OUTPUT_VARIABLE _rocm_paths OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) +endif() +if(NOT _rocm_paths) + file(GLOB _rocm_paths LIST_DIRECTORIES true "/opt/rocm*") + list(SORT _rocm_paths ORDER DESCENDING) +endif() find_package(hip REQUIRED CONFIG PATHS ${_rocm_paths}) add_library(FlyJitRuntime SHARED FlyRocmRuntimeWrappers.cpp) From 7d76692f97b50dd6ff0b0f57e88bd41f1713f073 Mon Sep 17 00:00:00 2001 From: Felix Li Date: Mon, 28 Sep 2026 10:44:08 +0000 Subject: [PATCH 2/4] [Build] Prefer selected ROCm SDK when finding HIP --- lib/Runtime/ROCm/CMakeLists.txt | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/Runtime/ROCm/CMakeLists.txt b/lib/Runtime/ROCm/CMakeLists.txt index 627fea28b..a9fdd4e58 100644 --- a/lib/Runtime/ROCm/CMakeLists.txt +++ b/lib/Runtime/ROCm/CMakeLists.txt @@ -3,18 +3,27 @@ # # FlyJitRuntime — thin ROCm runtime with GPU module caching. -# ROCM_PATH, else the SDK's own answer, else whatever is in /opt. -if(DEFINED ENV{ROCM_PATH}) - set(_rocm_paths "$ENV{ROCM_PATH}") -else() +# Prefer an explicitly selected ROCm, then the SDK in the active environment. +# NO_DEFAULT_PATH keeps a system HIP from winning over either one. +if(DEFINED ENV{ROCM_PATH} AND NOT "$ENV{ROCM_PATH}" STREQUAL "") + find_package(hip QUIET CONFIG PATHS "$ENV{ROCM_PATH}" NO_DEFAULT_PATH) +endif() + +if(NOT hip_FOUND) execute_process(COMMAND rocm-sdk path --root - OUTPUT_VARIABLE _rocm_paths OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) + OUTPUT_VARIABLE _rocm_sdk_root + RESULT_VARIABLE _rocm_sdk_result + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) + if(_rocm_sdk_result STREQUAL "0" AND _rocm_sdk_root) + find_package(hip QUIET CONFIG PATHS "${_rocm_sdk_root}" NO_DEFAULT_PATH) + endif() endif() -if(NOT _rocm_paths) + +if(NOT hip_FOUND) file(GLOB _rocm_paths LIST_DIRECTORIES true "/opt/rocm*") list(SORT _rocm_paths ORDER DESCENDING) + find_package(hip REQUIRED CONFIG PATHS ${_rocm_paths}) endif() -find_package(hip REQUIRED CONFIG PATHS ${_rocm_paths}) add_library(FlyJitRuntime SHARED FlyRocmRuntimeWrappers.cpp) target_include_directories(FlyJitRuntime PRIVATE From 6d467347202aaec9ce87ca9741896a3765da3da6 Mon Sep 17 00:00:00 2001 From: Felix Li Date: Tue, 29 Sep 2026 09:16:27 +0000 Subject: [PATCH 3/4] [Build] Test ROCm HIP discovery order --- lib/Runtime/ROCm/CMakeLists.txt | 2 +- tests/unit/test_rocm_cmake_discovery.py | 74 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_rocm_cmake_discovery.py diff --git a/lib/Runtime/ROCm/CMakeLists.txt b/lib/Runtime/ROCm/CMakeLists.txt index a9fdd4e58..bd6adcaed 100644 --- a/lib/Runtime/ROCm/CMakeLists.txt +++ b/lib/Runtime/ROCm/CMakeLists.txt @@ -4,7 +4,7 @@ # FlyJitRuntime — thin ROCm runtime with GPU module caching. # Prefer an explicitly selected ROCm, then the SDK in the active environment. -# NO_DEFAULT_PATH keeps a system HIP from winning over either one. +# NO_DEFAULT_PATH excludes default search locations; a cached hip_DIR still wins. if(DEFINED ENV{ROCM_PATH} AND NOT "$ENV{ROCM_PATH}" STREQUAL "") find_package(hip QUIET CONFIG PATHS "$ENV{ROCM_PATH}" NO_DEFAULT_PATH) endif() diff --git a/tests/unit/test_rocm_cmake_discovery.py b/tests/unit/test_rocm_cmake_discovery.py new file mode 100644 index 000000000..db495ae4b --- /dev/null +++ b/tests/unit/test_rocm_cmake_discovery.py @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 FlyDSL Project Contributors + +"""Check HIP package selection without requiring a ROCm installation.""" + +import os +import shutil +import subprocess +from pathlib import Path + +import pytest + +pytestmark = [pytest.mark.l0_backend_agnostic] + +_ROCM_CMAKE_DIR = Path(__file__).resolve().parents[2] / "lib" / "Runtime" / "ROCm" + + +@pytest.mark.parametrize( + ("rocm_path", "sdk_fails", "expected"), + [ + (None, False, "sdk"), + ("explicit", False, "explicit"), + ("missing", False, "sdk"), + ("", False, "sdk"), + (None, True, "system"), + ], +) +def test_hip_search_order(tmp_path, rocm_path, sdk_fails, expected): + cmake = shutil.which("cmake") + if cmake is None: + pytest.skip("cmake not available") + + for name in ("system", "sdk", "explicit"): + config_dir = tmp_path / name / "lib" / "cmake" / "hip" + config_dir.mkdir(parents=True) + (config_dir / "hip-config.cmake").write_text("""add_library(hip::host INTERFACE IMPORTED) +add_library(hip::amdhip64 INTERFACE IMPORTED) +""") + + tool_dir = tmp_path / "bin" + tool_dir.mkdir() + sdk_tool = tool_dir / "rocm-sdk" + sdk_tool.write_text("""#!/bin/sh +if [ "$FAKE_SDK_FAIL" = "1" ]; then exit 1; fi +printf "%s\\n" "$FAKE_SDK_ROOT" +""") + sdk_tool.chmod(0o755) + + (tmp_path / "CMakeLists.txt").write_text( + "cmake_minimum_required(VERSION 3.20)\n" + "project(HipSearchProbe LANGUAGES CXX)\n" + f'add_subdirectory("{_ROCM_CMAKE_DIR}" runtime)\n' + ) + + env = os.environ.copy() + env["PATH"] = f"{tool_dir}{os.pathsep}{env.get('PATH', '')}" + env["FAKE_SDK_ROOT"] = str(tmp_path / "sdk") + env["FAKE_SDK_FAIL"] = "1" if sdk_fails else "0" + if rocm_path is None: + env.pop("ROCM_PATH", None) + elif rocm_path: + env["ROCM_PATH"] = str(tmp_path / rocm_path) + else: + env["ROCM_PATH"] = "" + + build_dir = tmp_path / "build" + result = subprocess.run( + [cmake, "-S", str(tmp_path), "-B", str(build_dir), f"-DCMAKE_PREFIX_PATH={tmp_path / 'system'}"], + env=env, + text=True, + capture_output=True, + ) + assert result.returncode == 0, result.stdout + result.stderr + assert f"hip_DIR:PATH={tmp_path / expected / 'lib' / 'cmake' / 'hip'}" in (build_dir / "CMakeCache.txt").read_text() From f39f41bf807ada657ce06f8ee95df51230422578 Mon Sep 17 00:00:00 2001 From: Felix Li Date: Tue, 29 Sep 2026 09:28:35 +0000 Subject: [PATCH 4/4] [Build] Keep HIP dependencies on selected ROCm SDK --- lib/Runtime/ROCm/CMakeLists.txt | 13 +++++ tests/unit/test_rocm_cmake_discovery.py | 74 ------------------------- 2 files changed, 13 insertions(+), 74 deletions(-) delete mode 100644 tests/unit/test_rocm_cmake_discovery.py diff --git a/lib/Runtime/ROCm/CMakeLists.txt b/lib/Runtime/ROCm/CMakeLists.txt index bd6adcaed..5aed46f4c 100644 --- a/lib/Runtime/ROCm/CMakeLists.txt +++ b/lib/Runtime/ROCm/CMakeLists.txt @@ -15,7 +15,20 @@ if(NOT hip_FOUND) RESULT_VARIABLE _rocm_sdk_result OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(_rocm_sdk_result STREQUAL "0" AND _rocm_sdk_root) + # HIP's config uses ROCM_PATH to find its dependencies. A stale or empty + # value must not redirect those lookups away from the selected SDK. + set(_rocm_path_was_set FALSE) + if(DEFINED ENV{ROCM_PATH}) + set(_rocm_path_was_set TRUE) + set(_rocm_original_path "$ENV{ROCM_PATH}") + endif() + set(ENV{ROCM_PATH} "${_rocm_sdk_root}") find_package(hip QUIET CONFIG PATHS "${_rocm_sdk_root}" NO_DEFAULT_PATH) + if(_rocm_path_was_set) + set(ENV{ROCM_PATH} "${_rocm_original_path}") + else() + unset(ENV{ROCM_PATH}) + endif() endif() endif() diff --git a/tests/unit/test_rocm_cmake_discovery.py b/tests/unit/test_rocm_cmake_discovery.py deleted file mode 100644 index db495ae4b..000000000 --- a/tests/unit/test_rocm_cmake_discovery.py +++ /dev/null @@ -1,74 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2025 FlyDSL Project Contributors - -"""Check HIP package selection without requiring a ROCm installation.""" - -import os -import shutil -import subprocess -from pathlib import Path - -import pytest - -pytestmark = [pytest.mark.l0_backend_agnostic] - -_ROCM_CMAKE_DIR = Path(__file__).resolve().parents[2] / "lib" / "Runtime" / "ROCm" - - -@pytest.mark.parametrize( - ("rocm_path", "sdk_fails", "expected"), - [ - (None, False, "sdk"), - ("explicit", False, "explicit"), - ("missing", False, "sdk"), - ("", False, "sdk"), - (None, True, "system"), - ], -) -def test_hip_search_order(tmp_path, rocm_path, sdk_fails, expected): - cmake = shutil.which("cmake") - if cmake is None: - pytest.skip("cmake not available") - - for name in ("system", "sdk", "explicit"): - config_dir = tmp_path / name / "lib" / "cmake" / "hip" - config_dir.mkdir(parents=True) - (config_dir / "hip-config.cmake").write_text("""add_library(hip::host INTERFACE IMPORTED) -add_library(hip::amdhip64 INTERFACE IMPORTED) -""") - - tool_dir = tmp_path / "bin" - tool_dir.mkdir() - sdk_tool = tool_dir / "rocm-sdk" - sdk_tool.write_text("""#!/bin/sh -if [ "$FAKE_SDK_FAIL" = "1" ]; then exit 1; fi -printf "%s\\n" "$FAKE_SDK_ROOT" -""") - sdk_tool.chmod(0o755) - - (tmp_path / "CMakeLists.txt").write_text( - "cmake_minimum_required(VERSION 3.20)\n" - "project(HipSearchProbe LANGUAGES CXX)\n" - f'add_subdirectory("{_ROCM_CMAKE_DIR}" runtime)\n' - ) - - env = os.environ.copy() - env["PATH"] = f"{tool_dir}{os.pathsep}{env.get('PATH', '')}" - env["FAKE_SDK_ROOT"] = str(tmp_path / "sdk") - env["FAKE_SDK_FAIL"] = "1" if sdk_fails else "0" - if rocm_path is None: - env.pop("ROCM_PATH", None) - elif rocm_path: - env["ROCM_PATH"] = str(tmp_path / rocm_path) - else: - env["ROCM_PATH"] = "" - - build_dir = tmp_path / "build" - result = subprocess.run( - [cmake, "-S", str(tmp_path), "-B", str(build_dir), f"-DCMAKE_PREFIX_PATH={tmp_path / 'system'}"], - env=env, - text=True, - capture_output=True, - ) - assert result.returncode == 0, result.stdout + result.stderr - assert f"hip_DIR:PATH={tmp_path / expected / 'lib' / 'cmake' / 'hip'}" in (build_dir / "CMakeCache.txt").read_text()