From 58389ad68586c13b28430799bcd6286978b17889 Mon Sep 17 00:00:00 2001 From: JohnE Date: Wed, 11 Mar 2026 16:12:55 -0700 Subject: [PATCH] NEW: build scripts --- README_DEV.rst | 370 +++++++++++++++++++++++++++++++++++++++++++++++++ Taskfile.yaml | 256 ++++++++++++++++++++++++++++++++++ ci.sh | 168 ++++++++++++++++++++++ 3 files changed, 794 insertions(+) create mode 100644 README_DEV.rst create mode 100644 Taskfile.yaml create mode 100755 ci.sh diff --git a/README_DEV.rst b/README_DEV.rst new file mode 100644 index 0000000..ed2cc98 --- /dev/null +++ b/README_DEV.rst @@ -0,0 +1,370 @@ +============================================= +CCC Rust — Developer Build Guide +============================================= + +:Last Updated: 2026-03-11 + +This document covers everything needed to build, test, and cross-compile the +``ccc_rust`` workspace on a development machine. + +---- + +Prerequisites +============= + +The table below lists all required tools. Versions shown are known-good; newer +patch releases should work. + ++------------------+---------------+--------------------------------------------------+ +| Tool | Min Version | Purpose | ++==================+===============+==================================================+ +| **Rust (rustup)**| stable 1.85+ | Compiler toolchain (pinned via ``rust-toolchain`` | +| | | ``.toml``) | ++------------------+---------------+--------------------------------------------------+ +| **CMake** | 3.24+ | Builds vendored wolfSSL from source | ++------------------+---------------+--------------------------------------------------+ +| **Clang / LLVM** | 14+ | Required by ``bindgen`` for FFI generation | ++------------------+---------------+--------------------------------------------------+ +| **Git** | 2.30+ | Submodule management | ++------------------+---------------+--------------------------------------------------+ +| **task** (opt) | 3.x | Local task runner (``Taskfile.yaml``) | ++------------------+---------------+--------------------------------------------------+ +| **Android NDK** | r25+ | Cross-compile for Android (optional on macOS) | +| (optional) | | | ++------------------+---------------+--------------------------------------------------+ + +Installing Dependencies +----------------------- + +macOS (Homebrew) +~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + # Rust (via rustup — manages toolchains automatically) + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + source "$HOME/.cargo/env" + + # CMake and LLVM (clang for bindgen) + brew install cmake llvm + + # Task runner (optional — for Taskfile.yaml) + brew install go-task + + # Xcode Command Line Tools (required for iOS/macOS targets) + xcode-select --install + +Linux (apt) +~~~~~~~~~~~ + +.. code-block:: shell + + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + source "$HOME/.cargo/env" + + sudo apt update && sudo apt install -y cmake clang libclang-dev git + + # Task runner (optional) + sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + +Windows +~~~~~~~ + +.. code-block:: shell + + # Install rustup from https://rustup.rs + # Install CMake from https://cmake.org/download/ (add to PATH) + # Install LLVM/Clang from https://releases.llvm.org/ (add to PATH) + # Install Visual Studio Build Tools (C++ workload) + +Android NDK (all platforms, optional) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Required only for ``aarch64-linux-android`` / ``x86_64-linux-android`` targets. + +.. code-block:: shell + + # Via Android Studio SDK Manager, or: + sdkmanager --install "ndk;28.2.13676358" + + # Set environment variables (add to your shell profile): + export ANDROID_NDK_HOME="$HOME/Library/Android/sdk/ndk/27.0.12077973" + export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH" + + # On Linux, replace darwin-x86_64 with linux-x86_64. + +---- + +First-Time Setup +================ + +.. code-block:: shell + + # Clone the repository + git clone ccc_rust && cd ccc_rust + + # Initialise the wolfSSL submodule (required — build fails without it) + git submodule update --init --recursive + + # Verify the toolchain (rustup reads rust-toolchain.toml automatically) + rustc --version # should print stable ≥ 1.85 + cmake --version # should print ≥ 3.24 + +---- + +Building +======== + +Native Build (Host Machine) +---------------------------- + +.. code-block:: shell + + cargo build --workspace # debug + cargo build --workspace --release # release (optimised) + +Cross-Compile Targets +--------------------- + +Cargo aliases are defined in ``.cargo/config.toml``: + +.. code-block:: shell + + # Apple + cargo build-ios # aarch64-apple-ios + cargo build-ios-sim # aarch64-apple-ios-sim + cargo build-macos-arm64 # aarch64-apple-darwin + cargo build-macos-x64 # x86_64-apple-darwin + cargo build-all-apple # all three Apple targets at once + + # Android (requires NDK — see above) + cargo build-android-arm64 # aarch64-linux-android + cargo build-android-x64 # x86_64-linux-android + + # Release variants: append --release + cargo build-ios --release + cargo build-macos-arm64 --release + +wolfSSL Build Overrides +~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``build.rs`` script accepts two environment variables: + +``WOLFSSL_SOURCE_DIR`` + Override the wolfSSL source path (default: ``vendors/wolfssl``). + Useful in CI when the submodule is at a non-standard location. + +``WOLFSSL_INSTALL_DIR`` + Point to a pre-installed wolfSSL (must contain ``include/wolfssl/`` + and ``lib/libwolfssl.a``). Skips the CMake build entirely. + +Stub FFI (no C build) +~~~~~~~~~~~~~~~~~~~~~~ + +For type-checking without building wolfSSL (CI lint jobs, docs): + +.. code-block:: shell + + cargo check -p ccc-crypto-wolfssl --features stub_ffi + +---- + +Testing +======= + +.. code-block:: shell + + # Unit tests (all crates) + cargo test --workspace + + # Conformance test binary (NIST / RFC vectors) + cargo run -p ccc-conformance-tests + + # Run a single test by name + cargo test --workspace test_name + + # Clippy (lint — treat warnings as errors) + cargo clippy --workspace -- -D warnings + + # Format check + cargo fmt --check + +---- + +Build Artifacts +=============== + +All output lands under ``target/``. The directory structure is: + +:: + + target/ + ├── debug/ ← native host debug + │ ├── conformance ← conformance test binary + │ ├── libccc_crypto_core.rlib ← core crate (Rust lib) + │ ├── libccc_crypto_wolfssl.rlib ← wolfSSL provider (Rust lib) + │ └── build/ccc-crypto-wolfssl-*/out/ + │ ├── lib/libwolfssl.a ← wolfSSL static library + │ └── include/wolfssl/ ← generated wolfSSL headers + ├── release/ ← native host release + │ └── (same layout as debug/) + ├── aarch64-apple-ios/ + │ └── debug/ | release/ ← iOS artifacts + ├── aarch64-apple-darwin/ + │ └── debug/ | release/ ← macOS ARM64 artifacts + ├── x86_64-apple-darwin/ + │ └── debug/ | release/ ← macOS x86_64 artifacts + ├── aarch64-linux-android/ + │ └── debug/ | release/ ← Android ARM64 artifacts + └── x86_64-linux-android/ + └── debug/ | release/ ← Android x86_64 artifacts + +Key Artifacts per Target +~~~~~~~~~~~~~~~~~~~~~~~~ + ++---------------------------------+--------------------------------------------------------------+ +| Artifact | Path | ++=================================+==============================================================+ +| Core Rust library | ``target///libccc_crypto_core.rlib`` | ++---------------------------------+--------------------------------------------------------------+ +| wolfSSL provider library | ``target///libccc_crypto_wolfssl.rlib`` | ++---------------------------------+--------------------------------------------------------------+ +| wolfSSL static C library | ``target///build/ccc-crypto-wolfssl-*/out/`` | +| | ``lib/libwolfssl.a`` | ++---------------------------------+--------------------------------------------------------------+ +| Conformance test binary | ``target///conformance`` | ++---------------------------------+--------------------------------------------------------------+ + +Where ```` is the Rust target triple (e.g. ``aarch64-apple-ios``) +and ```` is ``debug`` or ``release``. + +.. note:: + + These crates produce **rlib** (Rust library) output. The Milestone 2 + bridge crate (in the separate ``ccc_cryptography`` repository) adds + ``crate-type = ["cdylib", "staticlib"]`` to produce the ``.so`` / + ``.dylib`` / ``.a`` artifacts consumed by Flutter. + +---- + +Publish +======= + +The Rust crypto library remains a pure Rust crate with no Flutter or FFI-specific code. + +Option 1 +-------- +Option 1: Build from source via Cargokit (recommended for development) + * Cargokit compiles the Rust code at build time for each platform + * No precompiled binaries are needed + +Option 2 +-------- +Option 2: Cargokit precompiled binaries via GitHub Releases (recommended for pub.dev) + * The Rust crate is compiled into platform-specific binaries (staticlib for iOS/macOS, cdylib for Android) + * Binaries are uploaded to GitHub Releases + * Cargokit fetches the correct binary at build time based on the target platform + * This allows pub.dev users to get native performance without needing Rust or a build environment + +Workflow +~~~~~~~~ +* CI builds the Rust crate for all 5 platform targets +* CI uploads the .so/.dylib/.dll/.framework to a GitHub Release tagged with the Cargo package hash +* When consumers run flutter build, Cargokit downloads the precompiled binary instead of compiling +* If no precompiled binary exists, it falls back to source build +* Pros: Fast builds for consumers, no Rust toolchain needed, no repo bloat, built into FRB, single repo +* Cons: Requires CI pipeline to build + upload binaries +* Best for: pub.dev releases, distributing to teams without Rust installed + +---- + +Workspace Layout +================ + +:: + + ccc_rust/ + ├── Cargo.toml workspace manifest + ├── rust-toolchain.toml pinned stable toolchain + targets + ├── Taskfile.yaml local task runner (task CLI) + ├── ci.sh CI/CD build script + ├── .cargo/config.toml cross-compile aliases + linker config + ├── vendors/ + │ ├── README.md submodule pin rationale + │ └── wolfssl/ git submodule → wolfSSL v5.7.2-stable + ├── crates/ + │ ├── ccc-crypto-core/ shared traits, enums, registry + │ └── ccc-crypto-wolfssl/ wolfSSL/wolfCrypt provider + ├── tests/ + │ └── conformance/ NIST/RFC conformance test binary + └── docs/ architecture + design documents + +---- + +Troubleshooting +=============== + +wolfSSL source not found +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + wolfSSL source not found at .../vendors/wolfssl. + Run `git submodule update --init --recursive` to fetch it. + +The wolfSSL submodule was not initialised. Run the command shown in the error. + +Linker errors on Apple (undefined symbols) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ensure the ``-lc++`` link arg is set for Apple targets. This is configured +in ``.cargo/config.toml`` and should work automatically. If you see linker +errors about C++ symbols, verify Xcode Command Line Tools are installed: + +.. code-block:: shell + + xcode-select --install + +Android linker not found +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + linker `aarch64-linux-android21-clang` not found + +The Android NDK toolchain is not in your PATH. See the "Android NDK" section +above. + +bindgen fails / libclang not found +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``bindgen`` needs ``libclang``. On macOS, install LLVM via Homebrew: + +.. code-block:: shell + + brew install llvm + export LIBCLANG_PATH="$(brew --prefix llvm)/lib" + +On Linux: + +.. code-block:: shell + + sudo apt install libclang-dev + +---- + +Plugin Integration Notes +========================= + +When building the Milestone 2 Flutter plugin (``ccc_cryptography``): + +1. The bridge crate depends on these crates via git tag:: + + [dependencies] + ccc-crypto-core = { git = "...", tag = "v0.1.0" } + ccc-crypto-wolfssl = { git = "...", tag = "v0.1.0" } + +2. The bridge crate sets ``crate-type = ["cdylib", "staticlib"]``. +3. Call ``ccc_crypto_wolfssl::init()`` from the bridge's ``ccc_init()``. +4. ``flutter_rust_bridge`` and all Dart/Flutter dependencies live exclusively + in the plugin repo — never in this one. diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..f33d388 --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,256 @@ +# https://taskfile.dev +version: "3" + +vars: + APPLE_TARGETS: "aarch64-apple-ios aarch64-apple-darwin x86_64-apple-darwin" + +tasks: + + # ── Setup ──────────────────────────────────────────────────────────────── + + setup: + desc: Initialise submodules and verify toolchain + cmds: + - git submodule update --init --recursive + - rustc --version + - cmd: cmake --version | head -1 + platforms: [darwin, linux] + - cmd: cmake --version + platforms: [windows] + status: + - test -f vendors/wolfssl/CMakeLists.txt + + # ── Build ──────────────────────────────────────────────────────────────── + + build: + desc: Build all crates (debug) + deps: [setup] + cmds: + - cargo build --workspace + + release: + desc: Build all crates (release) + deps: [setup] + cmds: + - cargo build --workspace --release + + build:ios: + desc: Cross-compile for iOS (aarch64-apple-ios, release) + deps: [setup] + cmds: + - cargo build-ios --release + + build:macos-arm64: + desc: Cross-compile for macOS ARM64 (release) + deps: [setup] + cmds: + - cargo build-macos-arm64 --release + + build:macos-x64: + desc: Cross-compile for macOS x86_64 (release) + deps: [setup] + cmds: + - cargo build-macos-x64 --release + + build:apple: + desc: Cross-compile all Apple targets (iOS + macOS, release) + deps: [setup] + cmds: + - cargo build-ios --release + - cargo build-macos-arm64 --release + - cargo build-macos-x64 --release + + build:android-arm64: + desc: Cross-compile for Android ARM64 (release) + deps: [setup] + preconditions: + - sh: command -v aarch64-linux-android21-clang + msg: "Android NDK not in PATH. Set ANDROID_NDK_HOME and add toolchain bin/ to PATH." + cmds: + - cargo build-android-arm64 --release + + build:android-x64: + desc: Cross-compile for Android x86_64 (release) + deps: [setup] + preconditions: + - sh: command -v x86_64-linux-android21-clang + msg: "Android NDK not in PATH. Set ANDROID_NDK_HOME and add toolchain bin/ to PATH." + cmds: + - cargo build-android-x64 --release + + build:android: + desc: Cross-compile all Android targets (release) + cmds: + - task: build:android-arm64 + - task: build:android-x64 + + # ── Windows (run on Windows only) ───────────────────────────────────── + + build:windows-x64: + desc: Build for Windows x86_64 (release, run on Windows) + platforms: [windows] + deps: [setup] + cmds: + - cargo build --workspace --release --target x86_64-pc-windows-msvc + + ci:windows: + desc: Full CI pipeline for Windows + platforms: [windows] + cmds: + - task: lint + - task: test + - task: conformance + - task: build:windows-x64 + + # ── Linux ──────────────────────────────────────────────────────────────── + + build:linux-x64: + desc: Build for Linux x86_64 (release, run on Linux) + platforms: [linux] + deps: [setup] + cmds: + - cargo build --workspace --release --target x86_64-unknown-linux-gnu + + ci:linux: + desc: Full CI pipeline for Linux (lint + test + conformance + build + Android) + platforms: [linux] + cmds: + - task: lint + - task: test + - task: conformance + - task: build:linux-x64 + - task: build:android + + # ── Aggregate ──────────────────────────────────────────────────────────── + + build:all: + desc: Build for all targets (native + Apple + Android) + cmds: + - task: release + - task: build:apple + - task: build:android + + # ── Test ───────────────────────────────────────────────────────────────── + + test: + desc: Run all unit tests + deps: [setup] + cmds: + - cargo test --workspace + + conformance: + desc: Run NIST/RFC conformance test vectors + deps: [setup] + cmds: + - cargo run -p ccc-conformance-tests + + test:all: + desc: Run unit tests + conformance tests + cmds: + - task: test + - task: conformance + + # ── Lint ───────────────────────────────────────────────────────────────── + + fmt: + desc: Format code with rustfmt + cmds: + - cargo fmt + + fmt:check: + desc: Check formatting (no changes) + cmds: + - cargo fmt --check + + clippy: + desc: Run clippy with strict warnings + deps: [setup] + cmds: + - cargo clippy --workspace -- -D warnings + + lint: + desc: Full lint (fmt check + clippy) + cmds: + - task: fmt:check + - task: clippy + + # ── CI Pipeline ───────────────────────────────────────────────────────── + + ci: + desc: Full CI pipeline (lint → test → conformance → release build) + cmds: + - task: lint + - task: test + - task: conformance + - task: release + + ci:full: + desc: Full CI + all cross-compile targets (platform-aware) + cmds: + - task: ci + - task: build:apple + - task: build:android + + ci:macos: + desc: Full CI pipeline for macOS (lint + test + conformance + Apple targets) + platforms: [darwin] + cmds: + - task: lint + - task: test + - task: conformance + - task: release + - task: build:apple + + # ── Utility ───────────────────────────────────────────────────────────── + + clean: + desc: Remove all build artifacts + cmds: + - cargo clean + + check: + desc: Type-check without building (fast) + deps: [setup] + cmds: + - cargo check --workspace + + check:stub: + desc: Type-check wolfSSL crate with stub_ffi (no C build) + cmds: + - cargo check -p ccc-crypto-wolfssl --features stub_ffi + + artifacts: + desc: Show artifact locations for all built targets + platforms: [darwin, linux] + cmds: + - | + echo "=== Build artifacts ===" + for dir in target/debug target/release target/aarch64-apple-ios/release target/aarch64-apple-darwin/release target/x86_64-apple-darwin/release target/aarch64-linux-android/release target/x86_64-linux-android/release target/x86_64-unknown-linux-gnu/release; do + if [ -d "$dir" ]; then + echo "" + echo "── $dir ──" + find "$dir" -maxdepth 1 \( -name "*.rlib" -o -name "*.a" -o -name "*.dylib" -o -name "*.so" -o -name "conformance" \) 2>/dev/null | sort + find "$dir/build" -name "libwolfssl.a" 2>/dev/null | head -1 + fi + done + + artifacts:windows: + desc: Show artifact locations (Windows) + platforms: [windows] + cmds: + - cmd: | + echo === Build artifacts === + for %%d in (target\debug target\release target\x86_64-pc-windows-msvc\release) do ( + if exist "%%d" ( + echo. + echo -- %%d -- + dir /b "%%d\*.rlib" "%%d\*.lib" "%%d\*.dll" "%%d\*.exe" 2>nul + ) + ) + + # ── Default ───────────────────────────────────────────────────────────── + + default: + desc: Run the default CI pipeline + cmds: + - task: ci diff --git a/ci.sh b/ci.sh new file mode 100755 index 0000000..db2fe56 --- /dev/null +++ b/ci.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────────────────────── +# ci.sh — CI/CD build script for ccc_rust +# +# Usage: +# ./ci.sh Run the full CI pipeline (lint + test + cross-build) +# ./ci.sh lint Lint only (fmt + clippy) +# ./ci.sh test Unit tests + conformance vectors +# ./ci.sh build Native debug build +# ./ci.sh release Native release build +# ./ci.sh apple Cross-compile all Apple targets (iOS + macOS) +# ./ci.sh android Cross-compile Android targets (requires NDK) +# ./ci.sh all Full pipeline + all cross targets +# ────────────────────────────────────────────────────────────────────────────── +set -euo pipefail + +# Source cargo env if not already in PATH. +if ! command -v cargo &>/dev/null; then + # shellcheck source=/dev/null + source "$HOME/.cargo/env" +fi + +RED='\033[0;31m' +GREEN='\033[0;32m' +CYAN='\033[0;36m' +BOLD='\033[1m' +RESET='\033[0m' + +step() { echo -e "\n${CYAN}${BOLD}── $1 ──${RESET}"; } +pass() { echo -e "${GREEN}✓ $1${RESET}"; } +fail() { echo -e "${RED}✗ $1${RESET}"; exit 1; } + +# ── Submodule check ────────────────────────────────────────────────────────── + +check_submodule() { + if [ ! -f "vendors/wolfssl/CMakeLists.txt" ]; then + step "Initialising wolfSSL submodule" + git submodule update --init --recursive + fi +} + +# ── Stages ─────────────────────────────────────────────────────────────────── + +do_lint() { + step "Format check" + cargo fmt --check || fail "cargo fmt --check failed" + pass "Format OK" + + step "Clippy" + cargo clippy --workspace -- -D warnings || fail "clippy failed" + pass "Clippy OK" +} + +do_test() { + step "Unit tests" + cargo test --workspace || fail "cargo test failed" + pass "Unit tests passed" + + step "Conformance vectors" + cargo run -p ccc-conformance-tests || fail "conformance tests failed" + pass "Conformance tests passed" +} + +do_build() { + step "Build (debug)" + cargo build --workspace || fail "debug build failed" + pass "Debug build OK" +} + +do_release() { + step "Build (release)" + cargo build --workspace --release || fail "release build failed" + pass "Release build OK" +} + +do_apple() { + step "Build iOS (aarch64-apple-ios)" + cargo build-ios --release || fail "iOS build failed" + pass "iOS build OK" + + step "Build macOS ARM64 (aarch64-apple-darwin)" + cargo build-macos-arm64 --release || fail "macOS ARM64 build failed" + pass "macOS ARM64 build OK" + + step "Build macOS x64 (x86_64-apple-darwin)" + cargo build-macos-x64 --release || fail "macOS x64 build failed" + pass "macOS x64 build OK" +} + +do_android() { + if ! command -v aarch64-linux-android21-clang &>/dev/null; then + echo -e "${RED}Android NDK not in PATH — skipping Android targets.${RESET}" + echo "Set ANDROID_NDK_HOME and add the toolchain bin/ to PATH." + return 1 + fi + + step "Build Android ARM64 (aarch64-linux-android)" + cargo build-android-arm64 --release || fail "Android ARM64 build failed" + pass "Android ARM64 build OK" + + step "Build Android x64 (x86_64-linux-android)" + cargo build-android-x64 --release || fail "Android x64 build failed" + pass "Android x64 build OK" +} + +do_full() { + do_lint + do_test + do_release +} + +do_linux() { + step "Build Linux x64 (x86_64-unknown-linux-gnu)" + cargo build --workspace --release --target x86_64-unknown-linux-gnu \ + || fail "Linux x64 build failed" + pass "Linux x64 build OK" +} + +do_windows() { + step "Build Windows x64 (x86_64-pc-windows-msvc)" + cargo build --workspace --release --target x86_64-pc-windows-msvc \ + || fail "Windows x64 build failed" + pass "Windows x64 build OK" +} + +do_all() { + do_full + do_apple + do_android || true # Don't fail the pipeline if NDK is absent. +} + +# ── Summary ────────────────────────────────────────────────────────────────── + +summary() { + echo "" + step "Artifact locations" + echo " Native (release): target/release/" + echo " iOS: target/aarch64-apple-ios/release/" + echo " macOS ARM64: target/aarch64-apple-darwin/release/" + echo " macOS x64: target/x86_64-apple-darwin/release/" + echo " Linux x64: target/x86_64-unknown-linux-gnu/release/" + echo " Windows x64: target/x86_64-pc-windows-msvc/release/" + echo " Android ARM64: target/aarch64-linux-android/release/" + echo " Android x64: target/x86_64-linux-android/release/" + echo "" + pass "CI pipeline complete" +} + +# ── Main ───────────────────────────────────────────────────────────────────── + +check_submodule + +case "${1:-}" in + lint) do_lint ;; + test) do_test ;; + build) do_build ;; + release) do_release ;; + apple) do_apple && summary ;; + android) do_android && summary ;; + linux) do_linux && summary ;; + windows) do_windows && summary ;; + all) do_all && summary ;; + "") do_full && summary ;; + *) + echo "Usage: $0 {lint|test|build|release|apple|android|linux|windows|all}" + exit 1 + ;; +esac