Open mxk opened 2 years ago
Oooh - this is really clever and the first potential solution for making cargo build
just work that seems viable! Thank you for figuring this out and taking the time to write it up!
Correct me if I'm wrong, but isn't a drawback of using [patch.crates-io]
that you can't upload the crate to crates.io? So if we went with this approach, projects using this approach wouldn't be publishable? (If so, this isn't a deal breaker to implementing this. But we'd probably want to make the functionality optional so people can have a publishable project.)
Also, the PyO3 maintainers have been very generous in implementing features upstream to accommodate PyOxidizer's use cases. But if I were a PyO3 maintainer, I'd be highly skeptical of teaching the canonical pyo3-build-config
to invoke pyoxidizer
and look for environment variables like PYOXIDIZER_CONFIG
and PYOXIDIZER_EXE
because it is too tightly coupled to a narrow use case. Can you think of a more generic way to achieve similar results in upstream pyo3-build-config
so we don't have to patch that crate indefinitely?
Thank you again for contributing this. This looks like a great idea!
According to this, crates.io ignores [patch]
sections, so this solution definitely won't work for anything that needs to be published.
I think a better solution will require pyo3-build-config
to have an optional feature/dependency on something that can generate the config as part of the build process. I'm imagining a very minimal crate that either has a single public CONFIG_FILE
const, or uses links = "pyo3"
to pass DEP_PYO3_CONFIG_FILE
to pyo3-build-config
.
This dependency could be PyOxidizer-specific, which would be very similar to the build script above, and require the user to either run PYOXIDIZER_CONFIG=<path> cargo build
, or add that variable to the [env] section. This solution completely eliminates the need for any patching and can be maintained as part of this project. The only real complication I see is how to trigger rebuilds when the Python source that's being packaged changes. That's why I currently have the cargo:rerun-if-changed=../pysrc
line above.
Alternatively, the dependency can be very generic, with the published version just being a no-op. The user could then patch it to supply custom config file generation logic, which may or may not depend on PyOxidizer.
I'm thinking something like this being added to pyo3-build-config
's manifest and some small modifications being made to its build script to use the output of these dependencies when PYO3_CONFIG_FILE
is unspecified:
[build-dependencies]
# Config generator that depends on PYOXIDIZER_CONFIG and PYOXIDIZER_EXE
pyo3-pyoxidizer-gen = { version = "0.20.0", optional = true }
# Custom generator that needs to be patched to do anything useful
pyo3-config-gen = { version = "1.0.0", optional = true }
Also, what are the advantages of using pyoxidizer
exe (it being a dependency that should be manually installed and updated) instead of calling pyoxidizerlib::project_building::run_from_build
directly from build.rs
?
My goal was to build a Rust project that embeds python and all dependencies via a simple
cargo build
. I finally figured out a method for doing this, but it's pretty much one big hack. Nevertheless, it may be helpful to others and could guide future development.The problem with the project structure created by
pyoxidizer init-rust-project
is that thepyo3-build-config
dependency needsPYO3_CONFIG_FILE
to point topyo3-build-config-file.txt
, which is generated bypyoxidizer run-build-script
. As a result, the only way to get a working build is to generate the artifacts first and then pass the relevant environment variables tocargo build
, as described in #467. Running the generatedbuild.rs
inbuild-mode-pyoxidizer-exe
mode does not work since all thepyo3
dependencies are already built by that point using the default configuration.A way to get everything to work with a one
cargo build
command is to havepyo3-build-config
runpyoxidizer run-build-script
directly. I used a [patch] override to do that. Essentially, I created my ownpyo3-build-config
package that runspyoxidizer
. It depends on the realpyo3-build-config
to avoid re-implementing most of the functionality.Below are the relevant file contents. I've omitted
./py/pyoxidizer.bzl
and other files generated bypyoxidizer init-rust-project
because those are all standard. Use at your own risk.Note that this still does not solve #466.
./Cargo.toml
:./py/Cargo.toml
:./py/build.rs
:./py/pyo3-build-config/Cargo.toml
:./py/pyo3-build-config/build.rs
:./py/pyo3-build-config/src/lib.rs
: