diff --git a/hatch_cpp/tests/test_platform_specific.py b/hatch_cpp/tests/test_platform_specific.py index 162c5d6..34778bd 100644 --- a/hatch_cpp/tests/test_platform_specific.py +++ b/hatch_cpp/tests/test_platform_specific.py @@ -454,3 +454,82 @@ def test_base_list_not_mutated(self): # Base list should not be modified assert library.include_dirs == ["common"] assert library.include_dirs_linux == ["linux"] + + +class TestMSVCPythonLibsPath: + """Tests for MSVC Python libs path discovery.""" + + def test_msvc_link_flags_include_libpath(self): + """Test that MSVC link flags include /LIBPATH for Python libs.""" + library = HatchCppLibrary( + name="test", + sources=["test.cpp"], + binding="generic", # Skip Python.h include + ) + + platform = HatchCppPlatform( + cc="cl", + cxx="cl", + ld="link", + platform="win32", + toolchain="msvc", + disable_ccache=True, + ) + + flags = platform.get_link_flags(library) + # Should have /link /DLL flags + assert "/link" in flags + assert "/DLL" in flags + # Should have output file + assert "/Fe:" in flags + + def test_msvc_link_flags_with_libraries(self): + """Test that MSVC link flags properly format library names.""" + library = HatchCppLibrary( + name="test", + sources=["test.cpp"], + binding="generic", + libraries=["mylib"], + library_dirs=["path/to/libs"], + ) + + platform = HatchCppPlatform( + cc="cl", + cxx="cl", + ld="link", + platform="win32", + toolchain="msvc", + disable_ccache=True, + ) + + flags = platform.get_link_flags(library) + # Libraries should have .lib suffix on Windows + assert "mylib.lib" in flags + # Library dirs should use /LIBPATH: + assert "/LIBPATH:path/to/libs" in flags + + def test_msvc_link_flags_with_platform_specific_libraries(self): + """Test that MSVC uses win32-specific libraries.""" + library = HatchCppLibrary( + name="test", + sources=["test.cpp"], + binding="generic", + libraries=["common"], + libraries_win32=["kernel32", "user32"], + library_dirs_win32=["C:/Windows/System32"], + ) + + platform = HatchCppPlatform( + cc="cl", + cxx="cl", + ld="link", + platform="win32", + toolchain="msvc", + disable_ccache=True, + ) + + flags = platform.get_link_flags(library) + assert "common.lib" in flags + assert "kernel32.lib" in flags + assert "user32.lib" in flags + assert "/LIBPATH:C:/Windows/System32" in flags diff --git a/hatch_cpp/toolchains/common.py b/hatch_cpp/toolchains/common.py index 3abcde7..120ed4a 100644 --- a/hatch_cpp/toolchains/common.py +++ b/hatch_cpp/toolchains/common.py @@ -5,7 +5,7 @@ from re import match from shutil import which from sys import executable, platform as sys_platform -from sysconfig import get_path +from sysconfig import get_config_var, get_path from typing import Any, List, Literal, Optional from pydantic import AliasChoices, BaseModel, Field, field_validator, model_validator @@ -368,8 +368,16 @@ def get_link_flags(self, library: HatchCppLibrary, build_type: BuildType = "rele flags += " /LD" flags += f" /Fe:{library.get_qualified_name(self.platform)}" flags += " /link /DLL" - if (Path(executable).parent / "libs").exists(): - flags += f" /LIBPATH:{str(Path(executable).parent / 'libs')}" + # Add Python libs directory - check multiple possible locations + python_libs_paths = [ + Path(executable).parent / "libs", # Standard Python install + Path(executable).parent.parent / "libs", # Some virtualenv layouts + Path(get_config_var("installed_base") or "") / "libs", # sysconfig approach + ] + for libs_path in python_libs_paths: + if libs_path.exists(): + flags += f" /LIBPATH:{str(libs_path)}" + break flags += " " + " ".join(f"{lib}.lib" for lib in effective_libraries) flags += " " + " ".join(f"/LIBPATH:{lib}" for lib in effective_library_dirs) # clean