Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions hatch_cpp/tests/test_platform_specific.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 11 additions & 3 deletions hatch_cpp/toolchains/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down