diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a791047..616c85c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,7 +253,7 @@ jobs: toolchain: stable override: true - name: Install cross - run: cargo install cross + run: cargo install --version 0.2.1 cross - name: Build package run: pip install -e . - name: Build wheel using cross diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f07bda8..ca6e0fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ ### Added - Add `cargo_manifest_args` to support locked, frozen and offline builds. [#234](https://github.com/PyO3/setuptools-rust/pull/234) +- Add `RustBin` for packaging binaries in scripts data directory. [#248](https://github.com/PyO3/setuptools-rust/pull/248) + +### Changed +- `Exec` binding `RustExtension` with `script=True` is deprecated in favor of `RustBin`. [#248](https://github.com/PyO3/setuptools-rust/pull/248) ### Fixed - If the sysconfig for `BLDSHARED` has no flags, `setuptools-rust` won't crash anymore. [#241](https://github.com/PyO3/setuptools-rust/pull/241) diff --git a/examples/hello-world/setup.py b/examples/hello-world/setup.py index 3cc0c6ff..48e7839b 100644 --- a/examples/hello-world/setup.py +++ b/examples/hello-world/setup.py @@ -1,15 +1,13 @@ from setuptools import setup -from setuptools_rust import Binding, RustExtension +from setuptools_rust import RustBin setup( name="hello-world", version="1.0", rust_extensions=[ - RustExtension( - {"hello-world": "hello_world.hello-world"}, - binding=Binding.Exec, - script=True, + RustBin( + "hello-world", args=["--profile", "release-lto"], ) ], diff --git a/setuptools_rust/__init__.py b/setuptools_rust/__init__.py index 334d1f3d..522fb0b6 100644 --- a/setuptools_rust/__init__.py +++ b/setuptools_rust/__init__.py @@ -1,6 +1,6 @@ from .build import build_rust from .clean import clean_rust -from .extension import Binding, RustExtension, Strip +from .extension import Binding, RustBin, RustExtension, Strip from .version import version as __version__ -__all__ = ("Binding", "RustExtension", "Strip", "build_rust", "clean_rust") +__all__ = ("Binding", "RustBin", "RustExtension", "Strip", "build_rust", "clean_rust") diff --git a/setuptools_rust/build.py b/setuptools_rust/build.py index 3db57c1c..ab97d971 100644 --- a/setuptools_rust/build.py +++ b/setuptools_rust/build.py @@ -21,7 +21,7 @@ from typing_extensions import Literal from .command import RustCommand -from .extension import RustExtension, Strip +from .extension import RustBin, RustExtension, Strip from .utils import ( PyLimitedApi, binding_features, @@ -313,7 +313,18 @@ def install_extension( ext_path += exe os.makedirs(os.path.dirname(ext_path), exist_ok=True) - ext.install_script(module_name.split(".")[-1], ext_path) + if isinstance(ext, RustBin): + executable_name = module_name + if exe is not None: + executable_name += exe + wheel = self.get_finalized_command("bdist_wheel") + scripts_dir = os.path.join( + build_ext.build_lib, wheel.data_dir, "scripts" # type: ignore[attr-defined] + ) + os.makedirs(scripts_dir, exist_ok=True) + ext_path = os.path.join(scripts_dir, executable_name) + else: + ext.install_script(module_name.split(".")[-1], ext_path) else: ext_path = self.get_dylib_ext_path(ext, module_name) os.makedirs(os.path.dirname(ext_path), exist_ok=True) diff --git a/setuptools_rust/extension.py b/setuptools_rust/extension.py index a9465d79..b8219d85 100644 --- a/setuptools_rust/extension.py +++ b/setuptools_rust/extension.py @@ -1,6 +1,7 @@ import json import os import re +import warnings import subprocess from distutils.errors import DistutilsSetupError from enum import IntEnum, auto @@ -160,6 +161,12 @@ def __init__( self._cargo_metadata: Optional[_CargoMetadata] = None + if binding == Binding.Exec and script: + warnings.warn( + "'Binding.Exec' with 'script=True' is deprecated, use 'RustBin' instead.", + DeprecationWarning, + ) + def get_lib_name(self) -> str: """Parse Cargo.toml to get the name of the shared library.""" metadata = self._metadata() @@ -240,6 +247,67 @@ def _uses_exec_binding(self) -> bool: return self.binding == Binding.Exec +class RustBin(RustExtension): + """Used to define a Rust binary and its build configuration. + + Args: + target: Rust binary target name. + path: Path to the ``Cargo.toml`` manifest file. + args: A list of extra arguments to be passed to Cargo. For example, + ``args=["--no-default-features"]`` will disable the default + features listed in ``Cargo.toml``. + cargo_manifest_args: A list of extra arguments to be passed to Cargo. + These arguments will be passed to every ``cargo`` command, not just + ``cargo build``. For valid options, see + `the Cargo Book `_. + For example, ``cargo_manifest_args=["--locked"]`` will require + ``Cargo.lock`` files are up to date. + features: A list of Cargo features to also build. + rustc_flags: A list of additional flags passed to rustc. + rust_version: Minimum Rust compiler version required for this + extension. + quiet: Suppress Cargo's output. + debug: Controls whether ``--debug`` or ``--release`` is passed to + Cargo. If set to `None` (the default) then build type is + automatic: ``inplace`` build will be a debug build, ``install`` + and ``wheel`` builds will be release. + strip: Strip symbols from final file. Does nothing for debug build. + native: Build extension or executable with ``--target-cpu=native``. + """ + + def __init__( + self, + target: str, + path: str = "Cargo.toml", + args: Optional[List[str]] = None, + cargo_manifest_args: Optional[List[str]] = None, + features: Optional[List[str]] = None, + rustc_flags: Optional[List[str]] = None, + rust_version: Optional[str] = None, + quiet: bool = False, + debug: Optional[bool] = None, + strip: Strip = Strip.No, + native: bool = False, + ): + super().__init__( + target, + path, + args, + cargo_manifest_args, + features, + rustc_flags, + rust_version, + quiet, + debug, + binding=Binding.Exec, + strip=strip, + native=native, + ) + + def entry_points(self) -> List[str]: + return [] + + _CargoMetadata = NewType("_CargoMetadata", Dict[str, Any])