Skip to content

Commit 9f393b6

Browse files
committed
Add first cut of C ABI creation / packaging
1 parent 698f6f2 commit 9f393b6

19 files changed

Lines changed: 1199 additions & 122 deletions

File tree

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,37 @@ path = "."
1818
module = "project"
1919
```
2020

21+
### Shared C ABI libraries
22+
23+
Projects can declare multiple Rust artifacts in one hook. A `python-extension`
24+
artifact keeps the existing PyO3 extension flow, while a `shared-library`
25+
artifact builds a standalone `cdylib`, copies the exact platform library name to
26+
the configured destination, and includes it in the wheel.
27+
28+
```toml
29+
[tool.hatch.build.hooks.hatch-rs]
30+
verbose = true
31+
path = "."
32+
module = "project"
33+
target-dir = "isolated"
34+
35+
[[tool.hatch.build.hooks.hatch-rs.artifacts]]
36+
name = "python-extension"
37+
kind = "python-extension"
38+
manifest = "Cargo.toml"
39+
library = "project"
40+
41+
[[tool.hatch.build.hooks.hatch-rs.artifacts]]
42+
name = "c-abi"
43+
kind = "shared-library"
44+
manifest = "rust/Cargo.toml"
45+
library = "project_ffi"
46+
crate-type = "cdylib"
47+
destination = "project/lib/{shared_library}"
48+
```
49+
50+
Destination templates support `{module}`, `{target}`, `{profile}`, `{library}`,
51+
`{shared_library}`, and `{python_extension_name}`.
52+
2153
> [!NOTE]
2254
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).

hatch_rs/plugin.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from logging import getLogger
44
from os import getenv
5-
from pathlib import Path
65
from platform import machine as platform_machine
76
from sys import platform as sys_platform, version_info
87
from typing import Any
@@ -61,12 +60,13 @@ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
6160
self._logger.warning(command)
6261

6362
# Execute build plan
64-
build_plan.execute()
63+
try:
64+
build_plan.execute()
65+
finally:
66+
# Perform any cleanup actions
67+
build_plan.cleanup()
6568

66-
# Perform any cleanup actions
67-
build_plan.cleanup()
68-
69-
if not build_plan._libraries:
69+
if not build_plan.libraries:
7070
raise ValueError("No libraries were created by the build.")
7171

7272
# force include libraries
@@ -104,13 +104,9 @@ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
104104
build_data["tag"] = f"cp{version_major}{version_minor}-cp{version_major}{version_minor}-{os_name}_{machine}"
105105

106106
# force include libraries
107-
for path in Path(".").rglob("*"):
108-
if path.is_dir():
109-
continue
110-
if str(path).startswith("target") or str(path).startswith("dist") or not str(path).startswith(config.module):
111-
continue
112-
if path.suffix in (".pyd", ".dll", ".so", ".dylib"):
113-
build_data["force_include"][str(path)] = str(path)
114-
115-
for path in build_data["force_include"]:
107+
force_include = build_data.setdefault("force_include", {})
108+
for artifact in build_plan.copied_artifacts:
109+
force_include[artifact.distribution_path] = artifact.distribution_path
110+
111+
for path in force_include:
116112
self._logger.warning(f"Force include: {path}")

0 commit comments

Comments
 (0)