-
-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ship both python library AND binary command line tool in wheel #368
Comments
For shipping both library and binary, you'd need to build twice and ship both binaries, having two copies of each dependency in the wheel. Would it be possible to work around issue by adding a pseudo-main to the rust library and creating a small python script that only calls the main of library? |
Does anyhow know how to control this from the pyproject.toml, so that |
After #948 we now have the skeleton to allow shipping both lib and bin, the remaining question is how to let users configure it. We'd still want maturin to by default only build I'm thinking about adding the following options to [[tool.maturin.targets]]
name = "example"
kind = "bin"
[[tool.maturin.targets]]
name = "example"
kind = "lib" Then you will get a I don't quite like the |
Sounds good to me. Agreed |
I like it and while |
Thanks for the feedback! While thinking more about this, there is a question on how does the existing The bindings detection might need to be changed to be per-target, and allow users to override it in [[tool.maturin.targets]]
name = "example"
kind = "bin"
bindings = "pyo3" # example links to libpython
[[tool.maturin.targets]]
name = "example"
kind = "lib"
bindings = "cffi" # or pyo3 and others |
We've been thinking about this as well - while this issue keeps moving forward, has anyone found a workaround to package both "bin" and "pyo3" bindings in a single wheel in the meantime? |
1328: Refactor `compile` to take cargo targets with bridge model r=messense a=messense To enable different bridge model per target in the future, baby steps towards #368 (comment) Co-authored-by: messense <messense@icloud.com>
maturin doesn't yet support packaging both a binary and a library into the same package. PyO3/maturin#368
maturin doesn't yet support packaging both a binary and a library into the same package. PyO3/maturin#368
maturin doesn't yet support packaging both a binary and a library into the same package. PyO3/maturin#368
maturin doesn't yet support packaging both a binary and a library into the same package. PyO3/maturin#368
1339: Add Cargo compile targets configuration for filtering multiple bin targets r=messense a=messense Implements #368 (comment) Co-authored-by: messense <messense@icloud.com>
1339: Add Cargo compile targets configuration for filtering multiple bin targets r=messense a=messense Implements #368 (comment) Co-authored-by: messense <messense@icloud.com>
1339: Add Cargo compile targets configuration for filtering multiple bin targets r=messense a=messense Implements #368 (comment) Co-authored-by: messense <messense@icloud.com>
Here is my workaround, but I can't guarantee the correctness. The idea is to build for two bindings and merge the built wheel. #!/bin/bash
set -e
# Implementation:
TMPDIR=.merge-tmp
rm -rf "$TMPDIR"
mkdir -p "$TMPDIR/tmp1"
mkdir -p "$TMPDIR/tmp2"
# Build the wheel
# Note that for my specific use case, "python" feature is needed. You might want to change it.
maturin build -F python --release --bindings pyo3 -o "$TMPDIR/tmp1" $@
maturin build -F python --release --bindings bin -o "$TMPDIR/tmp2" $@
# Grab Info
file_name=$(basename $(/bin/ls "$TMPDIR/tmp1"/*.whl))
dist_info=$(unzip -qql "$TMPDIR/tmp1/*.whl" | grep "\.dist-info/METADATA" | awk '{print $4}' | cut -d/ -f1)
name_version=$(basename -s '.dist-info' $dist_info)
# Merge wheel
mkdir -p "$TMPDIR/merged"
unzip -qo "$TMPDIR/tmp1/$file_name" -d "$TMPDIR/merged"
unzip -qo "$TMPDIR/tmp2/$file_name" -d "$TMPDIR/merged"
# Merge record
unzip -qjo "$TMPDIR/tmp1/$file_name" "*.dist-info/RECORD" -d "$TMPDIR/tmp1"
unzip -qjo "$TMPDIR/tmp2/$file_name" "*.dist-info/RECORD" -d "$TMPDIR/tmp2"
cat "$TMPDIR/tmp1/RECORD" "$TMPDIR/tmp2/RECORD" | sort | uniq > "$TMPDIR/merged/$name_version.dist-info/RECORD"
# Create the wheel
cd "$TMPDIR/merged"
zip -qr "../../$file_name" *
cd ../..
rm -rf "$TMPDIR" |
Here to say +1 for this feature. Love the project great work. |
For those commenting here, could you also comment on why using an entrypoint that calls a pyo3/cffi function in the shared library doesn't work for you? |
Just confirming that this means adding an entry point to [project.scripts] in pyproject.toml from which you call a pseudo-main function that you initialized in rust lib (i.e. run_cli). I have done this and it does function as expected. I think that this solution was simple and could avoid the above mentioned overhead by increasing documentation that this option/configuration exists. Thank you. |
I don't think its a matter of "doesn't work" as much as perceived in efficiencies in loading a python interpreter to launch a rust program. Might be worth a performance comparison to demonstrate one way or the other if its an actual problem, if it goes beyond "nice to have" I can maybe attempt something in the future. |
1565: Document binary and library in a single package by entrypoint workaround r=messense a=konstin Inspired by #368 (comment) Preview: https://deploy-preview-1565--maturin-guide.netlify.app/bindings.html#both-binary-and-library CC `@nanthony007` Co-authored-by: konstin <konstin@mailbox.org>
My use case for this is: I have a binary in Rust that does supervision/instrumentation of a Python program, and it comes with a small Python extension module to help the Python program integrate properly. Launching an entire Python interpreter in order to supervise my other Python interpreter could work, but it's pretty wasteful (memory + startup speed), and more importantly it adds fragility (the whole reason I'm running my Rust binary is because I don't 100% trust my Python interpreter, and I want Rust to keep an eye on it! also I might eg want to run the Rust binary ad hoc from outside a container to debug a Python that's inside the container, so I don't have easy access to the Python environment...). |
FWIW, https://github.com/deshaw/nbstripout-fast would be the same sort of idea as @njsmith. We need to ship a rust binary because launching python is too slow (that's a huge fraction of why we wrote it in rust). Our setup today is:
Ideally we'd add:
|
@njsmith @mlucool Thank you, those are very helpful replies and make a great case for including this feature For further design, do you think it would or would not make sense if maturin would automatically produce two different wheel, one for binary and on for the library, that could potentially depend on each other, either unconditionally or through an extra? That way the user could e.g. only install the binary or only the python module without having to download and install twice the size, and the binary wheels wouldn't depend on the python interpreter (if on the other hand you anyway always need them together or having a single wheel is a requirement, then only putting both in the same wheel would make sense) |
i'm always happy about real world benchmark numbers! |
I suspect flexibility is always what people want :). In my case, my rust program is small and no one would notice double the size so that would be the default either way for my use case. |
1565: Document binary and library in a single package by entrypoint workaround r=messense a=konstin Inspired by #368 (comment) Preview: https://deploy-preview-1565--maturin-guide.netlify.app/bindings.html#both-binary-and-library CC `@nanthony007` Co-authored-by: konstin <konstin@mailbox.org>
1565: Document binary and library in a single package by entrypoint workaround r=konstin a=konstin Inspired by #368 (comment) Preview: https://deploy-preview-1565--maturin-guide.netlify.app/bindings.html#both-binary-and-library CC `@nanthony007` Co-authored-by: konstin <konstin@mailbox.org>
1565: Document binary and library in a single package by entrypoint workaround r=konstin a=konstin Inspired by #368 (comment) Preview: https://deploy-preview-1565--maturin-guide.netlify.app/bindings.html#both-binary-and-library CC `@nanthony007` Co-authored-by: konstin <konstin@mailbox.org>
Use Python entrypoint as a workload (https://www.maturin.rs/bindings#both-binary-and-library) until PyO3/maturin#368 is resolved. Signed-off-by: Akhil Velagapudi <4@4khil.com>
Use Python entrypoint as a workload (https://www.maturin.rs/bindings#both-binary-and-library) until PyO3/maturin#368 is resolved. Signed-off-by: Akhil Velagapudi <4@4khil.com>
+1 |
It’s too slow to start up. For a Python extension imported into a larger program, the fixed startup cost is paid once by the parent process, and the early import. For a binary wrapped in a PyO3 wrapper, the startup cost is paid every time the script is invoked. It’s just too expensive. Two pyproject.toml files, one for binary, one for extension, built into two separate wheels, seems to be the best we can do right now. |
Use Python entrypoint as a workload (https://www.maturin.rs/bindings#both-binary-and-library) until PyO3/maturin#368 is resolved. Signed-off-by: Akhil Velagapudi <4@4khil.com>
Are there any updates on this? Is the recommended path forward still to have a python wrapper around the rust binary to serve as an entry point? Would love to see if there was bona fide support for the rust binary situation. |
Use Python entrypoint as a workload (https://www.maturin.rs/bindings#both-binary-and-library) until PyO3/maturin#368 is resolved. Signed-off-by: Akhil Velagapudi <4@4khil.com>
Use Python entrypoint as a workload (https://www.maturin.rs/bindings#both-binary-and-library) until PyO3/maturin#368 is resolved. Signed-off-by: Akhil Velagapudi <4@4khil.com>
I'm in a situation where I would like to build both a python library and a command line tool in a wheel for distribution. (e.g., https://python-packaging.readthedocs.io/en/latest/command-line-scripts.html , but all the code would be in rust.)
The Cargo.toml would contain:
Is it possible to do this in maturin?
I've tried doing
maturin build -b "bin"
, which only builds the command line tool (my_commandline) and not the library.maturin build -b "pyo3"
likewise only builds the library (my_library) and not the command line tool.Is it currently possible to build with both "bin" and "pyo3" bindings in a single wheel?
The text was updated successfully, but these errors were encountered: