Skip to content

Commit 777a4f0

Browse files
authored
chore: Rename tket-c-api and add static linking (#953)
After a lot more trials, I have concluded that we should support both static and dynamic linking of `tket1-passes` (which I am renaming to `tket-c-api`, see below). Shared VS static `tket-c-api` library. ### Static linking For users, static linking is much simpler: dynamic linking leads to problems at runtime, when the dynamic linker cannot find the `tket-c-api` library unless it is installed system-wide. [There is no way to tell cargo](rust-lang/cargo#9016) to set the rpath accordingly on every binary it builds, and so the users would have to point the linker to the right library with an environment variable whenever using `cargo` (or some `.cargo/config.toml` setting). However, static linking is only feasible through a dependency management tool such as conan. This is because when linking statically, all recursive dependencies have to be linked in (tket, symengine, boost, etc.). Doing this manually is a nightmare. So conan is a must, but is terrible for CI speeds: just installing `conan` and fetching the cache takes ~30 seconds :/ ### Dynamic linking With dynamic linking, on the other hand, it suffices to build against `tket-c-api`; no recursive dependencies are required. This can be cached in CI, and the `LD_LIBRARY_PATH` can be set so that the library can be found at runtime. ## Solution `tket-c-api` will by default be built using `conan` and linked in statically. Conan can be called directly from `cargo`, and so no separate build step other than `cargo build` should be necessary (provided `conan` has been installed). I have renamed the special purpose `tket1-passes` library into `tket-c-api`. I suggest the latter should be integrated into `tket1` and compiled libraries could be published to our JFrog artifactory, for faster local builds. Until this is done, a separate `cd tket1-passes/tket-c-api && conan create .` step will be required. If the user (mostly: CI) sets the `TKET_C_API_PATH`, this folder will be used instead to locate the `tket-c-api` library, bypassing conan altogether. This should be a shared library, otherwise dependencies will be missing at link time. It is then the user's responsibility to ensure that the library can be loaded at runtime (by setting `LD_LIBRARY_PATH` or equivalent)
1 parent 1bb86fa commit 777a4f0

File tree

27 files changed

+1010
-876
lines changed

27 files changed

+1010
-876
lines changed

.github/actions/tket-c-api/action.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: "Install tket-c-api C++ library"
2+
description: "Retrieve cached tket-c-api C++ library or build if needed"
3+
4+
inputs:
5+
install-path:
6+
description: "Path where the tket-c-api library will be installed"
7+
required: true
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Attempt to retrieve cached tket-c-api
13+
uses: actions/cache/restore@v4
14+
id: cache
15+
with:
16+
path: ${{ inputs.install-path }}
17+
key: ${{ runner.os }}-${{ hashFiles('tket1-passes/tket-c-api/**') }}
18+
19+
- name: Install conan
20+
if: steps.cache.outputs.cache-hit != 'true'
21+
uses: conan-io/setup-conan@v1
22+
with:
23+
cache_packages: true
24+
25+
- name: Set up conan remote
26+
if: steps.cache.outputs.cache-hit != 'true'
27+
shell: bash
28+
run: |
29+
conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0
30+
31+
- name: Build and install tket-c-api
32+
if: steps.cache.outputs.cache-hit != 'true'
33+
shell: bash
34+
run: |
35+
cd tket1-passes/tket-c-api
36+
PACKAGE_NAME="tket-c-api/$(conan inspect . --format=json | jq -r '.version')"
37+
CONAN_OUTPUT=$(conan create . --build=missing --options="$PACKAGE_NAME:shared=True" --format=json)
38+
CONAN_LIB_FOLDER=$(echo "$CONAN_OUTPUT" | jq -r ".graph.nodes.\"1\".package_folder")
39+
cp -r $CONAN_LIB_FOLDER ${{ inputs.install-path }}
40+
41+
- name: Upload compiled library to cache
42+
if: steps.cache.outputs.cache-hit != 'true'
43+
uses: actions/cache/save@v4
44+
with:
45+
path: ${{ inputs.install-path }}
46+
key: ${{ steps.cache.outputs.cache-primary-key }}

.github/actions/tket1-passes/action.yml

Lines changed: 0 additions & 46 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ env:
2929
LLVM_VERSION: "14.0"
3030
LLVM_FEATURE_NAME: "14-0"
3131

32+
TKET_C_API_PATH: "${{ github.workspace }}/tket-c-api"
33+
LD_LIBRARY_PATH: ${{ github.workspace }}/tket-c-api/lib
34+
3235
jobs:
3336
# Check if changes were made to the relevant files.
3437
# Always returns true if running on the default branch, to ensure all changes are thoroughly checked.
@@ -75,8 +78,10 @@ jobs:
7578
uses: dtolnay/rust-toolchain@stable
7679
with:
7780
components: rustfmt, clippy
78-
- name: Retrieve tket1-passes library
79-
uses: ./.github/actions/tket1-passes
81+
- name: Install tket-c-api library
82+
uses: ./.github/actions/tket-c-api
83+
with:
84+
install-path: ${{ env.TKET_C_API_PATH }}
8085
- name: Check formatting
8186
run: cargo fmt -- --check
8287
- name: Install LLVM and Clang
@@ -178,8 +183,10 @@ jobs:
178183
uses: KyleMayes/install-llvm-action@v2
179184
with:
180185
version: ${{ env.LLVM_VERSION }}
181-
- name: Retrieve tket1-passes library
182-
uses: ./.github/actions/tket1-passes
186+
- name: Install tket-c-api library
187+
uses: ./.github/actions/tket-c-api
188+
with:
189+
install-path: ${{ env.TKET_C_API_PATH }}
183190
- name: Build with all features
184191
run: cargo test --verbose --workspace --all-features --no-run
185192
- name: Tests with all features
@@ -208,8 +215,10 @@ jobs:
208215
uses: KyleMayes/install-llvm-action@v2
209216
with:
210217
version: ${{ env.LLVM_VERSION }}
211-
- name: Retrieve tket1-passes library
212-
uses: ./.github/actions/tket1-passes
218+
- name: Install tket-c-api library
219+
uses: ./.github/actions/tket-c-api
220+
with:
221+
install-path: ${{ env.TKET_C_API_PATH }}
213222
- name: Configure default rust toolchain
214223
run: rustup override set ${{steps.toolchain.outputs.name}}
215224
- name: Build with no features
@@ -240,8 +249,10 @@ jobs:
240249
uses: KyleMayes/install-llvm-action@v2
241250
with:
242251
version: ${{ env.LLVM_VERSION }}
243-
- name: Retrieve tket1-passes library
244-
uses: ./.github/actions/tket1-passes
252+
- name: Install tket-c-api library
253+
uses: ./.github/actions/tket-c-api
254+
with:
255+
install-path: ${{ env.TKET_C_API_PATH }}
245256
- name: Install cargo-llvm-cov
246257
uses: taiki-e/install-action@cargo-llvm-cov
247258
- name: Run tests with coverage instrumentation

.github/workflows/semver-checks.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,22 @@ jobs:
4343
needs: [changes]
4444
if: ${{ needs.changes.outputs.rust == 'true' }}
4545
runs-on: ubuntu-latest
46+
env:
47+
TKET_C_API_PATH: ${{ github.workspace }}/tket-c-api
48+
LD_LIBRARY_PATH: ${{ github.workspace }}/tket-c-api/lib
4649
steps:
4750
- name: Checkout tket2
4851
uses: actions/checkout@v4
49-
- name: Retrieve tket1-passes library
50-
uses: ./.github/actions/tket1-passes
52+
- name: Install tket-c-api library
53+
uses: ./.github/actions/tket-c-api
5154
with:
52-
lib-path: ${{ github.workspace }}/tket1-lib
55+
install-path: ${{ env.TKET_C_API_PATH }}
5356
- name: Install LLVM from apt
5457
run: |
5558
echo "Installing apt dependencies: llvm-14"
5659
sudo apt-get install -y llvm-14
5760
- uses: CQCL/hugrverse-actions/rs-semver-checks@main
5861
env:
59-
TKET_LIB_PATH: ${{ github.workspace }}/tket1-lib
62+
TKET_C_API_PATH: ${{ env.TKET_C_API_PATH }}
6063
with:
6164
token: ${{ secrets.HUGRBOT_PAT }}

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
"compile-rewriter",
1010
"badger-optimiser",
1111
"tket2-hseries",
12-
"tket1-passes/rust",
12+
"tket1-passes",
1313
]
1414
default-members = ["tket2", "tket2-hseries"]
1515

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dev-dependencies = [
1212
"hypothesis >=6.111.1,<7",
1313
"graphviz >=0.20,<0.21",
1414
"pre-commit >=3.8.0,<4",
15+
"conan >= 2.0.0,<3",
1516
# Required to run `maturin develop`
1617
"pip >=24",
1718
]
@@ -35,6 +36,7 @@ exclude = '''(?x)(
3536
^target/ # Build artifacts
3637
| ^notebooks/ # Examples
3738
| ^test_files/ # Test files
39+
| ^tket1-passes/tket-c-api/ # Do not check conan files
3840
)'''
3941

4042
# TODO: Fix the lint errors and enable this

tket1-passes/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
lib
1+
lib

tket1-passes/rust/Cargo.toml renamed to tket1-passes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ tket-json-rs.workspace = true
2121
[build-dependencies]
2222
cc = "1.2"
2323
bindgen = "0.72"
24+
conan2 = "0.1.7"
2425

2526
[dev-dependencies]
2627
rstest.workspace = true

tket1-passes/README.md

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,31 @@
11
# TKET1-Passes
22

3-
A bridge between C++ TKET1 and Rust land. The folder `cpp` provides a minimal
4-
C-interface to a subset of TKET1's functionality. The folder `rust` then wraps
5-
this interface into a Rust-friendly API.
3+
A bridge between C++ TKET1 and Rust land. The folder `tket-c-api`
4+
provides a minimal C-interface to a subset of TKET1's functionality. The
5+
crate in this directory then wraps this interface into a Rust-friendly
6+
API.
67

7-
## Building the C++ library
8+
## Building instructions
89

9-
This requires standard modern C++ tooling:
10-
11-
- Conan 2.0+
12-
- CMake 3.23+
13-
- C++20 compiler
14-
15-
as well as the GMP (GNU Multiple Precision Arithmetic Library). This is usually
16-
already installed on Linux; on macos you can use `brew install gmp`. You must
17-
further set up `conan` to use the artifactory containing the tket package:
10+
Building `tket1-passes` is done using `conan >= 2.0`. After installing `conan`,
11+
(`pip install conan` or use `pipx`), you must set up `conan` to use the
12+
artifactory containing the tket package:
1813

1914
```
2015
conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0
2116
```
2217

23-
Finally, if you have not used `conan` before, you will need to set up a profile:
18+
For the time being, one extra step is required to export `tket-c-api` to the conan cache:
2419

2520
```
26-
conan profile detect
27-
```
28-
29-
Building the `tket1-passes` library is then as simple as running the following script:
30-
31-
```bash
32-
cd cpp
33-
./build.sh
21+
cd tket-c-api && conan create . --build=missing"
3422
```
3523

36-
Upon successfully building the C++ library, the compiled library should be found
37-
in the `lib` directory. The location the library is installed to can be changed
38-
by setting the `TKET_LIB_PATH` environment variable.
39-
40-
## Building the Rust library
41-
42-
The Rust library can then be built using:
43-
44-
```bash
45-
cd rust
46-
cargo build
47-
```
24+
That's it! You can now build the library using `cargo build`.
4825

49-
If you are using a non-default library path, make sure to set the `TKET_LIB_PATH`
50-
environment variable accordingly.
26+
If conan is unable to fetch all dependencies as pre-compiled binaries, you will
27+
also need standard C++ tooling to compile the dependencies (i.e. a reasonably
28+
recent version of cmake and a C++ compiler).
5129

5230
## Currently supported TKET1 features
5331

0 commit comments

Comments
 (0)