forked from deepseek-ai/FlashMLA
-
Notifications
You must be signed in to change notification settings - Fork 5
校验 MACA 构建环境 #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ghangz
wants to merge
3
commits into
MetaX-MACA:main
Choose a base branch
from
ghangz:mengz/validate-maca-build-env
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
校验 MACA 构建环境 #21
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Build-time helpers for FlashMLA.""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| import os | ||
| import shutil | ||
| from dataclasses import dataclass | ||
| from pathlib import Path | ||
| from typing import Callable, Mapping | ||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class MacaBuildEnv: | ||
| maca_path: Path | None | ||
| cuda_path: Path | None | ||
| maca_clang_path: Path | None | ||
| maca_lib_path: Path | None | ||
| cucc_path: Path | None | ||
|
|
||
|
|
||
| def _path_from_env(env: Mapping[str, str], name: str) -> Path | None: | ||
| value = env.get(name) | ||
| cleaned = value.strip() if value else None | ||
| return Path(cleaned).expanduser() if cleaned else None | ||
|
|
||
|
|
||
| def _candidate_file(path: Path | None, relative: str) -> Path | None: | ||
| return path / relative if path is not None else None | ||
|
|
||
|
|
||
| def _find_executable( | ||
| name: str, | ||
| candidates: list[Path | None], | ||
| which: Callable[[str], str | None] = shutil.which, | ||
| ) -> Path | None: | ||
| for candidate in candidates: | ||
| if candidate is not None and candidate.is_file(): | ||
| return candidate | ||
| resolved = which(name) | ||
| return Path(resolved) if resolved else None | ||
|
|
||
|
|
||
| def resolve_maca_build_env( | ||
| env: Mapping[str, str] | None = None, | ||
| which: Callable[[str], str | None] = shutil.which, | ||
| ) -> MacaBuildEnv: | ||
| env = os.environ if env is None else env | ||
| maca_path = _path_from_env(env, "MACA_PATH") | ||
| cuda_path = ( | ||
| _path_from_env(env, "CUDA_HOME") | ||
| or _path_from_env(env, "CUDA_PATH") | ||
| or (maca_path / "tools" / "cu-bridge" if maca_path else None) | ||
| ) | ||
| maca_clang_path = _path_from_env(env, "MACA_CLANG_PATH") or ( | ||
| maca_path / "mxgpu_llvm" / "bin" if maca_path else None | ||
| ) | ||
| maca_lib_path = maca_path / "lib" if maca_path else None | ||
| cucc_path = _find_executable( | ||
| "cucc", | ||
| [ | ||
| _candidate_file(cuda_path, "bin/cucc"), | ||
| _candidate_file(maca_clang_path, "cucc"), | ||
| ], | ||
| which=which, | ||
| ) | ||
| return MacaBuildEnv( | ||
| maca_path=maca_path, | ||
| cuda_path=cuda_path, | ||
| maca_clang_path=maca_clang_path, | ||
| maca_lib_path=maca_lib_path, | ||
| cucc_path=cucc_path, | ||
| ) | ||
|
|
||
|
|
||
| def validate_maca_build_env(build_env: MacaBuildEnv) -> list[str]: | ||
| errors: list[str] = [] | ||
| required_dirs = { | ||
| "MACA_PATH": build_env.maca_path, | ||
| "CUDA_HOME/CUDA_PATH": build_env.cuda_path, | ||
| "MACA_CLANG_PATH": build_env.maca_clang_path, | ||
| "MACA library directory": build_env.maca_lib_path, | ||
| } | ||
| for label, path in required_dirs.items(): | ||
| if path is None: | ||
| errors.append(f"{label} is not configured") | ||
| elif not path.is_dir(): | ||
| errors.append(f"{label} does not exist or is not a directory: {path}") | ||
|
|
||
| if build_env.cucc_path is None: | ||
| errors.append("cucc compiler was not found in CUDA_HOME/bin, MACA_CLANG_PATH, or PATH") | ||
| elif not build_env.cucc_path.is_file(): | ||
| errors.append(f"cucc compiler path is not a file: {build_env.cucc_path}") | ||
|
|
||
| return errors | ||
|
|
||
|
|
||
| def format_maca_build_env_errors(errors: list[str]) -> str: | ||
| hint = ( | ||
| "Set MACA_PATH to the MACA toolkit root, CUDA_HOME or CUDA_PATH to " | ||
| "$MACA_PATH/tools/cu-bridge, and MACA_CLANG_PATH to " | ||
| "$MACA_PATH/mxgpu_llvm/bin before building FlashMLA from source." | ||
| ) | ||
| return "Invalid MACA build environment:\n- " + "\n- ".join(errors) + "\n" + hint |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| import sys | ||
| import unittest | ||
| from pathlib import Path | ||
| from tempfile import TemporaryDirectory | ||
|
|
||
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | ||
|
|
||
| from build_tools.maca_env import ( | ||
| format_maca_build_env_errors, | ||
| resolve_maca_build_env, | ||
| validate_maca_build_env, | ||
| ) | ||
|
|
||
|
|
||
| class MacaEnvTest(unittest.TestCase): | ||
| def test_resolve_maca_build_env_defaults_to_cu_bridge(self): | ||
| with TemporaryDirectory() as tmp_dir: | ||
| tmp_path = Path(tmp_dir) | ||
| maca_path = tmp_path / "maca" | ||
| cuda_path = maca_path / "tools" / "cu-bridge" | ||
| clang_path = maca_path / "mxgpu_llvm" / "bin" | ||
| for path in (cuda_path / "bin", clang_path, maca_path / "lib"): | ||
| path.mkdir(parents=True) | ||
| cucc = cuda_path / "bin" / "cucc" | ||
| cucc.write_text("#!/bin/sh\n", encoding="utf-8") | ||
|
|
||
| build_env = resolve_maca_build_env({"MACA_PATH": str(maca_path)}, which=lambda _: None) | ||
|
|
||
| self.assertEqual(build_env.maca_path, maca_path) | ||
| self.assertEqual(build_env.cuda_path, cuda_path) | ||
| self.assertEqual(build_env.maca_clang_path, clang_path) | ||
| self.assertEqual(build_env.maca_lib_path, maca_path / "lib") | ||
| self.assertEqual(build_env.cucc_path, cucc) | ||
| self.assertEqual(validate_maca_build_env(build_env), []) | ||
|
|
||
| def test_validate_maca_build_env_reports_missing_paths(self): | ||
| build_env = resolve_maca_build_env({}, which=lambda _: None) | ||
|
|
||
| errors = validate_maca_build_env(build_env) | ||
|
|
||
| self.assertIn("MACA_PATH is not configured", errors) | ||
| self.assertTrue(any("cucc compiler was not found" in error for error in errors)) | ||
| self.assertIn("Invalid MACA build environment", format_maca_build_env_errors(errors)) | ||
|
|
||
| def test_resolve_maca_build_env_uses_path_cucc(self): | ||
| with TemporaryDirectory() as tmp_dir: | ||
| tmp_path = Path(tmp_dir) | ||
| maca_path = tmp_path / "maca" | ||
| cuda_path = tmp_path / "cu-bridge" | ||
| clang_path = tmp_path / "clang" | ||
| path_cucc = tmp_path / "bin" / "cucc" | ||
| for path in (maca_path / "lib", cuda_path, clang_path, path_cucc.parent): | ||
| path.mkdir(parents=True) | ||
| path_cucc.write_text("#!/bin/sh\n", encoding="utf-8") | ||
|
|
||
| build_env = resolve_maca_build_env( | ||
| { | ||
| "MACA_PATH": str(maca_path), | ||
| "CUDA_PATH": str(cuda_path), | ||
| "MACA_CLANG_PATH": str(clang_path), | ||
| }, | ||
| which=lambda _: str(path_cucc), | ||
| ) | ||
|
|
||
| self.assertEqual(build_env.cucc_path, path_cucc) | ||
| self.assertEqual(validate_maca_build_env(build_env), []) | ||
|
|
||
| def test_resolve_maca_build_env_strips_whitespace(self): | ||
| with TemporaryDirectory() as tmp_dir: | ||
| tmp_path = Path(tmp_dir) | ||
| maca_path = tmp_path / "maca" | ||
| for path in (maca_path / "tools" / "cu-bridge" / "bin", maca_path / "mxgpu_llvm" / "bin", maca_path / "lib"): | ||
| path.mkdir(parents=True) | ||
| cucc = maca_path / "tools" / "cu-bridge" / "bin" / "cucc" | ||
| cucc.write_text("#!/bin/sh\n", encoding="utf-8") | ||
|
|
||
| build_env = resolve_maca_build_env( | ||
| {"MACA_PATH": f" {maca_path} "}, | ||
| which=lambda _: None, | ||
| ) | ||
|
|
||
| self.assertEqual(build_env.maca_path, maca_path) | ||
| self.assertEqual(build_env.cucc_path, cucc) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since
build_toolshas been turned into a Python package by addingbuild_tools/__init__.py,setuptools.find_packages()will automatically detect and package it. This will result inbuild_toolsbeing installed as a top-level package in the user's Python environment, polluting the global namespace.To prevent this, please add
"build_tools"to theexcludelist offind_packagesinsetup.py(around line 340).