From 49e76fe29b6d3e4cf4d0578df17fda5b54f38036 Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Wed, 18 Mar 2026 17:09:33 -0400 Subject: [PATCH 1/5] Makefile: Rename VERSION to QRMI_VERSION Rename it to avoid confusion. We will also have PYTHON_VERSION. Signed-off-by: Claudio Carvalho --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index aad8040..856a9b9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # (C) Copyright IBM Corporation 2026 -VERSION := $$($(MAKE) get-qrmi-version) +QRMI_VERSION := $$($(MAKE) get-qrmi-version) DIST_DIR ?= . include Makefile_helpers.mk @@ -24,19 +24,19 @@ build: # Allow disconnected/airgapped builds tarball-vendor: cargo vendor $(DIST_DIR)/vendor - @tar czf $(DIST_DIR)/qrmi-$(VERSION)-vendor.tar.gz vendor/ + @tar czf $(DIST_DIR)/qrmi-$(QRMI_VERSION)-vendor.tar.gz vendor/ @rm -rf $(DIST_DIR)/vendor @echo - @echo "Created: $(DIST_DIR)/qrmi-$(VERSION)-vendor.tar.gz" + @echo "Created: $(DIST_DIR)/qrmi-$(QRMI_VERSION)-vendor.tar.gz" dist-rhel-lib: build - TARBALL="$(DIST_DIR)/libqrmi-$(VERSION)-el8-x86_64.tar.gz"; \ - WORKDIR="$(DIST_DIR)/libqrmi-$(VERSION)"; \ + TARBALL="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)-el8-x86_64.tar.gz"; \ + WORKDIR="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)"; \ mkdir -p $$WORKDIR; \ cp target/release/libqrmi.so $$WORKDIR; \ cp qrmi.h $$WORKDIR; \ cp LICENSE.txt $$WORKDIR; \ - tar czf $$TARBALL -C $(DIST_DIR) libqrmi-$(VERSION); \ + tar czf $$TARBALL -C $(DIST_DIR) libqrmi-$(QRMI_VERSION); \ rm -rf $$WORKDIR; \ echo "Created: $$TARBALL" From 5ddaeeffe4c289577005f49e915fa9df327bce5e Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Wed, 18 Mar 2026 17:11:27 -0400 Subject: [PATCH 2/5] Rename Makefile_helpers.mk to Makefile_common.mk No functional change. Later we will use it for shared variables and targets. Signed-off-by: Claudio Carvalho --- Makefile | 2 +- Makefile_helpers.mk => Makefile_common.mk | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Makefile_helpers.mk => Makefile_common.mk (100%) diff --git a/Makefile b/Makefile index 856a9b9..3dac5ec 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ QRMI_VERSION := $$($(MAKE) get-qrmi-version) DIST_DIR ?= . -include Makefile_helpers.mk +include Makefile_common.mk .PHONY: all build dist dist-rhel-lib clean help diff --git a/Makefile_helpers.mk b/Makefile_common.mk similarity index 100% rename from Makefile_helpers.mk rename to Makefile_common.mk From 75df00939e3f80ba761aa905f3424401fd9526da Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Wed, 18 Mar 2026 17:20:32 -0400 Subject: [PATCH 3/5] Makefile: Avoid recursive make call in QRMI_VERSION One of the best practices in Makefile is to avoid recursive $(MAKE) calls as they can break the dependency tracking, preventing the top-level make from seeing the full, global dependency picture. This patch moves the QRMI_VERSION to Makefile_common.mk to ensure it is always defined. This also wraps the Makefile_common.mk with ifndef to prevent it from being included multiple times. Signed-off-by: Claudio Carvalho --- Makefile | 5 ++--- Makefile_common.mk | 10 +++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 3dac5ec..0a701ad 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 # (C) Copyright IBM Corporation 2026 -QRMI_VERSION := $$($(MAKE) get-qrmi-version) DIST_DIR ?= . -include Makefile_common.mk - .PHONY: all build dist dist-rhel-lib clean help all: build +include Makefile_common.mk + # ------------------------------------------------ # Rust targets # ------------------------------------------------ diff --git a/Makefile_common.mk b/Makefile_common.mk index 4f0f341..981260f 100644 --- a/Makefile_common.mk +++ b/Makefile_common.mk @@ -1,13 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 # (C) Copyright IBM Corporation 2026 +ifndef MAKEFILE_COMMON_MK_INCLUDED + .PHONY: get-qrmi-version check-new-qrmi-version-valid +# Get QRMI version from Cargo.toml +QRMI_VERSION := $(shell grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/') + MAKEFLAGS += --no-print-directory # Single source of truth to get the qrmi version. get-qrmi-version: - @grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/' + @echo "$(QRMI_VERSION)" # Before releasing a new qrmi version, we check if the current version was not released yet check-new-qrmi-version-valid: @@ -26,3 +31,6 @@ check-new-qrmi-version-valid: exit 1; \ fi; \ echo "New QRMI version v$${NEW_QRMI_VERSION} is valid" + +MAKEFILE_COMMON_MK_INCLUDED := true +endif \ No newline at end of file From 2fafd2f71402ce7bfbd7d3c2cf774ce5421216ba Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Fri, 20 Mar 2026 10:34:27 -0400 Subject: [PATCH 4/5] CI: Rename libqrmi-tarball-rhel.yml to tarball-libqrmi-el8.yml No functional change. Just making sure the filename is consistent with tarball-vendor.yml. Signed-off-by: Claudio Carvalho --- .github/workflows/release.yml | 2 +- .../{libqrmi-tarball-rhel.yml => tarball-libqrmi-el8.yml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{libqrmi-tarball-rhel.yml => tarball-libqrmi-el8.yml} (100%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2710a1..3a8a8ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,7 +47,7 @@ jobs: create-libqrmi-tarball-rhel: if: github.repository_owner == 'qiskit-community' name: Create libqrmi tarball for RHEL compatible distributions - uses: ./.github/workflows/libqrmi-tarball-rhel.yml + uses: ./.github/workflows/tarball-libqrmi-el8.yml create-draft-release: if: github.repository_owner == 'qiskit-community' diff --git a/.github/workflows/libqrmi-tarball-rhel.yml b/.github/workflows/tarball-libqrmi-el8.yml similarity index 100% rename from .github/workflows/libqrmi-tarball-rhel.yml rename to .github/workflows/tarball-libqrmi-el8.yml From d8385dfdba5c1b77981daed43ff433b4da0f8142 Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Fri, 20 Mar 2026 17:34:16 -0400 Subject: [PATCH 5/5] Makefile: Add targets to cover the CI and INSTALL.md Add all makefile targets needed to cover the steps found in the CI and in the INSTALL.md. With that, users can easily reproduce the same commands we use in the CI. The command below describes all targets available $ make help Fixes: #81 Signed-off-by: Claudio Carvalho --- .gitignore | 4 + Makefile | 316 ++++++++++++++++++++++++++++++++++++++++----- Makefile_common.mk | 33 ++++- 3 files changed, 319 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index 970a145..e6d8e73 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ qrmi.h # python venvs *venv +.venv* # Byte-compiled / optimized / DLL files __pycache__/ @@ -59,6 +60,9 @@ __pycache__/ # C extensions *.so +# Documentation +html/ + # Distribution / packaging .Python build/ diff --git a/Makefile b/Makefile index 0a701ad..838d668 100644 --- a/Makefile +++ b/Makefile @@ -3,24 +3,211 @@ DIST_DIR ?= . -.PHONY: all build dist dist-rhel-lib clean help - -all: build +.PHONY: _build +_build: build include Makefile_common.mk # ------------------------------------------------ -# Rust targets +# Build targets # ------------------------------------------------ +.PHONY: build build-rust-examples build-task-runner build-stubgen +.PHONY: build-c-examples build-pypkg build-rust-all build-all + build: - cargo build --locked --release + cargo build --locked --release --lib + +build-rust-examples: + cargo build --locked --release --examples + +build-task-runner: + cargo build --locked --release --bin task_runner --features="build-binary" + +build-stubgen: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + cargo build --locked --release --bin stubgen --features="pyo3" + +build-c-examples: build + @mkdir -p examples/qrmi/c/direct_access/build + @cd examples/qrmi/c/direct_access/build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + cmake --build . + @mkdir -p examples/qrmi/c/qiskit_runtime_service/build + @cd examples/qrmi/c/qiskit_runtime_service/build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + cmake --build . + @mkdir -p examples/qrmi/c/pasqal_cloud/build + @cd examples/qrmi/c/pasqal_cloud/build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + cmake --build . + @mkdir -p examples/qrmi/c/config/build + @cd examples/qrmi/c/config/build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. && \ + cmake --build . + +build-pypkg: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + maturin build --locked --release + +build-rust-all: build build-rust-examples build-task-runner build-stubgen + +build-all: build-rust-all build-c-examples build-pypkg + +# ------------------------------------------------ +# Linting targets +# ------------------------------------------------ + +.PHONY: lint lint-rust-examples lint-task-runner lint-stubgen +.PHONY: lint-pypkg lint-rust-all lint-all + +lint: + cargo clippy --locked --release --lib -- -D warnings + +lint-rust-examples: + cargo clippy --locked --release --examples -- -D warnings + +lint-task-runner: + cargo clippy --locked --release --bin task_runner --features="build-binary" -- -D warnings + +lint-stubgen: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + cargo clippy --locked --release --bin stubgen --features="pyo3" -- -D warnings + +lint-pypkg: check-venv-exists install-pypkg + @source $(PYTHON_VENV_ACTIVATE) && \ + pylint ./python + +lint-rust-all: lint-with-examples lint-task-runner lint-stubgen + +lint-all: lint-rust-all lint-pypkg + +# ------------------------------------------------ +# Unit test targets +# ------------------------------------------------ + +.PHONY: test test-doc test-deps test-rust-examples test-task-runner +.PHONY: test-stubgen test-pypkg test-rust-all test-all + +test: + cargo test --lib --locked --release + +test-doc: + cargo test --doc --locked --release + +test-deps: + cargo test --locked --release -p direct-access-api + cargo test --locked --release -p pasqal-cloud-api + cargo test --locked --release -p qiskit_runtime_client + +test-rust-examples: + cargo test --examples --locked --release + +test-task-runner: + cargo test --locked --release --bin task_runner --features="build-binary" + +test-stubgen: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + cargo test --locked --release --bin stubgen --features="pyo3" + +test-pypkg: check-venv-exists install-pypkg + @source $(PYTHON_VENV_ACTIVATE) && \ + pytest python/tests/ + +test-rust-all: test test-rust-examples test-rust-doc test-task-runner test-stubgen + +test-all: test-rust-all test-pypkg + +# ------------------------------------------------ +# Format check targets +# ------------------------------------------------ + +.PHONY: fmt fmt-rust fmt-pypkg fmt-all + +fmt: fmt-rust + +fmt-rust: + cargo fmt --all -- --check --verbose + +fmt-pypkg: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + black --check ./python + +fmt-all: fmt-rust fmt-pypkg + +# ------------------------------------------------ +# Setup targets +# ------------------------------------------------ + +.PHONY: create-env install-pypkg + +create-venv: check-python-version-installed + @if [ -d $(PYTHON_VENV_DIR) ]; then \ + echo "Error: $(PYTHON_VENV_DIR) already exists. Remove it first or just skip this step."; \ + exit 1; \ + fi; \ + python$(PYTHON_VERSION) -m venv $(PYTHON_VENV_DIR) && \ + source $(PYTHON_VENV_ACTIVATE) && \ + pip install --upgrade pip && \ + pip install -r requirements-dev.txt && \ + echo && \ + echo "*** Virtual environment created ***" && \ + echo && \ + echo "The makefile targets will activate the venv automatically, but if you want" && \ + echo "you can manually activate it with: source $(PYTHON_VENV_DIR)/bin/activate" && \ + echo + +install-pypkg: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + maturin develop --locked --release + +# ------------------------------------------------ +# Clean targets +# ------------------------------------------------ + +.PHONY: clean clean-c-examples clean-tarballs + +clean: + cargo clean + @rm -f qrmi.h + +clean-c-examples: + @rm -rf examples/qrmi/c/direct_access/build + @rm -rf examples/qrmi/c/qiskit_runtime_service/build + @rm -rf examples/qrmi/c/pasqal_cloud/build + @rm -rf examples/qrmi/c/config/build + +clean-tarballs: + rm -f $(DIST_DIR)/libqrmi-$(QRMI_VERSION)-el8-x86_64.tar.gz + rm -f $(DIST_DIR)/qrmi-$(QRMI_VERSION)-vendor.tar.gz + +clean-docs: + rm -rf $(DIST_DIR)/html + +# ------------------------------------------------ +# Documentation targets +# ------------------------------------------------ + +.PHONY: doc doc-pypkg doc-c + +doc: + cargo doc --no-deps --open + +doc-pypkg: check-venv-exists + @source $(PYTHON_VENV_ACTIVATE) && \ + python -m pydoc -b + +doc-c: check-doxygen-installed + @doxygen Doxyfile + @echo + @echo "Open the file $(DIST_DIR)/html/index.html" # ------------------------------------------------ # Packaging targets # ------------------------------------------------ -# Allow disconnected/airgapped builds +.PHONY: tarball-vendor tarball-libqrmi-el8 clean-tarballs + tarball-vendor: cargo vendor $(DIST_DIR)/vendor @tar czf $(DIST_DIR)/qrmi-$(QRMI_VERSION)-vendor.tar.gz vendor/ @@ -28,37 +215,100 @@ tarball-vendor: @echo @echo "Created: $(DIST_DIR)/qrmi-$(QRMI_VERSION)-vendor.tar.gz" -dist-rhel-lib: build - TARBALL="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)-el8-x86_64.tar.gz"; \ - WORKDIR="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)"; \ - mkdir -p $$WORKDIR; \ - cp target/release/libqrmi.so $$WORKDIR; \ - cp qrmi.h $$WORKDIR; \ - cp LICENSE.txt $$WORKDIR; \ - tar czf $$TARBALL -C $(DIST_DIR) libqrmi-$(QRMI_VERSION); \ - rm -rf $$WORKDIR; \ +tarball-libqrmi-el8: build + @TARBALL="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)-el8-x86_64.tar.gz" && \ + WORKDIR="$(DIST_DIR)/libqrmi-$(QRMI_VERSION)" && \ + mkdir -p $$WORKDIR && \ + cp target/release/libqrmi.so $$WORKDIR && \ + cp qrmi.h $$WORKDIR && \ + cp LICENSE.txt $$WORKDIR && \ + tar czf $$TARBALL -C $(DIST_DIR) libqrmi-$(QRMI_VERSION) && \ + rm -rf $$WORKDIR && \ echo "Created: $$TARBALL" # ------------------------------------------------ -# Misc targets +# Other targets # ------------------------------------------------ -clean: - cargo clean +define HELP_TEXT +Usage: make + +Build targets: + build - Build libqrmi (default target) + build-rust-examples - Build rust examples + build-c-examples - Build C examples + build-task-runner - Build task_runner binary + build-stubgen - Build stubgen binary. Requires: create-venv + build-pypkg - Build qrmi python package. Requires: create-venv + build-rust-all - Build libqrmi, rust examples and binaries + build-all - Build everything! + +Linting targets: + lint - Lint libqrmi + lint-rust-examples - Lint rust examples + lint-task-runner - Lint task_runner binary + lint-stubgen - Lint stubgen binary. (Requires: create-venv) + lint-pypkg - Lint qrmi python package installed in the venv. (Requires: create-venv) + The qrmi python package will be built and installed if necessary + lint-rust-all - Lint libqrmi, rust examples and binaries + lint-all - Lint everything! + +Unit test targets: + test - Test libqrmi + test-deps - Test libqrmi dependencies + test-doc - Test libqrmi doctests + test-rust-examples - Test rust examples + test-task-runner - Test task_runner binary + test-stubgen - Test stubgen binary. (Requires: create-venv) + test-pypkg - Test the qrmi python package installed in the venv. (Requires: create-venv) + The qrmi python package will be built and installed if necessary + test-rust-all - Test libqrmi, doctests, rust examples and binaries + test-all - Test everything! + +Format check targets: + fmt - Same as "fmt-rust" + fmt-rust - Format check libqrmi, dependencies, examples and binaries + fmt-pypkg - Format check the ./python directory. (Requires: create-venv) + fmt-all - Format check everything! + +Clean targets: + clean - Remove ./target directory and qrmi.h + clean-c-examples - Remove C examples build directories + clean-tarballs - Remove tarballs generated + clean-all - Remove all artifacts built + +Documentation targets: + doc - Generate rust API documentation and open it in a browser + doc-pypkg - Generate python API documentation and open it in a browser. (Requires: create-venv) + doc-c - Generate C API documentation + +Setup targets: + create-venv - Create python virtual environment for QRMI using the python version + defined in PYTHON_VERSION (default: "3.12"). + Once created, the makefile target will activate the venv automatically. + install-pypkg - Build (if needed) and install the qrmi python package + +Packaging targets: + tarball-libqrmi-el8 - Create versioned libqrmi tarball with libqrmi.so and qrmi.h + for RHEL8 compatible distributions + tarball-vendor - Create versioned vendor tarball in DIST_DIR (default: ./). + It can be used to build the qrmi version locally without + relying on the vendor crates to be available upstream. + +Other targets: + check-new-qrmi-version-valid - Check if the qrmi version returned by "get-qrmi-version" + has already been released in github. + check-python-version-installed - Check if the RHEL 8 required python packages are installed + check-venv-exists - Check if the venv for PYTHON_VERSION (default: "3.12") has already been created + get-qrmi-version - Read the qrmi version from Cargo.toml and print it + help - Show this help message + +endef +export HELP_TEXT + +.PHONY: clean-all help + +clean-all: clean clean-c-examples clean-tarballs help: - @echo "Rust targets:" - @echo - @echo " all - same as \"make build\" (default)" - @echo " build - Build libqrmi" - @echo - @echo "Packaging targets:" - @echo - @echo " tarball-vendor - Create vendor tarball in DIST_DIR (default: ./)" - @echo " dist-rhel-lib - Create libqrmi tarball with libqrmi.so and qrmi.h" - @echo - @echo "Misc targets:" - @echo - @echo " clean - Remove build artifacts" - @echo " help - Show this help message" - \ No newline at end of file + @echo "$$HELP_TEXT" diff --git a/Makefile_common.mk b/Makefile_common.mk index 981260f..d6026e5 100644 --- a/Makefile_common.mk +++ b/Makefile_common.mk @@ -3,10 +3,16 @@ ifndef MAKEFILE_COMMON_MK_INCLUDED -.PHONY: get-qrmi-version check-new-qrmi-version-valid +.PHONY: get-qrmi-version check-new-qrmi-version-valid check-python-version-installed check-venv-exists # Get QRMI version from Cargo.toml QRMI_VERSION := $(shell grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/') +# Python version to be used +PYTHON_VERSION ?= 3.12 + +PYTHON_VENV_SUFFIX = $(shell echo "py$(PYTHON_VERSION)" | sed 's/\.//') +PYTHON_VENV_DIR = ".venv_$(PYTHON_VENV_SUFFIX)" +PYTHON_VENV_ACTIVATE = $(PYTHON_VENV_DIR)/bin/activate MAKEFLAGS += --no-print-directory @@ -32,5 +38,30 @@ check-new-qrmi-version-valid: fi; \ echo "New QRMI version v$${NEW_QRMI_VERSION} is valid" +check-python-version-installed: + @if ! command -v python$(PYTHON_VERSION) >/dev/null 2>&1 ; then \ + echo "Error: python$(PYTHON_VERSION) not found"; \ + echo "Please install the package python$(PYTHON_VERSION)"; \ + exit 1; \ + fi; \ + if ! command -v python$(PYTHON_VERSION)-config >/dev/null 2>&1 ; then \ + echo "Error: python$(PYTHON_VERSION) library and headers not found"; \ + echo "Please install the package python$(PYTHON_VERSION)-devel"; \ + exit 1; \ + fi + +check-doxygen-installed: + @if ! command -v doxygen >/dev/null 2>&1 ; then \ + echo "Error: doxygen not found"; \ + echo "Please install the package doxygen"; \ + exit 1; \ + fi + +check-venv-exists: check-python-version-installed + @if [ ! -d "$(PYTHON_VENV_DIR)" ]; then \ + echo "Error: $(PYTHON_VENV_DIR) not found. Run: make create-venv"; \ + exit 1; \ + fi + MAKEFILE_COMMON_MK_INCLUDED := true endif \ No newline at end of file