-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Use cbindgen
via Rust API
#14013
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
Use cbindgen
via Rust API
#14013
Conversation
One or more of the following people are relevant to this code:
|
Pull Request Test Coverage Report for Build 14171774193Details
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the concept of this integrating the header generation into the build process, it makes a lot of sense, especially when building the standalone c dynamic library.
My concern is for the case where people are trying to get the header file without building the library. For example, if a user of the precompiled wheels is trying to generate the header and build a custom python extension the normal workflow is to run cbindgen manually or run make cheader
. So I'm wondering what the workflow is for that use case here because you removed the cbindgen.toml so the standalone header generation doesn't work anymore does it?
Yes that's a good point. It seems we can actually have both (until we would need features only exposed in the Rust API): we can have the settings in a |
and use Makefile to correctly move or regenerate the file lazily
I thought a point of this PR was that the build-script API is more featureful than the stand-alone command-line build. If so, then surely we must be removing the stand-alone build as a supported option, or we're setting ourselves up for pain when the two build methods start producing different results. I don't see a huge problem with "to build the header file you must build the library", especially at this early stage, but as a minimal workaround at least: |
Makefile
Outdated
$(C_LIB_CARGO_PATH): | ||
cargo rustc --release --crate-type cdylib -p qiskit-cext | ||
|
||
$(C_QISKIT_H): $(C_LIB_CARGO_PATH) | ||
cbindgen --crate qiskit-cext --output $(C_DIR_INCLUDE)/qiskit.h --lang C | ||
# Compile the C library and move the header into the right location, if it was generated | ||
$(C_LIB_CARGO_PATH): $(C_DIR_INCLUDE) | ||
cargo build --release -p qiskit-cext | ||
@if [ -f crates/cext/qiskit.h ]; then mv crates/cext/qiskit.h $(C_DIR_INCLUDE)/qiskit.h; fi | ||
|
||
$(C_DIR_LIB): | ||
mkdir -p $(C_DIR_LIB) | ||
|
||
$(C_LIBQISKIT): $(C_DIR_LIB) $(C_LIB_CARGO_PATH) | ||
$(C_DIR_INCLUDE): | ||
mkdir -p $(C_DIR_INCLUDE) | ||
|
||
$(C_LIBQISKIT): $(C_DIR_LIB) $(C_LIB_CARGO_PATH) | ||
cp $(C_LIB_CARGO_PATH) $(C_DIR_LIB)/$(subst _cext,,$(C_LIB_CARGO_FILENAME)) | ||
|
||
.PHONY: cheader clib c | ||
$(C_QISKIT_H): $(C_LIB_CARGO_PATH) | ||
@if [ ! -f "$(C_QISKIT_H)" ]; then cbindgen --crate qiskit-cext --output $(C_DIR_INCLUDE)/qiskit.h; fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's quite a lot of duplication going on here, and recipes building more than they're specifically asked. Recipes with specific filenames should build that filename only. Copying the file from one place to another is a separate recipe.
I don't think we should have cbindgen
as a command-line tool anywhere in the Makefile anymore, since we're now doing this by build script?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header handling is not analogous to how you did the lib handling before: there's separate targets for creating the include dir and copying the header into the include dir. Also cbindgen
is now no longer needed as command line tool since I added target/qiskit.h
as tracked file in the build script (to ensure it is rebuilt if it was removed/touched). I tested locally that deleting the headers manually retriggers the build process.
write header into target/qiskit.h and copy into dist/c/include with Makefile. The cargo build script tracks changes in target/qiskit.h and rebuilds if changed/deleted Not sure if this is the best way but it seems to work :)
…o cbindgen-script
this is probably why CI doesn't work, we need to ensure the cdylib is built
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good to me. Thanks for the updates on this, I just have one small inline question/comment about the build_header.rs
but otherwise I think this ready to merge.
crates/cext/build_header.rs
Outdated
let config = cbindgen::Config::from_file("cbindgen.toml").unwrap(); | ||
|
||
// Ensure target path exists and then set the full filename of qiskit.h. | ||
let mut path = ::std::path::PathBuf::from_str("../../target/").unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always worry when I see a relative path unqualified like this, since it's assuming the cwd is crates/cext/build_header
but I checked and there is not official way to get the target dir from cargo. The file!()
macro might be useful here, but I'm not sure what that returns, if it's the absolute path to build_header.rs
on the local filesystem that might be a better option, but if it just returns build_header.rs
that's obviously not useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An absolute path would indeed be nicer, but I didn't really find a way to get it. file!()
returned just crates/cext/build_header.rs
as path, not the absolute path to reach the target
dir... I tested building both from Qiskit root and cargo/cext
and it seems to work, if that is consolidation enough 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well then lets go with it, I couldn't come up with a better solution either and there is a tracking issue in cargo already: rust-lang/cargo#9661
So I'm fine with doing this and if/when we come up with an alternative we can adjust it. But, do you know if this works on windows? Maybe we wait until #14030 merges just to make sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, let's see if CI passes
* move cbindgen to Rust build * add include guard * allow cmdline build and compile-time build * write `qiskit.h` to `crates/cext` and use Makefile to correctly move or regenerate the file lazily * try cleaner build setup write header into target/qiskit.h and copy into dist/c/include with Makefile. The cargo build script tracks changes in target/qiskit.h and rebuilds if changed/deleted Not sure if this is the best way but it seems to work :) * try fix build deps, and fix clippy * fix merge artifact this is probably why CI doesn't work, we need to ensure the cdylib is built * include dir creation as dependency (cherry picked from commit 241818b)
* move cbindgen to Rust build * add include guard * allow cmdline build and compile-time build * write `qiskit.h` to `crates/cext` and use Makefile to correctly move or regenerate the file lazily * try cleaner build setup write header into target/qiskit.h and copy into dist/c/include with Makefile. The cargo build script tracks changes in target/qiskit.h and rebuilds if changed/deleted Not sure if this is the best way but it seems to work :) * try fix build deps, and fix clippy * fix merge artifact this is probably why CI doesn't work, we need to ensure the cdylib is built * include dir creation as dependency (cherry picked from commit 241818b) Co-authored-by: Julien Gacon <jules.gacon@googlemail.com>
Summary
We currently generate the header using
cbindgen
as command line tool. This works, butcbindgen
has (ok almost all)This PR moves to using the Rust API of
cbindgen
and builds the header as part of theqiskit-cext
compilation process. This fixes all the above points. The one down side is that thecbindgen.toml
was a bit nicer to read IMO, but that's a small price to pay.It would be nice to backport this to
stable/2.0
for a smoother build process for users.Details
Makefile
is slightly simpler now since we don't need to separately call the command line tool to generate the header file.