Skip to content

Commit 8a90fda

Browse files
committed
Further bugfixes
1 parent d315dce commit 8a90fda

1 file changed

Lines changed: 49 additions & 20 deletions

File tree

‎cuda_core/build_hooks.py‎

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
707707
return wheel_name
708708

709709

710+
@functools.cache
710711
def _find_clang_tidy() -> str | None:
711712
"""The clang-tidy executable of the build environment.
712713
@@ -751,20 +752,40 @@ def _warn_clang_tidy_missing() -> None:
751752
)
752753

753754

754-
def _get_handwritten_cpp_files(compile_command: Sequence[str]) -> list[Path]:
755-
"""The handwritten C++ sources, not Cython-generated ones, that a compiler command line compiles."""
755+
def _partition_handwritten_cpp_files(args: Sequence[str]) -> tuple[list[Path], list[str]]:
756+
"""Split compiler arguments into the handwritten C++ sources and the other arguments.
757+
758+
Cython-generated sources are not handwritten, so they stay among the other
759+
arguments.
760+
"""
756761
handwritten_dir = (_PACKAGE_DIR / "_cpp").resolve()
757-
files: list[Path] = []
758-
for arg in compile_command:
759-
# MSVC passes each C++ source as /Tp<path>, which is removed from the result.
760-
path = Path(arg.removeprefix("/Tp"))
762+
sources: list[Path] = []
763+
other_args: list[str] = []
764+
for arg in args:
765+
path = Path(arg)
761766
if path.suffix == ".cpp" and path.resolve().is_relative_to(handwritten_dir):
762-
files.append(path)
763-
return files
767+
sources.append(path)
768+
else:
769+
other_args.append(arg)
770+
return sources, other_args
771+
772+
773+
def _split_compile_command(compile_command: Sequence[str]) -> tuple[tuple[str, ...], list[str]]:
774+
"""Split a compiler command line into the compiler and its arguments.
775+
776+
The compiler is the leading words that are not options: a compiler launcher
777+
such as sccache or ccache, if any, and the compiler. MSVC options start with
778+
"/", like paths, so there the compiler is the first word only.
779+
"""
780+
n = 1
781+
if sys.platform != "win32":
782+
while n < len(compile_command) and not compile_command[n].startswith("-"):
783+
n += 1
784+
return tuple(compile_command[:n]), list(compile_command[n:])
764785

765786

766787
@functools.cache
767-
def _get_implicit_include_dirs(compiler: str) -> list[str]:
788+
def _get_implicit_include_dirs(compiler: tuple[str, ...]) -> list[str]:
768789
"""The include directories that a GCC-style compiler searches without being told.
769790
770791
They are built into the compiler, so they are not on the command line that
@@ -780,7 +801,7 @@ def _get_implicit_include_dirs(compiler: str) -> list[str]:
780801
return []
781802

782803
result = subprocess.run( # noqa: S603
783-
[compiler, "-E", "-x", "c++", "-", "-v"],
804+
[*compiler, "-E", "-x", "c++", "-", "-v"],
784805
input="",
785806
capture_output=True,
786807
text=True,
@@ -795,7 +816,9 @@ def _get_implicit_include_dirs(compiler: str) -> list[str]:
795816
elif in_list and not line.endswith("(framework directory)"):
796817
dirs.append(line.strip())
797818
if result.returncode != 0 or not dirs:
798-
raise RuntimeError(f"Failed to query the implicit include directories of {compiler}:\n{result.stderr}")
819+
raise RuntimeError(
820+
f"Failed to query the implicit include directories of {' '.join(compiler)}:\n{result.stderr}"
821+
)
799822
return dirs
800823

801824

@@ -809,22 +832,28 @@ def check_with_clang_tidy(compile_command: Sequence[str]) -> None:
809832
finding into an error. Raises RuntimeError with the findings.
810833
811834
When clang-tidy is not installed, the check is skipped with a prominent
812-
warning.
835+
warning, whether or not the command compiles a handwritten source.
813836
"""
814-
sources = _get_handwritten_cpp_files(compile_command)
815-
if not sources:
816-
return
817-
(source,) = sources
818837
clang_tidy = _find_clang_tidy()
819838
if clang_tidy is None:
820839
_warn_clang_tidy_missing()
821840
return
841+
compiler, args = _split_compile_command(compile_command)
842+
# MSVC passes each C++ source as /Tp<path>.
843+
args = [arg.removeprefix("/Tp") for arg in args]
844+
sources, args = _partition_handwritten_cpp_files(args)
845+
if not sources:
846+
return
847+
(source,) = sources
822848
config = Path(__file__).resolve().parent / ".clang-tidy"
823-
implicit_includes: list[str] = []
824-
for include_dir in _get_implicit_include_dirs(compile_command[0]):
825-
implicit_includes.extend(["-isystem", include_dir])
849+
if sys.platform == "win32":
850+
# Without this clang-tidy reads the MSVC options, such as /std:c++17,
851+
# as file names.
852+
args.insert(0, "--driver-mode=cl")
853+
for include_dir in _get_implicit_include_dirs(compiler):
854+
args.extend(["-isystem", include_dir])
826855
result = subprocess.run( # noqa: S603
827-
[clang_tidy, f"--config-file={config}", "--quiet", source, "--", *compile_command, *implicit_includes],
856+
[clang_tidy, f"--config-file={config}", "--quiet", source, "--", *args],
828857
capture_output=True,
829858
text=True,
830859
)

0 commit comments

Comments
 (0)