Skip to content

Commit 241818b

Browse files
authored
Use cbindgen via Rust API (#14013)
* 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
1 parent 00c4756 commit 241818b

3 files changed

Lines changed: 51 additions & 14 deletions

File tree

Makefile

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ C_LIB_CARGO_PATH=$(C_CARGO_TARGET_DIR)/$(C_LIB_CARGO_FILENAME)
106106
C_QISKIT_H=$(C_DIR_INCLUDE)/qiskit.h
107107
C_LIBQISKIT=$(C_DIR_LIB)/$(subst _cext,,$(C_LIB_CARGO_FILENAME))
108108

109-
110109
# Run clang-format (does not apply any changes)
111110
cformat:
112111
bash tools/run_clang_format.sh
@@ -120,22 +119,24 @@ fix_cformat:
120119
$(C_LIB_CARGO_PATH):
121120
cargo rustc --release --crate-type cdylib -p qiskit-cext
122121

123-
$(C_QISKIT_H): $(C_LIB_CARGO_PATH)
124-
cbindgen --crate qiskit-cext --output $(C_DIR_INCLUDE)/qiskit.h --lang C
125-
126122
$(C_DIR_LIB):
127123
mkdir -p $(C_DIR_LIB)
128124

129-
$(C_LIBQISKIT): $(C_DIR_LIB) $(C_LIB_CARGO_PATH)
125+
$(C_DIR_INCLUDE):
126+
mkdir -p $(C_DIR_INCLUDE)
127+
128+
$(C_LIBQISKIT): $(C_DIR_LIB) $(C_LIB_CARGO_PATH)
130129
cp $(C_LIB_CARGO_PATH) $(C_DIR_LIB)/$(subst _cext,,$(C_LIB_CARGO_FILENAME))
131130

132-
.PHONY: cheader clib c
131+
$(C_QISKIT_H): $(C_DIR_INCLUDE) $(C_LIB_CARGO_PATH)
132+
cp target/qiskit.h $(C_DIR_INCLUDE)/qiskit.h
133+
134+
.PHONY: c cheader
133135
cheader: $(C_QISKIT_H)
134-
clib: $(C_LIBQISKIT)
135-
c: clib cheader
136+
c: $(C_LIBQISKIT) $(C_QISKIT_H)
136137

137138
# Use ctest to run C API tests
138-
ctest: $(C_QISKIT_H)
139+
ctest: $(C_LIB_CARGO_PATH) $(C_QISKIT_H)
139140
# -S specifically specifies the source path to be the current folder
140141
# -B specifically specifies the build path to be inside test/c/build
141142
cmake -S. -B$(C_DIR_TEST_BUILD)
@@ -147,3 +148,5 @@ ctest: $(C_QISKIT_H)
147148

148149
cclean:
149150
rm -rf $(C_DIR_OUT) $(C_DIR_TEST_BUILD)
151+
rm -f target/qiskit.h
152+
cargo clean

crates/cext/build.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,36 @@
1010
// copyright notice, and modified files need to carry a notice indicating
1111
// that they have been altered from the originals.
1212

13-
fn main() {
14-
// Get the Python library directory and library name that PyO3 is using, and store it into a
15-
// configuration file.
13+
use std::str::FromStr;
14+
15+
extern crate cbindgen;
16+
17+
/// This function generates the C header for Qiskit from the qiskit-cext crate.
18+
fn generate_qiskit_header() {
19+
// Trigger this script if the header was changed/removed.
20+
#![allow(clippy::print_stdout)]
21+
println!("cargo:rerun-if-changed=../../target/qiskit.h");
22+
23+
// Pull the config from the cbindgen.toml file.
24+
let config = cbindgen::Config::from_file("cbindgen.toml").unwrap();
25+
26+
// Ensure target path exists and then set the full filename of qiskit.h.
27+
let mut path = ::std::path::PathBuf::from_str("../../target/").unwrap();
28+
::std::fs::create_dir_all(&path).expect("Could not create target directory.");
29+
path.push("qiskit.h");
30+
31+
// Build the header.
32+
cbindgen::Builder::new()
33+
.with_crate(".")
34+
.with_config(config)
35+
.generate()
36+
.expect("Unable to generate C bindings.")
37+
.write_to_file(path);
38+
}
39+
40+
// Get the Python library directory and library name that PyO3 is using, and store it into a
41+
// configuration file.
42+
fn write_python_config() {
1643
let interpreter_config = pyo3_build_config::get();
1744
let pyo3_lib_config = format!(
1845
"PYO3_PYTHON_LIB_DIR={}\nPYO3_PYTHON_LIB_NAME={}\n",
@@ -28,5 +55,10 @@ fn main() {
2855
match ::std::fs::write(pyo3_config_file, pyo3_lib_config) {
2956
Ok(_) => (),
3057
Err(_) => println!("cargo:warning=Failed to write Python config."),
31-
}
58+
};
59+
}
60+
61+
fn main() {
62+
generate_qiskit_header();
63+
write_python_config();
3264
}

crates/cext/cbindgen.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
language = "C"
12
include_version = true
2-
include_guard = "QISKIT_H_INCLUDED"
3+
include_guard = "QISKIT_H"
34
style = "type"
5+
46
sys_includes = ["complex.h"]
57
after_includes = """
68
#ifdef QISKIT_C_PYTHON_INTERFACE

0 commit comments

Comments
 (0)