Skip to content

Commit 1d139f4

Browse files
authored
Merge pull request #1 from OpenMS/feat/cmake-packaging-ci-release
Add CMake packaging and CI/release pipeline
2 parents 8b3dc62 + 955b593 commit 1d139f4

4 files changed

Lines changed: 309 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: CI & Release
2+
3+
on:
4+
push:
5+
branches: [master]
6+
tags: ['v*']
7+
pull_request:
8+
branches: [master]
9+
10+
jobs:
11+
build:
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- os: ubuntu-24.04
17+
target: x86_64-unknown-linux-gnu
18+
platform: linux-x86_64
19+
archive_ext: tar.gz
20+
21+
- os: ubuntu-24.04-arm
22+
target: aarch64-unknown-linux-gnu
23+
platform: linux-aarch64
24+
archive_ext: tar.gz
25+
26+
- os: macos-14
27+
target: aarch64-apple-darwin
28+
platform: macos-arm64
29+
archive_ext: tar.gz
30+
31+
- os: windows-2025
32+
target: x86_64-pc-windows-msvc
33+
platform: windows-x86_64
34+
archive_ext: zip
35+
36+
runs-on: ${{ matrix.os }}
37+
38+
# Must match OpenMS's MACOSX_DEPLOYMENT_TARGET (see pyOpenMS pyproject.toml
39+
# and openms_ci_matrix_full.yml) to avoid deployment target mismatch warnings
40+
# when linking the static library into OpenMS/pyOpenMS.
41+
env:
42+
MACOSX_DEPLOYMENT_TARGET: ${{ startsWith(matrix.os, 'macos') && '14.0' || '' }}
43+
44+
steps:
45+
# actions/checkout v6.0.2
46+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
47+
48+
- name: Install Rust toolchain
49+
# dtolnay/rust-toolchain stable branch
50+
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7
51+
with:
52+
toolchain: stable
53+
54+
- name: Cache Cargo
55+
# Swatinem/rust-cache v2.8.2
56+
uses: Swatinem/rust-cache@401aff9a7a08acb9d27b64936a90db81024cff97
57+
58+
- name: Run tests
59+
run: cargo test --features with_timsrust
60+
61+
- name: Build release
62+
run: cargo build --features with_timsrust --release
63+
64+
- name: Smoke test (Linux)
65+
if: runner.os == 'Linux'
66+
shell: bash
67+
run: |
68+
g++ -std=c++17 examples/cpp_client.cpp \
69+
-Iinclude \
70+
target/release/libtimsrust_cpp_bridge.a \
71+
-lpthread -ldl -lm \
72+
-o target/smoke_test
73+
# Run with no args — expect exit code 1 (usage), fail only on signal/crash
74+
target/smoke_test || if [ $? -gt 128 ]; then exit 1; fi
75+
76+
- name: Smoke test (macOS)
77+
if: runner.os == 'macOS'
78+
shell: bash
79+
run: |
80+
clang++ -std=c++17 examples/cpp_client.cpp \
81+
-Iinclude \
82+
target/release/libtimsrust_cpp_bridge.a \
83+
-framework Security -framework SystemConfiguration -framework CoreFoundation \
84+
-lresolv -lpthread \
85+
-o target/smoke_test
86+
# Run with no args — expect exit code 1 (usage), fail only on signal/crash
87+
target/smoke_test || if [ $? -gt 128 ]; then exit 1; fi
88+
89+
- name: Setup MSVC dev environment
90+
if: runner.os == 'Windows'
91+
# ilammy/msvc-dev-cmd v1.13.0
92+
uses: ilammy/msvc-dev-cmd@a102174a2b586eec2ea151a69e6fd14404a8ce7c
93+
94+
- name: Smoke test (Windows)
95+
if: runner.os == 'Windows'
96+
shell: cmd
97+
run: |
98+
cl.exe /std:c++17 /EHsc /MD /Fe:target\smoke_test.exe /I include examples\cpp_client.cpp target\release\timsrust_cpp_bridge.lib ws2_32.lib userenv.lib bcrypt.lib ntdll.lib advapi32.lib
99+
target\smoke_test.exe
100+
if %errorlevel% GEQ 2 exit /b %errorlevel%
101+
exit /b 0
102+
103+
- name: Set version
104+
id: version
105+
shell: bash
106+
run: |
107+
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
108+
echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
109+
else
110+
echo "version=0.0.0-dev" >> "$GITHUB_OUTPUT"
111+
fi
112+
113+
- name: Package
114+
shell: bash
115+
run: bash scripts/package.sh "${{ steps.version.outputs.version }}" "${{ matrix.target }}"
116+
117+
- name: Validate CMake package
118+
shell: bash
119+
run: |
120+
ARCHIVE_DIR="target/package/timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}/timsrust_cpp_bridge"
121+
mkdir -p /tmp/timsrust_cmake_test
122+
cat > /tmp/timsrust_cmake_test/CMakeLists.txt << 'CMAKEOF'
123+
cmake_minimum_required(VERSION 3.11)
124+
project(test_consumer CXX)
125+
set(CMAKE_CXX_STANDARD 17)
126+
find_package(timsrust_cpp_bridge REQUIRED)
127+
add_executable(test_consumer test.cpp)
128+
target_link_libraries(test_consumer timsrust_cpp_bridge::timsrust_cpp_bridge)
129+
CMAKEOF
130+
cat > /tmp/timsrust_cmake_test/test.cpp << 'CPPEOF'
131+
#include "timsrust_cpp_bridge.h"
132+
int main() { return 0; }
133+
CPPEOF
134+
cmake -S /tmp/timsrust_cmake_test -B /tmp/timsrust_cmake_test/build \
135+
-DCMAKE_PREFIX_PATH="$(pwd)/${ARCHIVE_DIR}"
136+
cmake --build /tmp/timsrust_cmake_test/build
137+
rm -rf /tmp/timsrust_cmake_test
138+
139+
- name: Upload artifact
140+
if: startsWith(github.ref, 'refs/tags/v')
141+
# actions/upload-artifact v7.0.0
142+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
143+
with:
144+
name: timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}
145+
path: target/package/timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}.${{ matrix.archive_ext }}
146+
147+
release:
148+
if: startsWith(github.ref, 'refs/tags/v')
149+
needs: build
150+
runs-on: ubuntu-latest
151+
permissions:
152+
contents: write
153+
154+
steps:
155+
- name: Download all artifacts
156+
# actions/download-artifact v8.0.1
157+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
158+
with:
159+
path: artifacts/
160+
161+
- name: Create GitHub Release
162+
# softprops/action-gh-release v2.5.0
163+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
164+
with:
165+
files: artifacts/**/*
166+
generate_release_notes: true
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# timsrust_cpp_bridgeConfig.cmake
2+
# Config-mode package file for timsrust_cpp_bridge
3+
#
4+
# Provides imported target: timsrust_cpp_bridge::timsrust_cpp_bridge
5+
#
6+
# This file lives at <prefix>/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfig.cmake
7+
# The prefix is resolved relative to this file's location.
8+
9+
get_filename_component(_TIMSRUST_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
10+
11+
if(NOT TARGET timsrust_cpp_bridge::timsrust_cpp_bridge)
12+
add_library(timsrust_cpp_bridge::timsrust_cpp_bridge STATIC IMPORTED)
13+
14+
set_target_properties(timsrust_cpp_bridge::timsrust_cpp_bridge PROPERTIES
15+
IMPORTED_LOCATION "${_TIMSRUST_PREFIX}/lib/@TIMSRUST_LIB_FILENAME@"
16+
INTERFACE_INCLUDE_DIRECTORIES "${_TIMSRUST_PREFIX}/include"
17+
)
18+
19+
# Platform-specific system link dependencies required by the Rust static library.
20+
# These are validated empirically by CI smoke tests on each platform.
21+
if(UNIX AND NOT APPLE)
22+
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
23+
INTERFACE_LINK_LIBRARIES pthread dl m)
24+
elseif(APPLE)
25+
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
26+
INTERFACE_LINK_LIBRARIES "-framework Security" "-framework SystemConfiguration" "-framework CoreFoundation" resolv)
27+
elseif(WIN32)
28+
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
29+
INTERFACE_LINK_LIBRARIES ws2_32 userenv bcrypt ntdll advapi32)
30+
endif()
31+
endif()
32+
33+
unset(_TIMSRUST_PREFIX)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# timsrust_cpp_bridgeConfigVersion.cmake
2+
# Auto-generated version compatibility file — SameMinorVersion semantics.
3+
4+
set(PACKAGE_VERSION "@TIMSRUST_VERSION_MAJOR@.@TIMSRUST_VERSION_MINOR@.@TIMSRUST_VERSION_PATCH@")
5+
6+
if(DEFINED PACKAGE_FIND_VERSION_RANGE)
7+
# Range semantics are not implemented in this template.
8+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
9+
elseif(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
10+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
11+
else()
12+
# SameMinorVersion: major and minor must match exactly
13+
if("@TIMSRUST_VERSION_MAJOR@" EQUAL PACKAGE_FIND_VERSION_MAJOR
14+
AND "@TIMSRUST_VERSION_MINOR@" EQUAL PACKAGE_FIND_VERSION_MINOR)
15+
set(PACKAGE_VERSION_COMPATIBLE TRUE)
16+
else()
17+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
18+
endif()
19+
20+
if(PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
21+
set(PACKAGE_VERSION_EXACT TRUE)
22+
endif()
23+
endif()

scripts/package.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Package timsrust_cpp_bridge release artifacts.
4+
#
5+
# Usage: scripts/package.sh <version> <target-triple>
6+
# e.g.: scripts/package.sh 0.1.0 x86_64-unknown-linux-gnu
7+
#
8+
# Expects cargo build --release to have been run already.
9+
# Outputs: timsrust_cpp_bridge-v<version>-<platform-label>.tar.gz (or .zip on Windows)
10+
11+
set -euo pipefail
12+
13+
VERSION="${1:?Usage: package.sh <version> <target-triple>}"
14+
TARGET="${2:?Usage: package.sh <version> <target-triple>}"
15+
16+
# Validate version format (semver or 0.0.0-dev for CI)
17+
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
18+
echo "Error: VERSION must be semver (e.g. 1.2.3), got: $VERSION" >&2
19+
exit 1
20+
fi
21+
22+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
24+
25+
# Map Rust target triple to platform label and library filename
26+
case "$TARGET" in
27+
x86_64-unknown-linux-gnu)
28+
PLATFORM="linux-x86_64"
29+
LIB_FILENAME="libtimsrust_cpp_bridge.a"
30+
;;
31+
aarch64-unknown-linux-gnu)
32+
PLATFORM="linux-aarch64"
33+
LIB_FILENAME="libtimsrust_cpp_bridge.a"
34+
;;
35+
aarch64-apple-darwin)
36+
PLATFORM="macos-arm64"
37+
LIB_FILENAME="libtimsrust_cpp_bridge.a"
38+
;;
39+
x86_64-pc-windows-msvc)
40+
PLATFORM="windows-x86_64"
41+
LIB_FILENAME="timsrust_cpp_bridge.lib"
42+
;;
43+
*)
44+
echo "Error: unknown target triple: $TARGET" >&2
45+
exit 1
46+
;;
47+
esac
48+
49+
ARCHIVE_NAME="timsrust_cpp_bridge-v${VERSION}-${PLATFORM}"
50+
STAGING_DIR="$PROJECT_ROOT/target/package/${ARCHIVE_NAME}/timsrust_cpp_bridge"
51+
52+
# Clean and create staging directory
53+
rm -rf "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}"
54+
mkdir -p "$STAGING_DIR/include"
55+
mkdir -p "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge"
56+
57+
# Copy header
58+
cp "$PROJECT_ROOT/include/timsrust_cpp_bridge.h" "$STAGING_DIR/include/"
59+
60+
# Copy static library
61+
cp "$PROJECT_ROOT/target/release/$LIB_FILENAME" "$STAGING_DIR/lib/"
62+
63+
# Configure CMake config file (replace @TIMSRUST_LIB_FILENAME@ placeholder)
64+
sed "s|@TIMSRUST_LIB_FILENAME@|${LIB_FILENAME}|g" \
65+
"$PROJECT_ROOT/cmake/timsrust_cpp_bridgeConfig.cmake.in" \
66+
> "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfig.cmake"
67+
68+
# Parse version components
69+
IFS='.' read -r V_MAJOR V_MINOR V_PATCH <<< "$VERSION"
70+
71+
# Configure version config file
72+
sed -e "s|@TIMSRUST_VERSION_MAJOR@|${V_MAJOR}|g" \
73+
-e "s|@TIMSRUST_VERSION_MINOR@|${V_MINOR}|g" \
74+
-e "s|@TIMSRUST_VERSION_PATCH@|${V_PATCH}|g" \
75+
"$PROJECT_ROOT/cmake/timsrust_cpp_bridgeConfigVersion.cmake.in" \
76+
> "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfigVersion.cmake"
77+
78+
# Create archive
79+
cd "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}"
80+
if [[ "$PLATFORM" == windows-* ]]; then
81+
rm -f "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.zip"
82+
7z a -tzip "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.zip" timsrust_cpp_bridge/
83+
echo "Created: target/package/${ARCHIVE_NAME}.zip"
84+
else
85+
tar czf "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.tar.gz" timsrust_cpp_bridge/
86+
echo "Created: target/package/${ARCHIVE_NAME}.tar.gz"
87+
fi

0 commit comments

Comments
 (0)