-
Notifications
You must be signed in to change notification settings - Fork 0
Update for libquil on modern sbcl-librarian #68
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
base: main
Are you sure you want to change the base?
Changes from all commits
4cbf5c8
45a5592
a3d2917
736a08e
545d05d
7b4bd4d
7e913f3
d8435d1
665f580
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,33 +1,52 @@ | ||
| name: Prepare Release | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
| inputs: | ||
| type: | ||
| description: Bump versions and trigger a new release. | ||
| required: true | ||
| default: release | ||
| options: | ||
| - release | ||
|
|
||
| jobs: | ||
| prepare-release: | ||
| runs-on: ubuntu-22.04 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.PAT }} | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
| # Release from the ref this was dispatched on, so a prerelease cut from a | ||
| # branch tags that branch rather than the default one. | ||
| ref: ${{ github.ref }} | ||
| token: ${{ secrets.PAT }} | ||
| - name: Install Knope | ||
| uses: knope-dev/action@v2.1.0 | ||
| uses: knope-dev/action@v2.1.2 | ||
| with: | ||
| version: 0.10.0 # Test before updating, breaking changes likely: https://github.com/knope-dev/action#install-latest-version | ||
| # 0.23 is needed for `--prerelease-label` and for tagging the ref being | ||
| # released. 0.10 tagged the default branch instead, so a prerelease cut from | ||
| # a branch produced a tag pointing at main's version, and the publish job | ||
| # then tried to republish that already-released version. | ||
| version: 0.23.0 # Test before updating, breaking changes likely: https://github.com/knope-dev/action#install-latest-version | ||
| - run: | | ||
| git config --global user.name "${{ github.triggering_actor }}" | ||
| git config --global user.email "${{ github.triggering_actor}}@users.noreply.github.com" | ||
|
|
||
| # On a pull request, only show what a release would do. | ||
| - name: Dry-run Release | ||
| if: github.event_name == 'pull_request' | ||
| run: knope release --verbose --dry-run | ||
|
|
||
| - name: Prepare Release | ||
| run: knope ${{ inputs.type }} --verbose | ||
| if: github.event_name == 'workflow_dispatch' | ||
| env: | ||
| # The Release step authenticates with this rather than an argument. | ||
| GITHUB_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| # A release off main is a real one; anywhere else it can only be a | ||
| # prerelease, which is how a change that needs a matching libquil release | ||
| # gets published for testing before either side is final. | ||
| if [[ "$GITHUB_REF" == "refs/heads/main" ]]; then | ||
| knope release --verbose | ||
| else | ||
| knope release --verbose --prerelease-label=rc | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,17 @@ on: | |
| branches: | ||
| - 'main' | ||
|
|
||
| env: | ||
| # The libquil release these bindings are built against. libquil's move to modern | ||
| # sbcl-librarian changed its C ABI and the set of files it installs, so this crate | ||
| # needs a release from after that change: 0.3.x installs neither the runtime | ||
| # headers nor libsbcl_librarian, and the build fails in build.rs. | ||
| LIBQUIL_VERSION: "0.4.0-rc.0" | ||
| # install.sh is fetched from the tag being installed. It has to match the release | ||
| # above: the installer that ships with a release knows which files that release | ||
| # contains, and the modern-sbcl-librarian layout added the runtime directory. | ||
| LIBQUIL_INSTALL_REF: "v0.4.0-rc.0" | ||
|
Comment on lines
+10
to
+18
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update to "release" tags once rigetti/libquil#58 is merged & released |
||
|
|
||
| jobs: | ||
| test-linux: | ||
| runs-on: ubuntu-22.04 | ||
|
|
@@ -20,14 +31,14 @@ jobs: | |
| - uses: dtolnay/rust-toolchain@stable | ||
| - name: Install libquil | ||
| run: | | ||
| curl https://raw.githubusercontent.com/rigetti/libquil/main/install.sh | bash -s 0.3.0 | ||
| curl https://raw.githubusercontent.com/rigetti/libquil/$LIBQUIL_INSTALL_REF/install.sh | bash -s $LIBQUIL_VERSION | ||
| - name: Run tests | ||
| run: | | ||
| cd $GITHUB_WORKSPACE/lib | ||
| cargo test | ||
|
|
||
| test-macos: | ||
| runs-on: macos-15-intel | ||
| runs-on: macos-latest | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
|
|
@@ -37,7 +48,7 @@ jobs: | |
| run: brew install lapack openblas | ||
| - uses: dtolnay/rust-toolchain@stable | ||
| - name: Install libquil | ||
| run: 'curl https://raw.githubusercontent.com/rigetti/libquil/main/install.sh | bash -s 0.3.0' | ||
| run: 'curl https://raw.githubusercontent.com/rigetti/libquil/$LIBQUIL_INSTALL_REF/install.sh | bash -s $LIBQUIL_VERSION' | ||
| - name: Run tests | ||
| run: | | ||
| cd $GITHUB_WORKSPACE/lib | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,25 @@ | ||
| ## 0.5.0-rc.2 (2026-08-12) | ||
|
|
||
| ### Breaking Changes | ||
|
|
||
| - build against libquil on modern sbcl-librarian | ||
|
|
||
| ### Fixes | ||
|
|
||
| - read libquil path envvars at build-script runtime | ||
|
|
||
| ## 0.5.0-rc.1 (2026-08-12) | ||
|
|
||
| ### Breaking Changes | ||
|
|
||
| - build against libquil on modern sbcl-librarian | ||
|
|
||
| ## 0.5.0-rc.0 (2026-08-12) | ||
|
|
||
| ### Breaking Changes | ||
|
|
||
| #### build against libquil on modern sbcl-librarian | ||
|
|
||
|
Comment on lines
+1
to
+22
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: delete the redundant entries before merging |
||
| ## 0.4.2 (2026-05-21) | ||
|
|
||
| ### Fixes | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,22 +3,42 @@ use std::path::PathBuf; | |
|
|
||
| #[derive(Debug, thiserror::Error)] | ||
| enum Error { | ||
| #[error("Could not find error in any of the standard locations. Try setting C_INCLUDE_PATH or LIBQUIL_SRC_PATH")] | ||
| #[error("Could not find libquil.h in any of the standard locations. Try setting C_INCLUDE_PATH or LIBQUIL_SRC_PATH")] | ||
| HeaderNotFound, | ||
| #[error( | ||
| "Found libquil.h at {0}, but no sbcl_librarian.h beside it. This crate requires a libquil \ | ||
| built against modern sbcl-librarian, which installs the runtime headers alongside \ | ||
| libquil.h; an older libquil (0.3.x or earlier) does not have them. Install a newer \ | ||
| libquil, or set LIBQUIL_SRC_PATH to a build that has one." | ||
| )] | ||
| RuntimeHeaderNotFound(String), | ||
| #[error("Could not read environment variable: {0}")] | ||
| InvalidEnvvar(#[from] env::VarError), | ||
| } | ||
|
|
||
| /// Environment variables that select a libquil installation. They are read when the | ||
| /// build script *runs*, so changing one takes effect without a manual `cargo clean`; | ||
| /// `cargo:rerun-if-env-changed` is what makes cargo re-run us when they change. | ||
| const PATH_ENVVARS: [&str; 3] = ["LIBQUIL_SRC_PATH", "LIBQUIL_LIB_PATH", "C_INCLUDE_PATH"]; | ||
|
|
||
| /// The value of `name`, or `None` when it is unset or empty. An empty value is | ||
| /// treated as unset so that `LIBQUIL_SRC_PATH= cargo build` does not put the | ||
| /// current directory at the front of the search order. | ||
| fn env_path(name: &str) -> Option<String> { | ||
| env::var(name).ok().filter(|value| !value.is_empty()) | ||
| } | ||
|
|
||
| fn get_header_path() -> Result<PathBuf, Error> { | ||
| let mut paths = vec!["/usr/local/include/libquil", "/usr/include/libquil"]; | ||
| let mut paths = vec![ | ||
| "/usr/local/include/libquil".to_string(), | ||
| "/usr/include/libquil".to_string(), | ||
| ]; | ||
|
|
||
| let libquil_src_path: Option<&'static str> = option_env!("LIBQUIL_SRC_PATH"); | ||
| if let Some(libquil_src_path) = libquil_src_path { | ||
| if let Some(libquil_src_path) = env_path("LIBQUIL_SRC_PATH") { | ||
| paths.insert(0, libquil_src_path); | ||
| } | ||
|
|
||
| let c_include_path: Option<&'static str> = option_env!("C_INCLUDE_PATH"); | ||
| if let Some(c_include_path) = c_include_path { | ||
| if let Some(c_include_path) = env_path("C_INCLUDE_PATH") { | ||
| paths.insert(0, c_include_path); | ||
| } | ||
|
|
||
|
|
@@ -35,34 +55,68 @@ fn get_header_path() -> Result<PathBuf, Error> { | |
| fn get_lib_search_paths() -> Vec<String> { | ||
| let mut paths = vec!["/usr/local/lib".to_string(), "/usr/lib".to_string()]; | ||
|
|
||
| let libquil_src_path: Option<&'static str> = option_env!("LIBQUIL_SRC_PATH"); | ||
| if let Some(libquil_src_path) = libquil_src_path { | ||
| // For installs that do not use /usr/local, where the headers and libraries live | ||
| // in separate directories and LIBQUIL_SRC_PATH names only the former. | ||
| if let Some(libquil_lib_path) = env_path("LIBQUIL_LIB_PATH") { | ||
| paths.insert(0, libquil_lib_path); | ||
| } | ||
|
|
||
| if let Some(libquil_src_path) = env_path("LIBQUIL_SRC_PATH") { | ||
| // libquil is a FASL library loaded into the libsbcl_librarian runtime, so | ||
| // both must be found. A source tree keeps the runtime in a subdirectory; | ||
| // an installed layout puts everything in one directory. | ||
| paths.insert(0, format!("{libquil_src_path}/runtime")); | ||
| paths.insert(0, libquil_src_path.to_string()); | ||
| } | ||
|
|
||
| paths | ||
| } | ||
|
|
||
| fn main() -> Result<(), Error> { | ||
| /// Directories to search for headers. `libquil.h` includes `sbcl_librarian_err.h`, | ||
| /// and `get_error_message` is declared in `sbcl_librarian.h`, both of which ship | ||
| /// with the runtime. | ||
| fn get_include_paths(libquil_header_path: &std::path::Path) -> Vec<PathBuf> { | ||
| let mut paths = Vec::new(); | ||
| if let Some(dir) = libquil_header_path.parent() { | ||
| paths.push(dir.to_path_buf()); | ||
| paths.push(dir.join("runtime")); | ||
| } | ||
| paths.retain(|p| p.exists()); | ||
| paths | ||
| } | ||
|
|
||
| fn main() { | ||
| // Cargo prints a build script's error with Debug, which would hide the | ||
| // explanation these errors carry, so report it and exit rather than returning it. | ||
|
Comment on lines
+89
to
+90
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this comment is explaining why
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's necessary to explain
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Frankly I'd accept a |
||
| if let Err(error) = build() { | ||
| eprintln!("\nerror: {error}\n"); | ||
| std::process::exit(1); | ||
| } | ||
| } | ||
|
|
||
| fn build() -> Result<(), Error> { | ||
| for envvar in PATH_ENVVARS { | ||
| println!("cargo:rerun-if-env-changed={envvar}"); | ||
| } | ||
|
|
||
| let libquil_header_path = get_header_path()?; | ||
|
|
||
| for path in get_lib_search_paths() { | ||
| println!("cargo:rustc-link-search={}", path); | ||
| } | ||
|
|
||
| println!("cargo:rustc-link-lib=quil"); | ||
| // The runtime that hosts libquil: it supplies the Lisp image, the error API | ||
| // (get_error_message) and the handle API (lisp_release_handle). | ||
| println!("cargo:rustc-link-lib=sbcl_librarian"); | ||
|
|
||
| // Tell cargo to rerun if the libquil implementation has changed | ||
| println!( | ||
| "cargo:rustc-rerun-if-changed={}", | ||
| "cargo:rerun-if-changed={}", | ||
| libquil_header_path.clone().display() | ||
| ); | ||
|
|
||
| // If this isn't set on MacOS, memory allocation errors occur when trying to initialize the | ||
| // library | ||
| if cfg!(target_os = "macos") { | ||
| println!("cargo:rustc-link-arg=-pagezero_size 0x100000"); | ||
| } | ||
|
Comment on lines
-61
to
-65
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is no longer necessary with |
||
| let include_paths = get_include_paths(&libquil_header_path); | ||
|
|
||
| // The bindgen::Builder is the main entry point | ||
| // to bindgen, and lets you build up options for | ||
|
|
@@ -71,6 +125,23 @@ fn main() -> Result<(), Error> { | |
| // The input header we would like to generate | ||
| // bindings for. | ||
| .header(libquil_header_path.to_string_lossy()) | ||
| // ...and the runtime's header, which declares the error API that libquil's | ||
| // functions report through. | ||
| .header( | ||
| include_paths | ||
| .iter() | ||
| .map(|dir| dir.join("sbcl_librarian.h")) | ||
| .find(|path| path.exists()) | ||
| .ok_or_else(|| { | ||
| Error::RuntimeHeaderNotFound(libquil_header_path.display().to_string()) | ||
| })? | ||
| .to_string_lossy(), | ||
| ) | ||
| .clang_args( | ||
| include_paths | ||
| .iter() | ||
| .map(|dir| format!("-I{}", dir.display())), | ||
| ) | ||
| // Tell cargo to invalidate the built crate whenever any of the | ||
| // included header files changed. | ||
| .parse_callbacks(Box::new(bindgen::CargoCallbacks)) | ||
|
|
||
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.