hatch-cpp 0.3.5__tar.gz → 0.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/PKG-INFO +2 -2
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/__init__.py +1 -1
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/config.py +18 -3
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_platform_specific.py +1 -1
- hatch_cpp-0.3.6/hatch_cpp/tests/test_structs.py +240 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/toolchains/cmake.py +12 -2
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/toolchains/common.py +26 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/pyproject.toml +4 -3
- hatch_cpp-0.3.5/hatch_cpp/tests/test_structs.py +0 -56
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/.gitignore +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/LICENSE +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/README.md +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/hooks.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/plugin.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_hatch_build.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/CMakeLists.txt +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/Makefile +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/project/include/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/CMakeLists.txt +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/Makefile +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/project/include/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/vcpkg.json +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_classes/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_classes/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_toolchain/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_toolchain/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.cpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.hpp +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/project/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/pyproject.toml +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/vcpkg.json +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_projects.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_vcpkg_ref.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/toolchains/__init__.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/toolchains/vcpkg.py +0 -0
- {hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hatch-cpp
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Hatch plugin for C++ builds
|
|
5
5
|
Project-URL: Repository, https://github.com/python-project-templates/hatch-cpp
|
|
6
6
|
Project-URL: Homepage, https://github.com/python-project-templates/hatch-cpp
|
|
@@ -33,7 +33,7 @@ Requires-Dist: hatch-build>=0.3.2; extra == 'develop'
|
|
|
33
33
|
Requires-Dist: hatchling; extra == 'develop'
|
|
34
34
|
Requires-Dist: mdformat; extra == 'develop'
|
|
35
35
|
Requires-Dist: mdformat-tables>=1; extra == 'develop'
|
|
36
|
-
Requires-Dist: nanobind<2.
|
|
36
|
+
Requires-Dist: nanobind<2.13.0; extra == 'develop'
|
|
37
37
|
Requires-Dist: pybind11; extra == 'develop'
|
|
38
38
|
Requires-Dist: pytest; extra == 'develop'
|
|
39
39
|
Requires-Dist: pytest-cov; extra == 'develop'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from os import system as system_call
|
|
3
|
+
from os import environ, system as system_call
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import List, Optional
|
|
6
6
|
|
|
@@ -63,12 +63,27 @@ class HatchCppBuildPlan(HatchCppBuildConfig):
|
|
|
63
63
|
def generate(self):
|
|
64
64
|
self.commands = []
|
|
65
65
|
|
|
66
|
+
# Check for env var overrides
|
|
67
|
+
vcpkg_override = environ.get("HATCH_CPP_VCPKG")
|
|
68
|
+
cmake_override = environ.get("HATCH_CPP_CMAKE")
|
|
69
|
+
|
|
66
70
|
# Evaluate toolchains
|
|
67
|
-
if
|
|
71
|
+
if vcpkg_override == "1":
|
|
72
|
+
if self.vcpkg:
|
|
73
|
+
self._active_toolchains.append("vcpkg")
|
|
74
|
+
else:
|
|
75
|
+
log.warning("HATCH_CPP_VCPKG=1 set but no vcpkg configuration found; ignoring.")
|
|
76
|
+
elif vcpkg_override != "0" and self.vcpkg and Path(self.vcpkg.vcpkg).exists():
|
|
68
77
|
self._active_toolchains.append("vcpkg")
|
|
78
|
+
|
|
69
79
|
if self.libraries:
|
|
70
80
|
self._active_toolchains.append("vanilla")
|
|
71
|
-
elif
|
|
81
|
+
elif cmake_override == "1":
|
|
82
|
+
if self.cmake:
|
|
83
|
+
self._active_toolchains.append("cmake")
|
|
84
|
+
else:
|
|
85
|
+
log.warning("HATCH_CPP_CMAKE=1 set but no cmake configuration found; ignoring.")
|
|
86
|
+
elif cmake_override != "0" and self.cmake:
|
|
72
87
|
self._active_toolchains.append("cmake")
|
|
73
88
|
|
|
74
89
|
# Collect toolchain commands
|
|
@@ -345,7 +345,7 @@ class TestPlatformFlagsIntegration:
|
|
|
345
345
|
|
|
346
346
|
flags = platform.get_link_flags(library)
|
|
347
347
|
assert "-shared" in flags
|
|
348
|
-
assert "-Wl,-rpath
|
|
348
|
+
assert r"-Wl,-rpath,\$ORIGIN/lib" in flags
|
|
349
349
|
|
|
350
350
|
def test_darwin_platform_uses_darwin_specific_fields(self):
|
|
351
351
|
"""Test that darwin platform uses darwin-specific fields."""
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
from os import environ
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from sys import version_info
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from pydantic import ValidationError
|
|
8
|
+
from toml import loads
|
|
9
|
+
|
|
10
|
+
from hatch_cpp import HatchCppBuildConfig, HatchCppBuildPlan, HatchCppLibrary, HatchCppPlatform
|
|
11
|
+
from hatch_cpp.toolchains.common import _normalize_rpath
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestStructs:
|
|
15
|
+
def test_validate_py_limited_api(self):
|
|
16
|
+
with pytest.raises(ValidationError):
|
|
17
|
+
library = HatchCppLibrary(
|
|
18
|
+
name="test",
|
|
19
|
+
sources=["test.cpp"],
|
|
20
|
+
py_limited_api="42",
|
|
21
|
+
)
|
|
22
|
+
library = HatchCppLibrary(
|
|
23
|
+
name="test",
|
|
24
|
+
sources=["test.cpp"],
|
|
25
|
+
py_limited_api="cp39",
|
|
26
|
+
)
|
|
27
|
+
assert library.py_limited_api == "cp39"
|
|
28
|
+
platform = HatchCppPlatform.default()
|
|
29
|
+
flags = platform.get_compile_flags(library)
|
|
30
|
+
assert "-DPy_LIMITED_API=0x030900f0" in flags or "/DPy_LIMITED_API=0x030900f0" in flags
|
|
31
|
+
|
|
32
|
+
with pytest.raises(ValidationError):
|
|
33
|
+
library.binding = "pybind11"
|
|
34
|
+
|
|
35
|
+
def test_cmake_args(self):
|
|
36
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
37
|
+
toml = loads(txt)
|
|
38
|
+
hatch_build_config = HatchCppBuildConfig(name=toml["project"]["name"], **toml["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
39
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
40
|
+
hatch_build_plan.generate()
|
|
41
|
+
|
|
42
|
+
assert hatch_build_plan.commands[0].startswith("cmake .")
|
|
43
|
+
assert hatch_build_plan.commands[1].startswith("cmake --build build")
|
|
44
|
+
assert hatch_build_plan.commands[2].startswith("cmake --install build")
|
|
45
|
+
|
|
46
|
+
assert "-DCMAKE_BUILD_TYPE=release" in hatch_build_plan.commands[0]
|
|
47
|
+
assert "-B build" in hatch_build_plan.commands[0]
|
|
48
|
+
assert "-DHATCH_CPP_TEST_PROJECT_BASIC_BUILD_TESTS=OFF" in hatch_build_plan.commands[0]
|
|
49
|
+
assert f"-DHATCH_CPP_TEST_PROJECT_BASIC_PYTHON_VERSION=3.{version_info.minor}" in hatch_build_plan.commands[0]
|
|
50
|
+
if hatch_build_plan.platform.platform == "darwin":
|
|
51
|
+
assert "-DCMAKE_OSX_DEPLOYMENT_TARGET=11" in hatch_build_plan.commands[0]
|
|
52
|
+
|
|
53
|
+
def test_platform_toolchain_override(self):
|
|
54
|
+
txt = (Path(__file__).parent / "test_project_override_toolchain" / "pyproject.toml").read_text()
|
|
55
|
+
toml = loads(txt)
|
|
56
|
+
hatch_build_config = HatchCppBuildConfig(name=toml["project"]["name"], **toml["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
57
|
+
assert "clang" in hatch_build_config.platform.cc
|
|
58
|
+
assert "clang++" in hatch_build_config.platform.cxx
|
|
59
|
+
assert hatch_build_config.platform.toolchain == "gcc"
|
|
60
|
+
|
|
61
|
+
def test_cmake_args_env_variable(self):
|
|
62
|
+
"""Test that CMAKE_ARGS environment variable is respected."""
|
|
63
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
64
|
+
toml_data = loads(txt)
|
|
65
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
66
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
67
|
+
|
|
68
|
+
with patch.dict(environ, {"CMAKE_ARGS": "-DFOO=bar -DBAZ=qux"}):
|
|
69
|
+
hatch_build_plan.generate()
|
|
70
|
+
assert "-DFOO=bar" in hatch_build_plan.commands[0]
|
|
71
|
+
assert "-DBAZ=qux" in hatch_build_plan.commands[0]
|
|
72
|
+
|
|
73
|
+
def test_cmake_args_env_variable_empty(self):
|
|
74
|
+
"""Test that an empty CMAKE_ARGS does not add extra whitespace."""
|
|
75
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
76
|
+
toml_data = loads(txt)
|
|
77
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
78
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
79
|
+
|
|
80
|
+
with patch.dict(environ, {"CMAKE_ARGS": ""}):
|
|
81
|
+
hatch_build_plan.generate()
|
|
82
|
+
# Should not have trailing whitespace from empty CMAKE_ARGS
|
|
83
|
+
assert not hatch_build_plan.commands[0].endswith(" ")
|
|
84
|
+
|
|
85
|
+
def test_cmake_generator_env_variable(self):
|
|
86
|
+
"""Test that CMAKE_GENERATOR environment variable is respected on non-Windows platforms."""
|
|
87
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
88
|
+
toml_data = loads(txt)
|
|
89
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
90
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
91
|
+
|
|
92
|
+
with patch.dict(environ, {"CMAKE_GENERATOR": "Ninja"}):
|
|
93
|
+
hatch_build_plan.generate()
|
|
94
|
+
assert '-G "Ninja"' in hatch_build_plan.commands[0]
|
|
95
|
+
|
|
96
|
+
def test_cmake_generator_env_variable_unset(self):
|
|
97
|
+
"""Test that no -G flag is added on non-Windows when CMAKE_GENERATOR is not set."""
|
|
98
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
99
|
+
toml_data = loads(txt)
|
|
100
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
101
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
102
|
+
|
|
103
|
+
with patch.dict(environ, {}, clear=False):
|
|
104
|
+
# Remove CMAKE_GENERATOR if present
|
|
105
|
+
environ.pop("CMAKE_GENERATOR", None)
|
|
106
|
+
hatch_build_plan.generate()
|
|
107
|
+
if hatch_build_plan.platform.platform != "win32":
|
|
108
|
+
assert "-G " not in hatch_build_plan.commands[0]
|
|
109
|
+
|
|
110
|
+
def test_hatch_cpp_cmake_env_force_off(self):
|
|
111
|
+
"""Test that HATCH_CPP_CMAKE=0 disables cmake even when cmake config is present."""
|
|
112
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
113
|
+
toml_data = loads(txt)
|
|
114
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
115
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
116
|
+
|
|
117
|
+
assert hatch_build_plan.cmake is not None
|
|
118
|
+
with patch.dict(environ, {"HATCH_CPP_CMAKE": "0"}):
|
|
119
|
+
hatch_build_plan.generate()
|
|
120
|
+
# cmake should not be active, so no cmake commands generated
|
|
121
|
+
assert len(hatch_build_plan.commands) == 0
|
|
122
|
+
assert "cmake" not in hatch_build_plan._active_toolchains
|
|
123
|
+
|
|
124
|
+
def test_hatch_cpp_cmake_env_force_on(self):
|
|
125
|
+
"""Test that HATCH_CPP_CMAKE=1 enables cmake when cmake config is present."""
|
|
126
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
127
|
+
toml_data = loads(txt)
|
|
128
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
129
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
130
|
+
|
|
131
|
+
assert hatch_build_plan.cmake is not None
|
|
132
|
+
with patch.dict(environ, {"HATCH_CPP_CMAKE": "1"}):
|
|
133
|
+
hatch_build_plan.generate()
|
|
134
|
+
assert "cmake" in hatch_build_plan._active_toolchains
|
|
135
|
+
|
|
136
|
+
def test_hatch_cpp_cmake_env_force_on_no_config(self):
|
|
137
|
+
"""Test that HATCH_CPP_CMAKE=1 warns and skips when no cmake config exists."""
|
|
138
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
139
|
+
toml_data = loads(txt)
|
|
140
|
+
config_data = toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"].copy()
|
|
141
|
+
config_data.pop("cmake", None)
|
|
142
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **config_data)
|
|
143
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
144
|
+
|
|
145
|
+
assert hatch_build_plan.cmake is None
|
|
146
|
+
with patch.dict(environ, {"HATCH_CPP_CMAKE": "1"}):
|
|
147
|
+
hatch_build_plan.generate()
|
|
148
|
+
# cmake should NOT be activated when there's no config
|
|
149
|
+
assert "cmake" not in hatch_build_plan._active_toolchains
|
|
150
|
+
|
|
151
|
+
def test_hatch_cpp_vcpkg_env_force_off(self):
|
|
152
|
+
"""Test that HATCH_CPP_VCPKG=0 disables vcpkg even when vcpkg.json exists."""
|
|
153
|
+
txt = (Path(__file__).parent / "test_project_cmake_vcpkg" / "pyproject.toml").read_text()
|
|
154
|
+
toml_data = loads(txt)
|
|
155
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
156
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
157
|
+
|
|
158
|
+
with patch.dict(environ, {"HATCH_CPP_VCPKG": "0"}):
|
|
159
|
+
hatch_build_plan.generate()
|
|
160
|
+
assert "vcpkg" not in hatch_build_plan._active_toolchains
|
|
161
|
+
|
|
162
|
+
def test_hatch_cpp_vcpkg_env_force_on(self):
|
|
163
|
+
"""Test that HATCH_CPP_VCPKG=1 enables vcpkg even when vcpkg.json doesn't exist."""
|
|
164
|
+
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
165
|
+
toml_data = loads(txt)
|
|
166
|
+
hatch_build_config = HatchCppBuildConfig(name=toml_data["project"]["name"], **toml_data["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
167
|
+
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
168
|
+
|
|
169
|
+
with patch.dict(environ, {"HATCH_CPP_VCPKG": "1"}):
|
|
170
|
+
hatch_build_plan.generate()
|
|
171
|
+
assert "vcpkg" in hatch_build_plan._active_toolchains
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class TestNormalizeRpath:
|
|
175
|
+
def test_origin_to_loader_path_on_darwin(self):
|
|
176
|
+
"""$ORIGIN should be translated to @loader_path on macOS."""
|
|
177
|
+
assert _normalize_rpath("-Wl,-rpath,$ORIGIN", "darwin") == "-Wl,-rpath,@loader_path"
|
|
178
|
+
|
|
179
|
+
def test_loader_path_to_origin_on_linux(self):
|
|
180
|
+
"""@loader_path should be translated to (escaped) $ORIGIN on Linux."""
|
|
181
|
+
result = _normalize_rpath("-Wl,-rpath,@loader_path", "linux")
|
|
182
|
+
assert result == r"-Wl,-rpath,\$ORIGIN"
|
|
183
|
+
|
|
184
|
+
def test_origin_escaped_on_linux(self):
|
|
185
|
+
"""$ORIGIN should be escaped as \\$ORIGIN on Linux for shell safety."""
|
|
186
|
+
result = _normalize_rpath("-Wl,-rpath,$ORIGIN", "linux")
|
|
187
|
+
assert result == r"-Wl,-rpath,\$ORIGIN"
|
|
188
|
+
|
|
189
|
+
def test_already_escaped_origin_on_darwin(self):
|
|
190
|
+
"""Already-escaped \\$ORIGIN should still translate to @loader_path on macOS."""
|
|
191
|
+
assert _normalize_rpath(r"-Wl,-rpath,\$ORIGIN", "darwin") == "-Wl,-rpath,@loader_path"
|
|
192
|
+
|
|
193
|
+
def test_no_rpath_unchanged(self):
|
|
194
|
+
"""Args without rpath values should pass through unchanged."""
|
|
195
|
+
assert _normalize_rpath("-lfoo", "linux") == "-lfoo"
|
|
196
|
+
assert _normalize_rpath("-lfoo", "darwin") == "-lfoo"
|
|
197
|
+
|
|
198
|
+
def test_win32_no_transform(self):
|
|
199
|
+
"""Windows should not transform rpath values."""
|
|
200
|
+
assert _normalize_rpath("$ORIGIN", "win32") == "$ORIGIN"
|
|
201
|
+
assert _normalize_rpath("@loader_path", "win32") == "@loader_path"
|
|
202
|
+
|
|
203
|
+
def test_link_flags_rpath_translation_darwin(self):
|
|
204
|
+
"""Full integration: extra_link_args with $ORIGIN produce @loader_path on macOS."""
|
|
205
|
+
library = HatchCppLibrary(
|
|
206
|
+
name="test",
|
|
207
|
+
sources=["test.cpp"],
|
|
208
|
+
binding="generic",
|
|
209
|
+
extra_link_args=["-Wl,-rpath,$ORIGIN"],
|
|
210
|
+
)
|
|
211
|
+
platform = HatchCppPlatform(
|
|
212
|
+
cc="clang",
|
|
213
|
+
cxx="clang++",
|
|
214
|
+
ld="ld",
|
|
215
|
+
platform="darwin",
|
|
216
|
+
toolchain="clang",
|
|
217
|
+
disable_ccache=True,
|
|
218
|
+
)
|
|
219
|
+
flags = platform.get_link_flags(library)
|
|
220
|
+
assert "@loader_path" in flags
|
|
221
|
+
assert "$ORIGIN" not in flags
|
|
222
|
+
|
|
223
|
+
def test_link_flags_rpath_escaped_linux(self):
|
|
224
|
+
"""Full integration: extra_link_args with $ORIGIN are shell-escaped on Linux."""
|
|
225
|
+
library = HatchCppLibrary(
|
|
226
|
+
name="test",
|
|
227
|
+
sources=["test.cpp"],
|
|
228
|
+
binding="generic",
|
|
229
|
+
extra_link_args=["-Wl,-rpath,$ORIGIN"],
|
|
230
|
+
)
|
|
231
|
+
platform = HatchCppPlatform(
|
|
232
|
+
cc="gcc",
|
|
233
|
+
cxx="g++",
|
|
234
|
+
ld="ld",
|
|
235
|
+
platform="linux",
|
|
236
|
+
toolchain="gcc",
|
|
237
|
+
disable_ccache=True,
|
|
238
|
+
)
|
|
239
|
+
flags = platform.get_link_flags(library)
|
|
240
|
+
assert r"\$ORIGIN" in flags
|
|
@@ -54,9 +54,14 @@ class HatchCppCmakeConfiguration(BaseModel):
|
|
|
54
54
|
commands[-1] += f" -DCMAKE_INSTALL_PREFIX={Path(self.root).parent}"
|
|
55
55
|
|
|
56
56
|
# TODO: CMAKE_CXX_COMPILER
|
|
57
|
+
# Respect CMAKE_GENERATOR environment variable
|
|
58
|
+
cmake_generator = environ.get("CMAKE_GENERATOR", "")
|
|
57
59
|
if config.platform.platform == "win32":
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
if not cmake_generator:
|
|
61
|
+
cmake_generator = "Visual Studio 17 2022"
|
|
62
|
+
commands[-1] += f' -G "{cmake_generator}"'
|
|
63
|
+
elif cmake_generator:
|
|
64
|
+
commands[-1] += f' -G "{cmake_generator}"'
|
|
60
65
|
|
|
61
66
|
# Put in CMake flags
|
|
62
67
|
args = self.cmake_args.copy()
|
|
@@ -78,6 +83,11 @@ class HatchCppCmakeConfiguration(BaseModel):
|
|
|
78
83
|
if config.platform.platform == "darwin":
|
|
79
84
|
commands[-1] += f" -DCMAKE_OSX_DEPLOYMENT_TARGET={environ.get('OSX_DEPLOYMENT_TARGET', '11')}"
|
|
80
85
|
|
|
86
|
+
# Respect CMAKE_ARGS environment variable
|
|
87
|
+
cmake_args_env = environ.get("CMAKE_ARGS", "").strip()
|
|
88
|
+
if cmake_args_env:
|
|
89
|
+
commands[-1] += " " + cmake_args_env
|
|
90
|
+
|
|
81
91
|
# Append build command
|
|
82
92
|
commands.append(f"cmake --build {self.build} --config {config.build_type}")
|
|
83
93
|
|
|
@@ -20,6 +20,7 @@ __all__ = (
|
|
|
20
20
|
"PlatformDefaults",
|
|
21
21
|
"HatchCppLibrary",
|
|
22
22
|
"HatchCppPlatform",
|
|
23
|
+
"_normalize_rpath",
|
|
23
24
|
)
|
|
24
25
|
|
|
25
26
|
|
|
@@ -207,6 +208,28 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
|
|
|
207
208
|
return macros
|
|
208
209
|
|
|
209
210
|
|
|
211
|
+
def _normalize_rpath(value: str, platform: Platform) -> str:
|
|
212
|
+
r"""Translate and escape rpath values for the target platform.
|
|
213
|
+
|
|
214
|
+
- On macOS (darwin): ``$ORIGIN`` is replaced with ``@loader_path``.
|
|
215
|
+
- On Linux: ``@loader_path`` is replaced with ``$ORIGIN``, and
|
|
216
|
+
``$ORIGIN`` is escaped as ``\$ORIGIN`` so that ``os.system()``
|
|
217
|
+
(which invokes a shell) passes it through literally.
|
|
218
|
+
- On Windows: no transformation is applied (Windows does not use
|
|
219
|
+
rpath).
|
|
220
|
+
"""
|
|
221
|
+
if platform == "darwin":
|
|
222
|
+
# Handle already-escaped \$ORIGIN first, then plain $ORIGIN
|
|
223
|
+
value = value.replace(r"\$ORIGIN", "@loader_path")
|
|
224
|
+
value = value.replace("$ORIGIN", "@loader_path")
|
|
225
|
+
elif platform == "linux":
|
|
226
|
+
# Translate macOS rpath to Linux equivalent
|
|
227
|
+
value = value.replace("@loader_path", "$ORIGIN")
|
|
228
|
+
# Escape $ORIGIN for shell safety (os.system runs through bash)
|
|
229
|
+
value = value.replace("$ORIGIN", r"\$ORIGIN")
|
|
230
|
+
return value
|
|
231
|
+
|
|
232
|
+
|
|
210
233
|
class HatchCppPlatform(BaseModel):
|
|
211
234
|
cc: str
|
|
212
235
|
cxx: str
|
|
@@ -338,6 +361,9 @@ class HatchCppPlatform(BaseModel):
|
|
|
338
361
|
effective_libraries = library.get_effective_libraries(self.platform)
|
|
339
362
|
effective_library_dirs = library.get_effective_library_dirs(self.platform)
|
|
340
363
|
|
|
364
|
+
# Normalize rpath values ($ORIGIN <-> @loader_path) and escape for shell
|
|
365
|
+
effective_link_args = [_normalize_rpath(arg, self.platform) for arg in effective_link_args]
|
|
366
|
+
|
|
341
367
|
if self.toolchain == "gcc":
|
|
342
368
|
flags += " -shared"
|
|
343
369
|
flags += " " + " ".join(effective_link_args)
|
|
@@ -12,7 +12,7 @@ authors = [
|
|
|
12
12
|
description = "Hatch plugin for C++ builds"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
license = { text = "Apache-2.0" }
|
|
15
|
-
version = "0.3.
|
|
15
|
+
version = "0.3.6"
|
|
16
16
|
requires-python = ">=3.10"
|
|
17
17
|
keywords = [
|
|
18
18
|
"hatch",
|
|
@@ -62,7 +62,7 @@ develop = [
|
|
|
62
62
|
"uv",
|
|
63
63
|
"wheel",
|
|
64
64
|
# test
|
|
65
|
-
"nanobind<2.
|
|
65
|
+
"nanobind<2.13.0", # https://github.com/wjakob/nanobind/commit/abd27e3b5565bc95f5091321f0f863fce8b5b95b
|
|
66
66
|
"pybind11",
|
|
67
67
|
"pytest",
|
|
68
68
|
"pytest-cov",
|
|
@@ -80,7 +80,7 @@ Repository = "https://github.com/python-project-templates/hatch-cpp"
|
|
|
80
80
|
Homepage = "https://github.com/python-project-templates/hatch-cpp"
|
|
81
81
|
|
|
82
82
|
[tool.bumpversion]
|
|
83
|
-
current_version = "0.3.
|
|
83
|
+
current_version = "0.3.6"
|
|
84
84
|
commit = true
|
|
85
85
|
tag = true
|
|
86
86
|
commit_args = "-s"
|
|
@@ -100,6 +100,7 @@ branch = false
|
|
|
100
100
|
omit = [
|
|
101
101
|
"hatch_cpp/tests/integration/",
|
|
102
102
|
]
|
|
103
|
+
|
|
103
104
|
[tool.coverage.report]
|
|
104
105
|
exclude_also = [
|
|
105
106
|
"raise NotImplementedError",
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from sys import version_info
|
|
3
|
-
|
|
4
|
-
import pytest
|
|
5
|
-
from pydantic import ValidationError
|
|
6
|
-
from toml import loads
|
|
7
|
-
|
|
8
|
-
from hatch_cpp import HatchCppBuildConfig, HatchCppBuildPlan, HatchCppLibrary, HatchCppPlatform
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class TestStructs:
|
|
12
|
-
def test_validate_py_limited_api(self):
|
|
13
|
-
with pytest.raises(ValidationError):
|
|
14
|
-
library = HatchCppLibrary(
|
|
15
|
-
name="test",
|
|
16
|
-
sources=["test.cpp"],
|
|
17
|
-
py_limited_api="42",
|
|
18
|
-
)
|
|
19
|
-
library = HatchCppLibrary(
|
|
20
|
-
name="test",
|
|
21
|
-
sources=["test.cpp"],
|
|
22
|
-
py_limited_api="cp39",
|
|
23
|
-
)
|
|
24
|
-
assert library.py_limited_api == "cp39"
|
|
25
|
-
platform = HatchCppPlatform.default()
|
|
26
|
-
flags = platform.get_compile_flags(library)
|
|
27
|
-
assert "-DPy_LIMITED_API=0x030900f0" in flags or "/DPy_LIMITED_API=0x030900f0" in flags
|
|
28
|
-
|
|
29
|
-
with pytest.raises(ValidationError):
|
|
30
|
-
library.binding = "pybind11"
|
|
31
|
-
|
|
32
|
-
def test_cmake_args(self):
|
|
33
|
-
txt = (Path(__file__).parent / "test_project_cmake" / "pyproject.toml").read_text()
|
|
34
|
-
toml = loads(txt)
|
|
35
|
-
hatch_build_config = HatchCppBuildConfig(name=toml["project"]["name"], **toml["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
36
|
-
hatch_build_plan = HatchCppBuildPlan(**hatch_build_config.model_dump())
|
|
37
|
-
hatch_build_plan.generate()
|
|
38
|
-
|
|
39
|
-
assert hatch_build_plan.commands[0].startswith("cmake .")
|
|
40
|
-
assert hatch_build_plan.commands[1].startswith("cmake --build build")
|
|
41
|
-
assert hatch_build_plan.commands[2].startswith("cmake --install build")
|
|
42
|
-
|
|
43
|
-
assert "-DCMAKE_BUILD_TYPE=release" in hatch_build_plan.commands[0]
|
|
44
|
-
assert "-B build" in hatch_build_plan.commands[0]
|
|
45
|
-
assert "-DHATCH_CPP_TEST_PROJECT_BASIC_BUILD_TESTS=OFF" in hatch_build_plan.commands[0]
|
|
46
|
-
assert f"-DHATCH_CPP_TEST_PROJECT_BASIC_PYTHON_VERSION=3.{version_info.minor}" in hatch_build_plan.commands[0]
|
|
47
|
-
if hatch_build_plan.platform.platform == "darwin":
|
|
48
|
-
assert "-DCMAKE_OSX_DEPLOYMENT_TARGET=11" in hatch_build_plan.commands[0]
|
|
49
|
-
|
|
50
|
-
def test_platform_toolchain_override(self):
|
|
51
|
-
txt = (Path(__file__).parent / "test_project_override_toolchain" / "pyproject.toml").read_text()
|
|
52
|
-
toml = loads(txt)
|
|
53
|
-
hatch_build_config = HatchCppBuildConfig(name=toml["project"]["name"], **toml["tool"]["hatch"]["build"]["hooks"]["hatch-cpp"])
|
|
54
|
-
assert "clang" in hatch_build_config.platform.cc
|
|
55
|
-
assert "clang++" in hatch_build_config.platform.cxx
|
|
56
|
-
assert hatch_build_config.platform.toolchain == "gcc"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_basic/cpp/project/basic.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.hpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_cmake_vcpkg/project/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.hpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_hatch_build/project/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.hpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_limited_api/project/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.hpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_nanobind/project/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_classes/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_override_toolchain/pyproject.toml
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.cpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.hpp
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/project/__init__.py
RENAMED
|
File without changes
|
{hatch_cpp-0.3.5 → hatch_cpp-0.3.6}/hatch_cpp/tests/test_project_pybind_vcpkg/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|