Skip to content
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

Add Rust and Android CI build #499

Merged
merged 4 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 105 additions & 4 deletions .github/workflows/prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ env:
PYTHONUTF8: 1
PYTHON_VERSION: 3.11
DOTNET_VERSION: 7.0.x
ANDROID_NDK_VERSION: 26.3.11579264
ANDROID_SDK_VERSION: 21

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
Expand Down Expand Up @@ -101,11 +103,15 @@ jobs:
run: npm test

# Rust
- name: Set up Rust
run: |
rustup update stable
rustup default stable
rustc -vV
- name: Build Rust
run: cargo build
- name: Test Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
run: cargo test

# Java
- name: Setup Java
Expand Down Expand Up @@ -193,6 +199,17 @@ jobs:
- name: Test Python
run: pytest

# Rust
- name: Set up Rust
run: |
rustup update stable
rustup default stable
rustc -vV
- name: Build Rust
run: cargo build
- name: Test Rust
run: cargo test

# C#
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v3
Expand Down Expand Up @@ -260,6 +277,17 @@ jobs:
- name: Test ObjC/Swift
run: swift test

# Rust
- name: Set up Rust
run: |
rustup update stable
rustup default stable
rustc -vV
- name: Build Rust
run: cargo build
- name: Test Rust
run: cargo test

# C#
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v3
Expand Down Expand Up @@ -318,6 +346,17 @@ jobs:
- name: Test JavaScript
run: npm test

# Rust
- name: Set up Rust
run: |
rustup update stable
rustup default stable
rustc -vV
- name: Build Rust
run: cargo build
- name: Test Rust
run: cargo test

# C#
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v3
Expand Down Expand Up @@ -421,3 +460,65 @@ jobs:
run: |
test -e build_artifacts/libusearch_c.so
test -e build_artifacts/libusearch_sqlite.so

test_ubuntu_android_ndk:
name: Android NDK Build
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- processor: armv7a
abi: armeabi-v7a
target: armv7-linux-androideabi
- processor: aarch64
abi: arm64-v8a
target: aarch64-linux-android
steps:
- uses: actions/checkout@v4
- run: git submodule update --init --recursive

- name: Install NDK ndk
run: |
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install "ndk;${{ env.ANDROID_NDK_VERSION }}"

- name: Build C/C++
run: |
cmake -B build_artifacts \
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
-D CMAKE_EXPORT_COMPILE_COMMANDS=1 \
-D CMAKE_TOOLCHAIN_FILE=${ANDROID_HOME}/ndk/${{ env.ANDROID_NDK_VERSION }}/build/cmake/android.toolchain.cmake \
-D CMAKE_ANDROID_STL_TYPE=c++_static \
-D ANDROID_PLATFORM=${{ env.ANDROID_SDK_VERSION }} \
-D ANDROID_ABI=${{ matrix.abi }} \
-D USEARCH_BUILD_LIB_C=1 \
-D USEARCH_BUILD_TEST_CPP=0 \
-D USEARCH_BUILD_BENCH_CPP=0

cmake --build build_artifacts --config RelWithDebInfo

# We can't run the produced builds, but we can make sure they exist
- name: Test artifacts presense
run: |
test -e build_artifacts/libusearch_c.so

# Rust
- name: Set up Rust
run: |
rustup update stable
rustup default stable
rustup target add ${{ matrix.target }}
rustc -vV

- name: Set up Rust Env
run: |
TOOLCHAIN=${ANDROID_HOME}/ndk/${{ env.ANDROID_NDK_VERSION }}/toolchains/llvm/prebuilt/linux-x86_64/bin/
NDK_CLANG=$(find ${TOOLCHAIN} -name "${{ matrix.processor }}*${{ env.ANDROID_SDK_VERSION }}-clang")
echo "CC_${{ matrix.target }}=${NDK_CLANG}" >> ${GITHUB_ENV}
echo "CXX_${{ matrix.target }}=${NDK_CLANG}++" >> ${GITHUB_ENV}
echo "AR_${{ matrix.target }}=${TOOLCHAIN}/llvm-ar" >> ${GITHUB_ENV}
echo "CARGO_${{ matrix.target }}=${NDK_CLANG}" >> ${GITHUB_ENV}
echo "CARGO_${{ matrix.target }}=${TOOLCHAIN}/llvm-ar" >> ${GITHUB_ENV}

- name: Build Rust
run: |
cargo build --target ${{ matrix.target }}
78 changes: 43 additions & 35 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,37 @@ fn main() {

// Define all possible SIMD targets as 1
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let flags_to_try = match target_arch.as_str() {
"arm" | "aarch64" => vec![
"SIMSIMD_TARGET_SVE_BF16",
"SIMSIMD_TARGET_SVE_F16",
"SIMSIMD_TARGET_SVE_I8",
"SIMSIMD_TARGET_SVE",
"SIMSIMD_TARGET_NEON_BF16",
"SIMSIMD_TARGET_NEON_F16",
"SIMSIMD_TARGET_NEON_I8",
"SIMSIMD_TARGET_NEON",
],
_ => vec![
"SIMSIMD_TARGET_SAPPHIRE",
"SIMSIMD_TARGET_GENOA",
"SIMSIMD_TARGET_ICE",
"SIMSIMD_TARGET_SKYLAKE",
"SIMSIMD_TARGET_HASWELL",
],
};

let mut flags_to_try;
if cfg!(feature = "simsimd") {
build
.file("simsimd/c/lib.c")
.define("USEARCH_USE_SIMSIMD", "1")
.define("SIMSIMD_DYNAMIC_DISPATCH", "1")
.define("SIMSIMD_NATIVE_BF16", "0")
.define("SIMSIMD_NATIVE_F16", "0");

for flag in &flags_to_try {
build.define(flag, "1");
}
flags_to_try = match target_arch.as_str() {
"arm" | "aarch64" => vec![
"SIMSIMD_TARGET_NEON",
"SIMSIMD_TARGET_NEON_I8",
"SIMSIMD_TARGET_NEON_F16",
"SIMSIMD_TARGET_NEON_BF16",
"SIMSIMD_TARGET_SVE",
"SIMSIMD_TARGET_SVE_I8",
"SIMSIMD_TARGET_SVE_F16",
"SIMSIMD_TARGET_SVE_BF16",
],
_ => vec![
"SIMSIMD_TARGET_HASWELL",
"SIMSIMD_TARGET_SKYLAKE",
"SIMSIMD_TARGET_ICE",
"SIMSIMD_TARGET_GENOA",
"SIMSIMD_TARGET_SAPPHIRE",
],
};
} else {
build.define("USEARCH_USE_SIMSIMD", "0");
flags_to_try = vec![];
}

let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
Expand Down Expand Up @@ -91,26 +89,36 @@ fn main() {
.define("_ALLOW_POINTER_TO_CONST_MISMATCH", None);
}

let mut result = build.try_compile("usearch");
if result.is_err() {
print!("cargo:warning=Failed to compile with all SIMD backends...");
for flag in flags_to_try {
build.define(flag, "0");
result = build.try_compile("usearch");
if result.is_err() {
let base_build = build.clone();

let mut pop_flag = None;
loop {
let mut sub_build = base_build.clone();
for flag in &flags_to_try {
sub_build.define(flag, "1");
}
let result = sub_build.try_compile("usearch");
if result.is_err() {
if let Some(flag) = pop_flag {
println!(
"cargo:warning=Failed to compile after disabling {}, trying next configuration...",
"cargo:warning=Failed to compile after disabling {:?}, trying next configuration...",
flag
);
} else {
break;
if !flags_to_try.is_empty() {
print!("cargo:warning=Failed to compile with all SIMD backends...");
}
}

pop_flag = flags_to_try.pop();
if pop_flag.is_none() {
result.unwrap();
}
} else {
break;
}
}

// Ensure one build has been successful
result.unwrap();

println!("cargo:rerun-if-changed=rust/lib.rs");
println!("cargo:rerun-if-changed=rust/lib.cpp");
println!("cargo:rerun-if-changed=rust/lib.hpp");
Expand Down
Loading