Skip to content

Commit bd890d0

Browse files
committed
Build
1 parent 446e420 commit bd890d0

File tree

14 files changed

+1213
-28
lines changed

14 files changed

+1213
-28
lines changed

cppython/build/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""CPPython build backend wrapping scikit-build-core.
2+
3+
This module provides PEP 517/518 build backend hooks that wrap scikit-build-core,
4+
automatically running CPPython's provider workflow before building
5+
to inject the generated toolchain file into the CMake configuration.
6+
7+
Usage in pyproject.toml:
8+
[build-system]
9+
requires = ["cppython[conan, cmake]"]
10+
build-backend = "cppython.build"
11+
"""
12+
13+
from cppython.build.backend import (
14+
build_editable,
15+
build_sdist,
16+
build_wheel,
17+
get_requires_for_build_editable,
18+
get_requires_for_build_sdist,
19+
get_requires_for_build_wheel,
20+
prepare_metadata_for_build_editable,
21+
prepare_metadata_for_build_wheel,
22+
)
23+
24+
__all__ = [
25+
'build_editable',
26+
'build_sdist',
27+
'build_wheel',
28+
'get_requires_for_build_editable',
29+
'get_requires_for_build_sdist',
30+
'get_requires_for_build_wheel',
31+
'prepare_metadata_for_build_editable',
32+
'prepare_metadata_for_build_wheel',
33+
]

cppython/build/backend.py

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
"""PEP 517 build backend implementation wrapping scikit-build-core.
2+
3+
This module provides the actual build hooks that delegate to scikit-build-core
4+
after running CPPython's preparation workflow.
5+
"""
6+
7+
import logging
8+
from pathlib import Path
9+
from typing import Any
10+
11+
from scikit_build_core import build as skbuild
12+
13+
from cppython.build.prepare import prepare_build
14+
15+
logger = logging.getLogger('cppython.build')
16+
17+
18+
def _inject_toolchain(
19+
config_settings: dict[str, Any] | None, toolchain_file: Path | None
20+
) -> dict[str, Any]:
21+
"""Inject the toolchain file into config settings for scikit-build-core.
22+
23+
Args:
24+
config_settings: The original config settings (may be None)
25+
toolchain_file: Path to the toolchain file to inject
26+
27+
Returns:
28+
Updated config settings with toolchain file injected
29+
"""
30+
settings = dict(config_settings) if config_settings else {}
31+
32+
if toolchain_file and toolchain_file.exists():
33+
# scikit-build-core accepts cmake.define.VAR_NAME format
34+
toolchain_key = 'cmake.define.CMAKE_TOOLCHAIN_FILE'
35+
36+
# Don't override if user explicitly set a toolchain file
37+
if toolchain_key not in settings:
38+
settings[toolchain_key] = str(toolchain_file.absolute())
39+
logger.info('CPPython: Injected CMAKE_TOOLCHAIN_FILE=%s', toolchain_file)
40+
else:
41+
logger.info(
42+
'CPPython: User-specified toolchain file takes precedence: %s',
43+
settings[toolchain_key],
44+
)
45+
46+
return settings
47+
48+
49+
def _prepare_and_get_settings(
50+
config_settings: dict[str, Any] | None,
51+
) -> dict[str, Any]:
52+
"""Run CPPython preparation and merge toolchain into config settings.
53+
54+
Args:
55+
config_settings: The original config settings
56+
57+
Returns:
58+
Config settings with CPPython toolchain injected
59+
"""
60+
# Determine source directory (current working directory during build)
61+
source_dir = Path.cwd()
62+
63+
# Run CPPython preparation
64+
toolchain_file = prepare_build(source_dir)
65+
66+
# Inject toolchain into config settings
67+
return _inject_toolchain(config_settings, toolchain_file)
68+
69+
70+
# PEP 517 Hooks - delegating to scikit-build-core after preparation
71+
72+
73+
def get_requires_for_build_wheel(
74+
config_settings: dict[str, Any] | None = None,
75+
) -> list[str]:
76+
"""Get additional requirements for building a wheel.
77+
78+
Args:
79+
config_settings: Build configuration settings
80+
81+
Returns:
82+
List of additional requirements
83+
"""
84+
return skbuild.get_requires_for_build_wheel(config_settings)
85+
86+
87+
def get_requires_for_build_sdist(
88+
config_settings: dict[str, Any] | None = None,
89+
) -> list[str]:
90+
"""Get additional requirements for building an sdist.
91+
92+
Args:
93+
config_settings: Build configuration settings
94+
95+
Returns:
96+
List of additional requirements
97+
"""
98+
return skbuild.get_requires_for_build_sdist(config_settings)
99+
100+
101+
def get_requires_for_build_editable(
102+
config_settings: dict[str, Any] | None = None,
103+
) -> list[str]:
104+
"""Get additional requirements for building an editable install.
105+
106+
Args:
107+
config_settings: Build configuration settings
108+
109+
Returns:
110+
List of additional requirements
111+
"""
112+
return skbuild.get_requires_for_build_editable(config_settings)
113+
114+
115+
def build_wheel(
116+
wheel_directory: str,
117+
config_settings: dict[str, Any] | None = None,
118+
metadata_directory: str | None = None,
119+
) -> str:
120+
"""Build a wheel from the source distribution.
121+
122+
This runs CPPython's provider workflow first to ensure C++ dependencies
123+
are installed and the toolchain file is generated, then delegates to
124+
scikit-build-core for the actual wheel build.
125+
126+
Args:
127+
wheel_directory: Directory to place the built wheel
128+
config_settings: Build configuration settings
129+
metadata_directory: Directory containing wheel metadata
130+
131+
Returns:
132+
The basename of the built wheel
133+
"""
134+
logger.info('CPPython: Starting wheel build')
135+
136+
# Prepare CPPython and get updated settings
137+
settings = _prepare_and_get_settings(config_settings)
138+
139+
# Delegate to scikit-build-core
140+
return skbuild.build_wheel(wheel_directory, settings, metadata_directory)
141+
142+
143+
def build_sdist(
144+
sdist_directory: str,
145+
config_settings: dict[str, Any] | None = None,
146+
) -> str:
147+
"""Build a source distribution.
148+
149+
For sdist, we don't run the full CPPython workflow since the C++ dependencies
150+
should be resolved at wheel build time, not sdist creation time.
151+
152+
Args:
153+
sdist_directory: Directory to place the built sdist
154+
config_settings: Build configuration settings
155+
156+
Returns:
157+
The basename of the built sdist
158+
"""
159+
logger.info('CPPython: Starting sdist build')
160+
161+
# Delegate directly to scikit-build-core (no preparation needed for sdist)
162+
return skbuild.build_sdist(sdist_directory, config_settings)
163+
164+
165+
def build_editable(
166+
wheel_directory: str,
167+
config_settings: dict[str, Any] | None = None,
168+
metadata_directory: str | None = None,
169+
) -> str:
170+
"""Build an editable wheel.
171+
172+
This runs CPPython's provider workflow first, similar to build_wheel.
173+
174+
Args:
175+
wheel_directory: Directory to place the built wheel
176+
config_settings: Build configuration settings
177+
metadata_directory: Directory containing wheel metadata
178+
179+
Returns:
180+
The basename of the built wheel
181+
"""
182+
logger.info('CPPython: Starting editable build')
183+
184+
# Prepare CPPython and get updated settings
185+
settings = _prepare_and_get_settings(config_settings)
186+
187+
# Delegate to scikit-build-core
188+
return skbuild.build_editable(wheel_directory, settings, metadata_directory)
189+
190+
191+
def prepare_metadata_for_build_wheel(
192+
metadata_directory: str,
193+
config_settings: dict[str, Any] | None = None,
194+
) -> str:
195+
"""Prepare metadata for wheel build.
196+
197+
Args:
198+
metadata_directory: Directory to place the metadata
199+
config_settings: Build configuration settings
200+
201+
Returns:
202+
The basename of the metadata directory
203+
"""
204+
return skbuild.prepare_metadata_for_build_wheel(metadata_directory, config_settings)
205+
206+
207+
def prepare_metadata_for_build_editable(
208+
metadata_directory: str,
209+
config_settings: dict[str, Any] | None = None,
210+
) -> str:
211+
"""Prepare metadata for editable build.
212+
213+
Args:
214+
metadata_directory: Directory to place the metadata
215+
config_settings: Build configuration settings
216+
217+
Returns:
218+
The basename of the metadata directory
219+
"""
220+
return skbuild.prepare_metadata_for_build_editable(metadata_directory, config_settings)

0 commit comments

Comments
 (0)