From 6a524afa1389d6af52c0756fa4f3689eb2d5fa5c Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 16 May 2025 16:26:28 -0700 Subject: [PATCH 01/29] chore: Updates c2pa_rs and leverages workspace versioning and dependencies --- Cargo.lock | 4 ++-- Cargo.toml | 7 +++++++ c_api/Cargo.toml | 4 ++-- cli/Cargo.toml | 2 +- make_test_images/Cargo.toml | 4 ++-- sdk/Cargo.toml | 2 +- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1ca771be..695246ae6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "c2pa-c" -version = "0.49.5" +version = "0.51.1" dependencies = [ "c2pa", "cbindgen", @@ -2677,7 +2677,7 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "make_test_images" -version = "0.49.5" +version = "0.51.1" dependencies = [ "anyhow", "c2pa", diff --git a/Cargo.toml b/Cargo.toml index cbe890859..67aa09a9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,13 @@ members = [ "sdk", ] +# members in this workspace can share this version setting +[workspace.package] +version = "0.51.1" + +[workspace.dependencies] +c2pa = { path = "sdk" } + [profile.release] strip = true # Automatically strip symbols from the binary. opt-level = 3 diff --git a/c_api/Cargo.toml b/c_api/Cargo.toml index 7427794eb..80363fe6c 100644 --- a/c_api/Cargo.toml +++ b/c_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c2pa-c" -version = "0.49.5" +version.workspace = true edition = "2021" authors = ["Gavin Peacock "] license = "MIT OR Apache-2.0" @@ -14,7 +14,7 @@ json_api = ["c2pa/v1_api"] [dependencies] tokio = { version = "1.36", features = ["rt-multi-thread","rt"] } -c2pa = { path = "../sdk", version = "0.51.1", features = [ +c2pa = { workspace = true , features = [ "file_io", "add_thumbnails", "fetch_remote_manifests", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 99a18901c..7b2d2d604 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,7 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } [dependencies] anyhow = "1.0" atree = "0.5.2" -c2pa = { path = "../sdk", version = "0.51.1", features = [ +c2pa = { workspace = true , features = [ "fetch_remote_manifests", "file_io", "add_thumbnails", diff --git a/make_test_images/Cargo.toml b/make_test_images/Cargo.toml index 15fbbe0c5..c1ddc9691 100644 --- a/make_test_images/Cargo.toml +++ b/make_test_images/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "make_test_images" -version = "0.49.5" +version.workspace = true authors = ["Gavin Peacock "] license = "MIT OR Apache-2.0" edition = "2021" @@ -16,7 +16,7 @@ required-features = ["default"] [dependencies] anyhow = "1.0.40" -c2pa = { path = "../sdk" } +c2pa = { workspace = true } env_logger = "0.11" log = "0.4.8" image = { version = "0.25.2", default-features = false, features = [ diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index f5190d422..0938ac567 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c2pa" -version = "0.51.1" +version.workspace = true description = "Rust SDK for C2PA (Coalition for Content Provenance and Authenticity) implementors" authors = [ "Maurice Fisher ", From 09ac4dd464897f03c2fa1b52cb67b74057ca608d Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 16 May 2025 16:26:59 -0700 Subject: [PATCH 02/29] chore: Another attempt at fixing the library release process --- .github/workflows/library-release.yml | 36 ++++++--------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 8c2496695..52d51f6de 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -65,7 +65,6 @@ jobs: - name: Upload build artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }}-${{ matrix.target }}-release path: target/artifacts/* release: @@ -75,42 +74,21 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - path: artifacts + name: release-artifacts + path: . + merge-multiple: true - name: List downloaded artifacts - run: find . -type f | sort - + run: ls -lh + - name: Create Release id: create_release uses: softprops/action-gh-release@v1 with: files: | - ./ubuntu-latest-x86_64-unknown-linux-gnu-release/ubuntu-latest-x86_64-unknown-linux-gnu-release.tar.gz - ./windows-latest-x86_64-pc-windows-msvc-release/windows-latest-x86_64-pc-windows-msvc-release.zip - ./macos-latest-x86_64-apple-darwin-release/macos-latest-x86_64-apple-darwin-release.tar.gz - draft: false - prerelease: false - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create GitHub Release legacy - id: create_release_legacy - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref_name }} - release_name: Release ${{ github.ref_name }} + ./* draft: true prerelease: true - - - name: Upload Release Assets old + generate_release_notes: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - for file in artifacts/*; do - echo "Uploading $file..." - gh release upload "${{ github.ref_name }}" "$file" --clobber - done - From 3a04c6a4d97820bf02cb1b52e5967c5c4cdb931d Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 16 May 2025 20:47:13 -0700 Subject: [PATCH 03/29] chore: repair capi_makefile - realpath was failing --- .github/workflows/library-release.yml | 3 ++- c_api/Makefile | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 52d51f6de..3560ee1ab 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -53,10 +53,11 @@ jobs: perl -MLocale::Maketext::Simple -e "print \$INC{'Locale/Maketext/Simple.pm'}" > module_path.txt $MODULE_PATH = Get-Content -Path module_path.txt echo "Module found at: $MODULE_PATH" - + # Create symbolic links to the modules in paths that are being checked # Set environment variable for subsequent steps echo "PERL5LIB=$env:PERL5LIB;D:\a\c2pa-rs\c2pa-rs\target\x86_64-pc-windows-msvc\release\build\openssl-sys-def693d178636927\out\openssl-build\build\src\util\perl" | Out-File -FilePath $env:GITHUB_ENV -Append + choco install make shell: pwsh - name: Build release diff --git a/c_api/Makefile b/c_api/Makefile index 699715dac..ba2bfd84e 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -16,10 +16,11 @@ else endif endif -TARGET_DIR := $(realpath ../target) +TARGET_DIR := ../target # Helper function to create a zip file define make_zip + set -e; \ echo "Reading version from $(1)/c2pa.h"; \ if [ "$(PLATFORM)" = "win" ]; then \ VERSION=$$(findstr "^// Version:" $(1)/c2pa.h | awk -F": " "{print \$$2}"); \ @@ -31,7 +32,7 @@ define make_zip mkdir -p $(TARGET_DIR)/artifacts $(1)/include $(1)/lib; \ cp $(1)/c2pa.h $(1)/include/; \ cp $(1)/libc2pa_c.* $(1)/lib/; \ - cd $(1) && zip -r $${ZIP_NAME} include lib; \ + zip -r $${ZIP_NAME} $(1)/include $(1)/lib; \ echo "Zip file created: $${ZIP_NAME}" endef From 73e9153b0408550266535568684d7e8f95461df1 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 16 May 2025 23:55:40 -0700 Subject: [PATCH 04/29] chore: actually try to publish to the right tag --- .github/workflows/library-release.yml | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 3560ee1ab..2fbba9914 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -4,8 +4,11 @@ on: push: tags: - 'c2pa-v*' # Trigger on version tags (e.g., v1.0.0) - workflow_dispatch: # Allow manual triggering of the workflow - + workflow_dispatch: + #inputs: + # tag_name: + # description: 'Release tag (e.g., c2pa-v0.52.0)' + # required: true jobs: build: name: Publish c2pa-library binaries @@ -66,6 +69,7 @@ jobs: - name: Upload build artifacts uses: actions/upload-artifact@v4 with: + name: release-artifacts path: target/artifacts/* release: @@ -82,13 +86,22 @@ jobs: - name: List downloaded artifacts run: ls -lh + - name: Extract tag_name from zip file + id: extract_tag + run: | + ZIP=$(ls c2pa-v*-*.zip | head -n1) + TAG_NAME=$(echo "$ZIP" | sed -E 's/^(c2pa-v[0-9]+\.[0-9]+\.[0-9]+)-.*\.zip/\1/') + echo "Found tag: $TAG_NAME" + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + - name: Create Release id: create_release uses: softprops/action-gh-release@v1 with: - files: | - ./* - draft: true + tag_name: ${{ steps.extract_tag.outputs.tag_name }} + #tag_name: ${{ github.event.inputs.tag_name || github.ref_name }} + files: ./* + draft: false prerelease: true generate_release_notes: true env: From ee371687443331b6f89bc86b07e42ede98b44e89 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sat, 17 May 2025 00:22:53 -0700 Subject: [PATCH 05/29] chore: allow overwrite and add ssl env vars for win --- .github/workflows/library-release.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 2fbba9914..b287d2e2e 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -61,6 +61,14 @@ jobs: # Set environment variable for subsequent steps echo "PERL5LIB=$env:PERL5LIB;D:\a\c2pa-rs\c2pa-rs\target\x86_64-pc-windows-msvc\release\build\openssl-sys-def693d178636927\out\openssl-build\build\src\util\perl" | Out-File -FilePath $env:GITHUB_ENV -Append choco install make + run: echo "Windows env vars set" + env: + OPENSSL_CONF: C:\vcpkg\installed\x64-windows-static\tools\openssl\openssl.cnf + OPENSSL_DIR: C:\vcpkg\installed\x64-windows-static + OPENSSL_NO_VENDOR: 1 + OPENSSL_STATIC: Yes + RUSTFLAGS: -Ctarget-feature=-crt-static + VCPKGRS_DYNAMIC: 1 shell: pwsh - name: Build release @@ -104,5 +112,6 @@ jobs: draft: false prerelease: true generate_release_notes: true + overwrite: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 6dd88cb7c0efe9a4a74b752014f0c6c640f3fd27 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sat, 17 May 2025 00:48:10 -0700 Subject: [PATCH 06/29] chore: try try try again --- .github/workflows/library-release.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index b287d2e2e..54ee2f820 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -61,7 +61,6 @@ jobs: # Set environment variable for subsequent steps echo "PERL5LIB=$env:PERL5LIB;D:\a\c2pa-rs\c2pa-rs\target\x86_64-pc-windows-msvc\release\build\openssl-sys-def693d178636927\out\openssl-build\build\src\util\perl" | Out-File -FilePath $env:GITHUB_ENV -Append choco install make - run: echo "Windows env vars set" env: OPENSSL_CONF: C:\vcpkg\installed\x64-windows-static\tools\openssl\openssl.cnf OPENSSL_DIR: C:\vcpkg\installed\x64-windows-static @@ -78,10 +77,11 @@ jobs: uses: actions/upload-artifact@v4 with: name: release-artifacts - path: target/artifacts/* + path: target/artifacts/ release: needs: build + if: always() runs-on: ubuntu-latest steps: - name: Download build artifacts @@ -108,10 +108,11 @@ jobs: with: tag_name: ${{ steps.extract_tag.outputs.tag_name }} #tag_name: ${{ github.event.inputs.tag_name || github.ref_name }} + files: ./* draft: false prerelease: true generate_release_notes: true - overwrite: true + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 575b73ee5803c15eea0fad9d1d8b8f138867d226 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sat, 17 May 2025 01:07:22 -0700 Subject: [PATCH 07/29] chore: if at first you fail, keep failing --- .github/workflows/library-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 54ee2f820..9edbb9561 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -76,7 +76,7 @@ jobs: - name: Upload build artifacts uses: actions/upload-artifact@v4 with: - name: release-artifacts + name: release-artifacts-${{ matrix.os }}-${{ matrix.target }} path: target/artifacts/ release: @@ -87,7 +87,7 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: release-artifacts + pattern: release-artifacts-* path: . merge-multiple: true From a8773860955a20e5d444bdfaa2ee4dd9e77b3751 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sat, 17 May 2025 15:11:09 -0700 Subject: [PATCH 08/29] chore(c_api): The artifacts did not have correct content --- c_api/Makefile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/c_api/Makefile b/c_api/Makefile index ba2bfd84e..692262ab7 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -20,20 +20,18 @@ TARGET_DIR := ../target # Helper function to create a zip file define make_zip - set -e; \ + set -e; \ echo "Reading version from $(1)/c2pa.h"; \ if [ "$(PLATFORM)" = "win" ]; then \ VERSION=$$(findstr "^// Version:" $(1)/c2pa.h | awk -F": " "{print \$$2}"); \ else \ VERSION=$$(grep '^// Version:' $(1)/c2pa.h | sed 's/^\/\/ Version: //'); \ fi; \ - ZIP_NAME=$(TARGET_DIR)/artifacts/c2pa-v$${VERSION}-$(2).zip; \ - echo "Creating zip file: $${ZIP_NAME}"; \ mkdir -p $(TARGET_DIR)/artifacts $(1)/include $(1)/lib; \ cp $(1)/c2pa.h $(1)/include/; \ cp $(1)/libc2pa_c.* $(1)/lib/; \ - zip -r $${ZIP_NAME} $(1)/include $(1)/lib; \ - echo "Zip file created: $${ZIP_NAME}" + (cd $(1) && zip -9 -r ../../artifacts/c2pa-v$${VERSION}-$(2).zip include lib); \ + echo "Zip file created: $(TARGET_DIR)/artifacts/c2pa-v$${VERSION}-$(2).zip" endef check-format: From a28371431cf5ffa327de0d67fc987f7f5d70ae7b Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sat, 17 May 2025 21:16:51 -0700 Subject: [PATCH 09/29] chore(c_api): fix the rpath and add universal debug symbols --- Cargo.toml | 3 ++- c_api/Makefile | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 67aa09a9a..4f610c30d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ version = "0.51.1" c2pa = { path = "sdk" } [profile.release] -strip = true # Automatically strip symbols from the binary. +debug = true +#strip = true # Automatically strip symbols from the binary. opt-level = 3 lto = "thin" # Link time optimization. diff --git a/c_api/Makefile b/c_api/Makefile index 692262ab7..88bcfdd03 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -59,20 +59,35 @@ release-win: release-mac-arm: rustup target add aarch64-apple-darwin MACOSX_DEPLOYMENT_TARGET=11.1 cargo build --target=aarch64-apple-darwin --release - @$(call make_zip,$(TARGET_DIR)/aarch64-apple-darwin/release,aarch64-apple-darwin) + install_name_tool -id @rpath/libc2pa_c.dylib $(TARGET_DIR)/aarch64-apple-darwin/release/libc2pa_c.dylib release-mac-x86: rustup target add x86_64-apple-darwin MACOSX_DEPLOYMENT_TARGET=10.15 cargo build --target=x86_64-apple-darwin --release - @$(call make_zip,$(TARGET_DIR)/x86_64-apple-darwin/release,x86_64-apple-darwin) + install_name_tool -id @rpath/libc2pa_c.dylib $(TARGET_DIR)/x86_64-apple-darwin/release/libc2pa_c.dylib release-mac-universal: release-mac-arm release-mac-x86 rm -rf $(TARGET_DIR)/universal-apple-darwin mkdir -p $(TARGET_DIR)/universal-apple-darwin/release lipo -create -output $(TARGET_DIR)/universal-apple-darwin/release/libc2pa_c.dylib $(TARGET_DIR)/aarch64-apple-darwin/release/libc2pa_c.dylib ../target/x86_64-apple-darwin/release/libc2pa_c.dylib cp $(TARGET_DIR)/aarch64-apple-darwin/release/c2pa.h $(TARGET_DIR)/universal-apple-darwin/release/c2pa.h + install_name_tool -id @rpath/libc2pa_c.dylib $(TARGET_DIR)/universal-apple-darwin/release/libc2pa_c.dylib + dsymutil $(TARGET_DIR)/universal-apple-darwin/release/libc2pa_c.dylib + + cd $(TARGET_DIR)/universal-apple-darwin/release && \ + zip -r9 libc2pa_c.dylib.dSYM.zip libc2pa_c.dylib.dSYM && \ + rm -rf libc2pa_c.dylib.dSYM && \ + ls -l + + strip -x $(TARGET_DIR)/universal-apple-darwin/release/libc2pa_c.dylib @$(call make_zip,$(TARGET_DIR)/universal-apple-darwin/release,universal-apple-darwin) + strip -x $(TARGET_DIR)/aarch64-apple-darwin/release/libc2pa_c.dylib + @$(call make_zip,$(TARGET_DIR)/aarch64-apple-darwin/release,aarch64-apple-darwin) + + strip -x $(TARGET_DIR)/x86_64-apple-darwin/release/libc2pa_c.dylib + @$(call make_zip,$(TARGET_DIR)/x86_64-apple-darwin/release,x86_64-apple-darwin) + release-linux-gnu-x86: rustup target add x86_64-unknown-linux-gnu cargo build --target=x86_64-unknown-linux-gnu --release From b1fa53846f3774a086df1d63fa45c8f99e3eb1b4 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Sun, 18 May 2025 21:50:23 -0700 Subject: [PATCH 10/29] chore(c_api): add powershell script for windows --- .github/workflows/library-release.yml | 39 +-------- setup-rust-openssl.ps1 | 118 ++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 setup-rust-openssl.ps1 diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 9edbb9561..2e06ac5c8 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -5,10 +5,7 @@ on: tags: - 'c2pa-v*' # Trigger on version tags (e.g., v1.0.0) workflow_dispatch: - #inputs: - # tag_name: - # description: 'Release tag (e.g., c2pa-v0.52.0)' - # required: true + jobs: build: name: Publish c2pa-library binaries @@ -36,40 +33,12 @@ jobs: - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Setup Strawberry Perl - if: matrix.os == 'windows-latest' - uses: shogo82148/actions-setup-perl@v1 - with: - perl-version: '5.32' - distribution: 'strawberry' - - # Install Locale::Maketext::Simple only on Windows with explicit paths - - name: Install Locale::Maketext::Simple and configure paths + - name: Setup OpenSSL if: matrix.os == 'windows-latest' + shell: pwsh run: | - cpanm --verbose Locale::Maketext::Simple - # List installed modules to confirm installation - cpanm --info Locale::Maketext::Simple - # Display Perl's include paths - perl -e "print join(\"\n\", @INC);" - # Create a local copy in the expected path - perl -MLocale::Maketext::Simple -e "print \$INC{'Locale/Maketext/Simple.pm'}" > module_path.txt - $MODULE_PATH = Get-Content -Path module_path.txt - echo "Module found at: $MODULE_PATH" + ./setup-rust-openssl.ps1 - # Create symbolic links to the modules in paths that are being checked - # Set environment variable for subsequent steps - echo "PERL5LIB=$env:PERL5LIB;D:\a\c2pa-rs\c2pa-rs\target\x86_64-pc-windows-msvc\release\build\openssl-sys-def693d178636927\out\openssl-build\build\src\util\perl" | Out-File -FilePath $env:GITHUB_ENV -Append - choco install make - env: - OPENSSL_CONF: C:\vcpkg\installed\x64-windows-static\tools\openssl\openssl.cnf - OPENSSL_DIR: C:\vcpkg\installed\x64-windows-static - OPENSSL_NO_VENDOR: 1 - OPENSSL_STATIC: Yes - RUSTFLAGS: -Ctarget-feature=-crt-static - VCPKGRS_DYNAMIC: 1 - shell: pwsh - - name: Build release run: make release diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 new file mode 100644 index 000000000..8a0c01bd0 --- /dev/null +++ b/setup-rust-openssl.ps1 @@ -0,0 +1,118 @@ +# setup-rust-openssl.ps1 +# Script to setup Rust with OpenSSL using Visual Studio tools on GitHub Actions windows-latest image + +# Stop on first error +$ErrorActionPreference = "Stop" + +Write-Host "Setting up Rust with OpenSSL (MSVC) environment..." + +# Define variables +$OPENSSL_VERSION = "3.1.4" +$OPENSSL_DIR = "C:\OpenSSL" +$TEMP_DIR = "C:\openssl_build" +# Detect Visual Studio installation path using vswhere +Write-Host "Detecting Visual Studio installation..." +$vswhere_path = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" +if (-Not (Test-Path $vswhere_path)) { + Write-Host "Error: vswhere.exe not found. Please ensure Visual Studio is installed." -ForegroundColor Red + exit 1 +} + +$vs_installation_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath +if (-Not $vs_installation_path) { + Write-Host "Error: Could not detect Visual Studio installation. Ensure the required components are installed." -ForegroundColor Red + exit 1 +} + +$VCVARS_PATH = Join-Path -Path $vs_installation_path -ChildPath "VC\Auxiliary\Build\vcvars64.bat" +if (-Not (Test-Path $VCVARS_PATH)) { + Write-Host "Error: vcvars64.bat not found. Ensure Visual Studio is properly installed." -ForegroundColor Red + exit 1 +} + +Write-Host "Visual Studio detected at: $vs_installation_path" +Write-Host "Using vcvars64.bat at: $VCVARS_PATH" + +# Create directories +New-Item -ItemType Directory -Force -Path $TEMP_DIR | Out-Null +New-Item -ItemType Directory -Force -Path $OPENSSL_DIR | Out-Null + +# Change to temp directory +Push-Location $TEMP_DIR + +try { + # Download OpenSSL source + Write-Host "Downloading OpenSSL source..." + $openssl_url = "https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz" + Invoke-WebRequest -Uri $openssl_url -OutFile "openssl.tar.gz" + + # Extract OpenSSL + Write-Host "Extracting OpenSSL source..." + tar -xf openssl.tar.gz + + # Setup Visual Studio environment + Write-Host "Setting up Visual Studio environment..." + cmd.exe /c "call `"$VCVARS_PATH`" && set > %temp%\vcvars.txt" + Get-Content "$env:temp\vcvars.txt" | ForEach-Object { + if ($_ -match "^(.*?)=(.*)$") { + $name = $matches[1] + $value = $matches[2] + [Environment]::SetEnvironmentVariable($name, $value, [EnvironmentVariableTarget]::Process) + } + } + + # Configure and build OpenSSL + Write-Host "Configuring and building OpenSSL..." + cd "openssl-$OPENSSL_VERSION" + + # Configure OpenSSL for MSVC (not MinGW/GNU) + perl Configure VC-WIN64A --prefix=$OPENSSL_DIR --openssldir=$OPENSSL_DIR\ssl + + # Set locale environment variables to avoid Perl warnings + [Environment]::SetEnvironmentVariable("LC_ALL", "C", [EnvironmentVariableTarget]::Process) + [Environment]::SetEnvironmentVariable("LANG", "C", [EnvironmentVariableTarget]::Process) + + # Build and install OpenSSL (not needed if rust will be compiling and embedding) + #nmake + #nmake install_sw + + # Set environment variables for Rust + Write-Host "Setting environment variables for Rust..." + [Environment]::SetEnvironmentVariable("OPENSSL_DIR", $OPENSSL_DIR, [EnvironmentVariableTarget]::User) + [Environment]::SetEnvironmentVariable("OPENSSL_LIB_DIR", "$OPENSSL_DIR\lib", [EnvironmentVariableTarget]::User) + [Environment]::SetEnvironmentVariable("OPENSSL_INCLUDE_DIR", "$OPENSSL_DIR\include", [EnvironmentVariableTarget]::User) + + # Set for current process as well + $env:OPENSSL_DIR = $OPENSSL_DIR + $env:OPENSSL_LIB_DIR = "$OPENSSL_DIR\lib" + $env:OPENSSL_INCLUDE_DIR = "$OPENSSL_DIR\include" + + # Ensure Rust is using MSVC toolchain + Write-Host "Configuring Rust to use MSVC toolchain..." + rustup default stable-msvc + rustup update stable-msvc + + # Add OpenSSL bin to PATH for DLLs + $current_path = [Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::User) + $new_path = "$OPENSSL_DIR\bin;$current_path" + [Environment]::SetEnvironmentVariable("PATH", $new_path, [EnvironmentVariableTarget]::user) + $env:PATH = "$OPENSSL_DIR\bin;$env:PATH" + + # Output summary + Write-Host "`n=== Configuration Summary ===`n" + Write-Host "OpenSSL installed to: $OPENSSL_DIR" + Write-Host "OpenSSL version: $OPENSSL_VERSION" + Write-Host "Rust toolchain: $(rustc --version)" + Write-Host "Environment variables set:" + Write-Host " OPENSSL_DIR = $env:OPENSSL_DIR" + Write-Host " OPENSSL_LIB_DIR = $env:OPENSSL_LIB_DIR" + Write-Host " OPENSSL_INCLUDE_DIR = $env:OPENSSL_INCLUDE_DIR" + Write-Host "`nSetup completed successfully!" + +} catch { + Write-Host "Error: $_" -ForegroundColor Red + exit 1 +} finally { + # Return to original directory + Pop-Location +} \ No newline at end of file From 2458b14e36c1d55cde5a1ca2c35b270c11276837 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 19 May 2025 22:59:22 -0700 Subject: [PATCH 11/29] build: add linux arm build --- .github/workflows/library-release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 2e06ac5c8..f08527213 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -23,6 +23,9 @@ jobs: - os: ubuntu-latest target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + - os: windows-latest target: x86_64-pc-windows-msvc @@ -33,6 +36,13 @@ jobs: - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Install ARM cross-compilation dependencies + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + rustup target add aarch64-unknown-linux-gnu + - name: Setup OpenSSL if: matrix.os == 'windows-latest' shell: pwsh From 1b1b7eee4c53f81f1008326017db5b32cbb6a40a Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 19 May 2025 23:34:44 -0700 Subject: [PATCH 12/29] build: another approach to linux arm --- .github/workflows/library-release.yml | 7 ------- c_api/Makefile | 7 +------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index f08527213..2841110aa 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -13,19 +13,13 @@ jobs: strategy: fail-fast: false matrix: - os: [ macos-latest, ubuntu-latest, windows-latest ] rust_version: [ stable ] experimental: [ false ] include: - os: macos-latest target: aarch64-apple-darwin - - os: ubuntu-latest target: x86_64-unknown-linux-gnu - - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - os: windows-latest target: x86_64-pc-windows-msvc @@ -86,7 +80,6 @@ jobs: uses: softprops/action-gh-release@v1 with: tag_name: ${{ steps.extract_tag.outputs.tag_name }} - #tag_name: ${{ github.event.inputs.tag_name || github.ref_name }} files: ./* draft: false diff --git a/c_api/Makefile b/c_api/Makefile index 88bcfdd03..db0fbfa97 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -112,10 +112,5 @@ echo "No release build for aarch64 on Windows" endif endif ifeq ($(PLATFORM), linux) -ifeq ($(ARCH), x86_64) -release: release-linux-gnu-x86 -endif -ifeq ($(ARCH), aarch64) -release: release-linux-gnu-arm -endif +release: release-linux-gnu-x86 release-linux-gnu-arm endif From f851b53106ba6f2c6bf66c802dde5b2bebb5b23e Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 19 May 2025 23:53:30 -0700 Subject: [PATCH 13/29] build: restore the matrix --- .github/workflows/library-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 2841110aa..8599b729f 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -13,13 +13,12 @@ jobs: strategy: fail-fast: false matrix: - rust_version: [ stable ] - experimental: [ false ] include: - os: macos-latest target: aarch64-apple-darwin - os: ubuntu-latest target: x86_64-unknown-linux-gnu + - os: windows-latest target: x86_64-pc-windows-msvc From 084565db717788b684a20452ffe7f456e4589072 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 19 May 2025 23:56:41 -0700 Subject: [PATCH 14/29] build: fix cross comp --- .github/workflows/library-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 8599b729f..c65b07cd9 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -18,7 +18,6 @@ jobs: target: aarch64-apple-darwin - os: ubuntu-latest target: x86_64-unknown-linux-gnu - - os: windows-latest target: x86_64-pc-windows-msvc @@ -30,7 +29,7 @@ jobs: uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Install ARM cross-compilation dependencies - if: matrix.target == 'aarch64-unknown-linux-gnu' + if: matrix.target == '86_64-unknown-linux-gnu' run: | sudo apt-get update sudo apt-get install -y gcc-aarch64-linux-gnu From d7dd1c3f1082f55380a08c6d2ef58dc3ec2dce55 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 00:01:34 -0700 Subject: [PATCH 15/29] build: add the magic x --- .github/workflows/library-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index c65b07cd9..0f87f260c 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -29,7 +29,7 @@ jobs: uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Install ARM cross-compilation dependencies - if: matrix.target == '86_64-unknown-linux-gnu' + if: matrix.target == 'x86_64-unknown-linux-gnu' run: | sudo apt-get update sudo apt-get install -y gcc-aarch64-linux-gnu From 897eac8e29046b2a9cf4e7c364e4bea7d5624a6a Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 00:08:19 -0700 Subject: [PATCH 16/29] build: add Maketext::Simple --- setup-rust-openssl.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 index 8a0c01bd0..ca9140293 100644 --- a/setup-rust-openssl.ps1 +++ b/setup-rust-openssl.ps1 @@ -49,6 +49,10 @@ try { # Extract OpenSSL Write-Host "Extracting OpenSSL source..." tar -xf openssl.tar.gz + + # Install required Perl modules + Write-Host "Installing Perl module Locale::Maketext::Simple..." + cpan -T -i Locale::Maketext::Simple # Setup Visual Studio environment Write-Host "Setting up Visual Studio environment..." From 6196cc9554d01026057dde50ba613e6d3412601e Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 00:19:17 -0700 Subject: [PATCH 17/29] build: cross comp fix --- c_api/Cargo.toml | 3 +++ docs/c_api.md | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 docs/c_api.md diff --git a/c_api/Cargo.toml b/c_api/Cargo.toml index 80363fe6c..b481f382c 100644 --- a/c_api/Cargo.toml +++ b/c_api/Cargo.toml @@ -31,3 +31,6 @@ tempfile = "3.7.0" [build-dependencies] cbindgen = "0.28" + +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" diff --git a/docs/c_api.md b/docs/c_api.md new file mode 100644 index 000000000..2ff7cccbb --- /dev/null +++ b/docs/c_api.md @@ -0,0 +1,7 @@ +# C API Notes + +This C API provides a standard export C based interface for binding to other languages. +We provide pre-built dynamic library binary images for linux, macosx and windows that export this API. +This can be used without any specific knowledge of Rust and leverages well known rules for linking to C based libraries. + +### \ No newline at end of file From 1871d18cf8a3edffaaa722c70c876ef93e5230cd Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 00:27:18 -0700 Subject: [PATCH 18/29] build: go back to stripping debug symbols until someone asks for them --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f610c30d..67aa09a9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ version = "0.51.1" c2pa = { path = "sdk" } [profile.release] -debug = true -#strip = true # Automatically strip symbols from the binary. +strip = true # Automatically strip symbols from the binary. opt-level = 3 lto = "thin" # Link time optimization. From 108cafd47b467c4b3bb2572dd6c8b8dee693db99 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 11:21:23 -0700 Subject: [PATCH 19/29] build: Another shot at a linux arm build --- .github/workflows/library-release.yml | 9 ++------- c_api/Makefile | 7 ++++++- docs/c_api.md | 11 ++++++++++- setup-rust-openssl.ps1 | 18 +++++++++++++++++- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 0f87f260c..022d5ec10 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -16,6 +16,8 @@ jobs: include: - os: macos-latest target: aarch64-apple-darwin + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu - os: ubuntu-latest target: x86_64-unknown-linux-gnu - os: windows-latest @@ -28,13 +30,6 @@ jobs: - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Install ARM cross-compilation dependencies - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu - rustup target add aarch64-unknown-linux-gnu - - name: Setup OpenSSL if: matrix.os == 'windows-latest' shell: pwsh diff --git a/c_api/Makefile b/c_api/Makefile index db0fbfa97..88bcfdd03 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -112,5 +112,10 @@ echo "No release build for aarch64 on Windows" endif endif ifeq ($(PLATFORM), linux) -release: release-linux-gnu-x86 release-linux-gnu-arm +ifeq ($(ARCH), x86_64) +release: release-linux-gnu-x86 +endif +ifeq ($(ARCH), aarch64) +release: release-linux-gnu-arm +endif endif diff --git a/docs/c_api.md b/docs/c_api.md index 2ff7cccbb..09eb214c3 100644 --- a/docs/c_api.md +++ b/docs/c_api.md @@ -4,4 +4,13 @@ This C API provides a standard export C based interface for binding to other lan We provide pre-built dynamic library binary images for linux, macosx and windows that export this API. This can be used without any specific knowledge of Rust and leverages well known rules for linking to C based libraries. -### \ No newline at end of file +### Change from earlier versions +The C interface is not new, but it used to be part of the c2pa_c repo. We discovered that a lot of the that interface was useful to other bindings, so we were exporting as a Rust based JSON api from there. But that led to things like the c2pa_python repo importing from c2pa_c and then re-exporting it via uniffi as a python api. There were some severe limitations in what the uniffi tools could represent such as the inability to have mutable parameters. We found other limitations with the tools designed for binding Rust to C++, Swift and other languages. + +#### New approach +Binding to C APIs is a well established and mature practice. Every language has well documented methods for binding to C. Rust has built in support for writing C bindings. If we provide a solid C interface, we can simply bind other languages to C and leverage all the work that has gone into those bindings. + +We still need to write bindings for each language, but since there are so many examples of this, AI engines are very good at writing the code. The result is well formed, well documented bindings. I've found it takes some manual effort to fix some things. Instead of unreadable, incomprehensible auto generated binding glue, we end up with well structured code bindings that can be customized for our needs. + +#### Tradeoffs +The C language is not object oriented and does not natively support things like exception handling. There is no garbage collection. APIs use unsafe pointer references. We must be very careful about pointers an memory management. So the C API is not something we want developers to use directly. But it makes a very solid common way to bridge between Rust and other languages when used correctly. Higher level structures in the other languages can ensure that references to Rust structures are correctly managed and freed. diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 index ca9140293..9cb507360 100644 --- a/setup-rust-openssl.ps1 +++ b/setup-rust-openssl.ps1 @@ -51,8 +51,24 @@ try { tar -xf openssl.tar.gz # Install required Perl modules + Write-Host "Checking for CPAN..." + if (-not (Get-Command cpan -ErrorAction SilentlyContinue)) { + Write-Error "CPAN is not installed. Please install Strawberry Perl or ActiveState Perl first." + exit 1 + } + Write-Host "Installing Perl module Locale::Maketext::Simple..." - cpan -T -i Locale::Maketext::Simple + try { + cpan -i Locale::Maketext::Simple + if (-not (perl -e "use Locale::Maketext::Simple; print 'Module installed successfully'")) { + throw "Module installation verification failed" + } + Write-Host "Successfully installed Locale::Maketext::Simple" + } + catch { + Write-Error "Failed to install Locale::Maketext::Simple: $_" + exit 1 + } # Setup Visual Studio environment Write-Host "Setting up Visual Studio environment..." From 71f150f357be7e735182ee527beb37466c8f2da2 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 11:50:34 -0700 Subject: [PATCH 20/29] build: use the right kind of perl --- .github/workflows/library-release.yml | 2 ++ setup-rust-openssl.ps1 | 20 -------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 022d5ec10..725bebc2d 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -34,6 +34,8 @@ jobs: if: matrix.os == 'windows-latest' shell: pwsh run: | + "PERL=$((where.exe perl)[0])" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 + echo "OPENSSL_SRC_PERL=$((where.exe perl)[0])" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 ./setup-rust-openssl.ps1 - name: Build release diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 index 9cb507360..8a0c01bd0 100644 --- a/setup-rust-openssl.ps1 +++ b/setup-rust-openssl.ps1 @@ -49,26 +49,6 @@ try { # Extract OpenSSL Write-Host "Extracting OpenSSL source..." tar -xf openssl.tar.gz - - # Install required Perl modules - Write-Host "Checking for CPAN..." - if (-not (Get-Command cpan -ErrorAction SilentlyContinue)) { - Write-Error "CPAN is not installed. Please install Strawberry Perl or ActiveState Perl first." - exit 1 - } - - Write-Host "Installing Perl module Locale::Maketext::Simple..." - try { - cpan -i Locale::Maketext::Simple - if (-not (perl -e "use Locale::Maketext::Simple; print 'Module installed successfully'")) { - throw "Module installation verification failed" - } - Write-Host "Successfully installed Locale::Maketext::Simple" - } - catch { - Write-Error "Failed to install Locale::Maketext::Simple: $_" - exit 1 - } # Setup Visual Studio environment Write-Host "Setting up Visual Studio environment..." From 26a5f6d51047d85b1ae4d7dec34365516e21769b Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 14:27:32 -0700 Subject: [PATCH 21/29] build: do not use make for windows build --- .github/workflows/library-release.yml | 6 ++-- setup-rust-openssl.ps1 | 41 ++++++++++++++++++++------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.github/workflows/library-release.yml b/.github/workflows/library-release.yml index 725bebc2d..55fbf7146 100644 --- a/.github/workflows/library-release.yml +++ b/.github/workflows/library-release.yml @@ -30,15 +30,13 @@ jobs: - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Setup OpenSSL + - name: Build Windows release if: matrix.os == 'windows-latest' shell: pwsh run: | - "PERL=$((where.exe perl)[0])" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 - echo "OPENSSL_SRC_PERL=$((where.exe perl)[0])" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 ./setup-rust-openssl.ps1 - - name: Build release + if: matrix.os != 'windows-latest' run: make release - name: Upload build artifacts diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 index 8a0c01bd0..61e3941ca 100644 --- a/setup-rust-openssl.ps1 +++ b/setup-rust-openssl.ps1 @@ -72,9 +72,6 @@ try { [Environment]::SetEnvironmentVariable("LC_ALL", "C", [EnvironmentVariableTarget]::Process) [Environment]::SetEnvironmentVariable("LANG", "C", [EnvironmentVariableTarget]::Process) - # Build and install OpenSSL (not needed if rust will be compiling and embedding) - #nmake - #nmake install_sw # Set environment variables for Rust Write-Host "Setting environment variables for Rust..." @@ -86,12 +83,7 @@ try { $env:OPENSSL_DIR = $OPENSSL_DIR $env:OPENSSL_LIB_DIR = "$OPENSSL_DIR\lib" $env:OPENSSL_INCLUDE_DIR = "$OPENSSL_DIR\include" - - # Ensure Rust is using MSVC toolchain - Write-Host "Configuring Rust to use MSVC toolchain..." - rustup default stable-msvc - rustup update stable-msvc - + # Add OpenSSL bin to PATH for DLLs $current_path = [Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::User) $new_path = "$OPENSSL_DIR\bin;$current_path" @@ -108,7 +100,36 @@ try { Write-Host " OPENSSL_LIB_DIR = $env:OPENSSL_LIB_DIR" Write-Host " OPENSSL_INCLUDE_DIR = $env:OPENSSL_INCLUDE_DIR" Write-Host "`nSetup completed successfully!" - + + # build with Rust msvc + Write-Host "Building Rust project with msvc toolchain ..." + rustup update stable-msvc + rustup target add x86_64-pc-windows-msvc + cargo build --target=x86_64-pc-windows-msvc --release + + # generate zip file with version and platform and add to artifacts folder + $platform = "x86_64-pc-windows-msvc" + $ReleaseDir = "target\$platform\release" + $artifactsDir = "target\artifacts" + $includeDir = "$ReleaseDir\include" + $libDir = "$ReleaseDir\lib" + + Write-Host "Reading version from $ReleaseDir\c2pa.h" + $versionLine = Select-String -Path "$ReleaseDir\c2pa.h" -Pattern "^// Version:" | Select-Object -First 1 + $version = $versionLine -replace "^// Version: ", "" + + New-Item -ItemType Directory -Force -Path $artifactsDir | Out-Null + New-Item -ItemType Directory -Force -Path $includeDir | Out-Null + New-Item -ItemType Directory -Force -Path $libDir | Out-Null + + Copy-Item "$ReleaseDir\c2pa.h" $includeDir -Force + Copy-Item "$ReleaseDir\libc2pa_c.*" $libDir -Force + + $zipPath = "$artifactsDir\c2pa-v$version-$Platform.zip" + Compress-Archive -Path "$includeDir", "$libDir" -DestinationPath $zipPath -Force + + Write-Host "Zip file created: $zipPath" + } catch { Write-Host "Error: $_" -ForegroundColor Red exit 1 From 5e7a193e2406f56308e3ccce9dc8f079206cb10b Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 15:42:40 -0700 Subject: [PATCH 22/29] build: use powershell for make on windows --- c_api/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/c_api/Makefile b/c_api/Makefile index 88bcfdd03..10444d537 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -52,9 +52,7 @@ fmt: # These are for building the c2patool release bin on various platforms release-win: - rustup target add x86_64-pc-windows-msvc - cargo build --target=x86_64-pc-windows-msvc --release - @$(call make_zip,$(TARGET_DIR)/x86_64-pc-windows-msvc/release,x86_64-pc-windows-msvc) + powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 release-mac-arm: rustup target add aarch64-apple-darwin From 33035b5e75a1d6a17d7bd3b2c7ad47ab6c40bf4f Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Tue, 20 May 2025 16:32:23 -0700 Subject: [PATCH 23/29] chore: version --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 556fce783..b8f9b9e91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -712,7 +712,7 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "c2pa" -version = "0.53.0" +version = "0.51.1" dependencies = [ "actix", "anyhow", From 5a5891a6575ae9175c4394393879947ec456527d Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Wed, 21 May 2025 14:57:21 -0700 Subject: [PATCH 24/29] build: c2pa_c libraries with native_rust_crypto --- Cargo.lock | 30 ++++++++++++------------ Cargo.toml | 2 +- c_api/Cargo.toml | 11 ++++----- c_api/Makefile | 14 +++++++++-- c_api/src/c_api.rs | 54 +++++++++++++++++++++++++++++++++---------- c_api/src/json_api.rs | 33 +++++++++----------------- c_api/src/lib.rs | 4 +--- cli/Cargo.toml | 2 +- 8 files changed, 87 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8f9b9e91..0c1b5a3a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -816,21 +816,6 @@ dependencies = [ "zip", ] -[[package]] -name = "c2pa-c" -version = "0.51.1" -dependencies = [ - "c2pa", - "cbindgen", - "scopeguard", - "serde", - "serde_json", - "tempfile", - "thiserror 1.0.69", - "tokio", - "zip", -] - [[package]] name = "c2patool" version = "0.17.0" @@ -860,6 +845,21 @@ dependencies = [ "wstd", ] +[[package]] +name = "c_api" +version = "0.51.1" +dependencies = [ + "c2pa", + "cbindgen", + "scopeguard", + "serde", + "serde_json", + "tempfile", + "thiserror 1.0.69", + "tokio", + "zip", +] + [[package]] name = "cbindgen" version = "0.28.0" diff --git a/Cargo.toml b/Cargo.toml index eec688810..b898f59a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ version = "0.51.1" [workspace.dependencies] -c2pa = { path = "sdk" } +c2pa = { path = "sdk", default-features = true } [profile.release] strip = true # Automatically strip symbols from the binary. diff --git a/c_api/Cargo.toml b/c_api/Cargo.toml index 5898ffddc..1837502b4 100644 --- a/c_api/Cargo.toml +++ b/c_api/Cargo.toml @@ -1,18 +1,17 @@ [package] -name = "c2pa-c" +name = "c_api" version.workspace = true edition = "2021" authors = ["Gavin Peacock "] license = "MIT OR Apache-2.0" [lib] +name = "c2pa_c" crate-type = ["cdylib"] [features] -default = ["json_api", "openssl"] -json_api = ["c2pa/v1_api"] -openssl = ["c2pa/openssl"] rust_native_crypto = ["c2pa/rust_native_crypto"] +file_io = ["c2pa/file_io"] [dependencies] tokio = { version = "1.36", features = ["rt-multi-thread","rt"] } @@ -21,7 +20,7 @@ c2pa = { workspace = true , features = [ "file_io", "add_thumbnails", "fetch_remote_manifests", -], default-features = false } +]} scopeguard = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -34,5 +33,3 @@ tempfile = "3.7.0" [build-dependencies] cbindgen = "0.28" -[target.aarch64-unknown-linux-gnu] -linker = "aarch64-linux-gnu-gcc" diff --git a/c_api/Makefile b/c_api/Makefile index 10444d537..ac21109be 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -51,8 +51,18 @@ fmt: cargo +nightly fmt # These are for building the c2patool release bin on various platforms -release-win: - powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 +release-win-x86_64: + rustup update stable-msvc + rustup target add x86_64-pc-windows-msvc + cargo build --target=x86_64-pc-windows-msvc --release --no-default-features --features "rust_native_crypto, file_io" + cargo test --target=x86_64-pc-windows-msvc --release ---no-default-features --features "rust_native_crypto, file_io" +# powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 + +release-win-aarch64: + rustup update stable-msvc + rustup target add aarch64-pc-windows-msvc + cargo build --target=aarch64-pc-windows-msvc --release +# powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 release-mac-arm: rustup target add aarch64-apple-darwin diff --git a/c_api/src/c_api.rs b/c_api/src/c_api.rs index bb722e8f7..e51c80b9e 100644 --- a/c_api/src/c_api.rs +++ b/c_api/src/c_api.rs @@ -24,12 +24,9 @@ use c2pa::{ use scopeguard::guard; use tokio::runtime::Runtime; // cawg validator requires async -use crate::{ - c2pa_stream::C2paStream, - error::Error, - json_api::{read_file, read_ingredient_file, sign_file}, - signer_info::SignerInfo, -}; +#[cfg(feature = "file_io")] +use crate::json_api::{read_file, read_ingredient_file, sign_file}; +use crate::{c2pa_stream::C2paStream, error::Error, signer_info::SignerInfo}; // Work around limitations in cbindgen. mod cbindgen_fix { @@ -297,6 +294,7 @@ pub unsafe extern "C" fn c2pa_load_settings( /// Reads from NULL-terminated C strings. /// The returned value MUST be released by calling release_string /// and it is no longer valid after that call. +#[cfg(feature = "file_io")] #[no_mangle] pub unsafe extern "C" fn c2pa_read_file( path: *const c_char, @@ -328,6 +326,7 @@ pub unsafe extern "C" fn c2pa_read_file( /// Reads from NULL-terminated C strings. /// The returned value MUST be released by calling release_string /// and it is no longer valid after that call. +#[cfg(feature = "file_io")] #[no_mangle] pub unsafe extern "C" fn c2pa_read_ingredient_file( path: *const c_char, @@ -335,11 +334,10 @@ pub unsafe extern "C" fn c2pa_read_ingredient_file( ) -> *mut c_char { let path = from_cstr_or_return_null!(path); let data_dir = from_cstr_or_return_null!(data_dir); - - let result = read_ingredient_file(&path, &data_dir); + result = Ingredient::from_file_with_folder(path, data_dir).map_err(Error::from_c2pa_error); match result { - Ok(json) => to_c_string(json), + Ok(ingredient) => to_c_string(ingredient.to_string()), Err(err) => { err.set_last(); std::ptr::null_mut() @@ -372,6 +370,7 @@ pub struct C2paSignerInfo { /// Reads from NULL-terminated C strings. /// The returned value MUST be released by calling release_string /// and it is no longer valid after that call. +#[cfg(feature = "file_io")] #[no_mangle] pub unsafe extern "C" fn c2pa_sign_file( source_path: *const c_char, @@ -447,7 +446,7 @@ fn post_validate(result: Result) -> Result Result { + let path = from_cstr_or_return_null!(path); + let result = C2paReader::from_file(&path); + return_boxed!(post_validate(result)) +} + /// Creates and verifies a C2paReader from an asset stream with the given format and manifest data. /// /// Parameters @@ -965,8 +996,7 @@ pub unsafe extern "C" fn c2pa_format_embeddable( check_or_return_int!(result_bytes_ptr); let bytes = std::slice::from_raw_parts(manifest_bytes_ptr, manifest_bytes_size); - // todo: Add a way to do this without using the v1_api Manifest - let result = c2pa::Manifest::composed_manifest(bytes, &format); + let result = c2pa::Builder::composed_manifest(bytes, &format); ok_or_return_int!(result, |result_bytes: Vec| { let len = result_bytes.len() as i64; if !result_bytes_ptr.is_null() { diff --git a/c_api/src/json_api.rs b/c_api/src/json_api.rs index 347fa7604..90c031584 100644 --- a/c_api/src/json_api.rs +++ b/c_api/src/json_api.rs @@ -39,15 +39,6 @@ pub fn read_file(path: &str, data_dir: Option) -> Result { }) } -/// Returns an Ingredient JSON string from a file path. -/// -/// Any thumbnail or c2pa data will be written to data_dir if provided -pub fn read_ingredient_file(path: &str, data_dir: &str) -> Result { - Ok(Ingredient::from_file_with_folder(path, data_dir) - .map_err(Error::from_c2pa_error)? - .to_string()) -} - /// Adds a manifest to the source file and writes the result to the destination file. /// Also returns the binary manifest data for optional cloud storage /// A manifest definition must be supplied @@ -61,30 +52,28 @@ pub fn sign_file( signer_info: &SignerInfo, data_dir: Option, ) -> Result> { - let mut manifest = Manifest::from_json(manifest_json).map_err(Error::from_c2pa_error)?; + let mut builder = c2pa::Builder::rom_json(manifest_json).map_err(Error::from_c2pa_error)?; // if data_dir is provided, set the base path for the manifest if let Some(path) = data_dir { - manifest - .with_base_path(path) - .map_err(Error::from_c2pa_error)?; + builder.base_path = Some(PathBuf::from(path)); } // If the source file has a manifest store, and no parent is specified, treat the source's manifest store as the parent. - if manifest.parent().is_none() { - let source_ingredient = Ingredient::from_file(source).map_err(Error::from_c2pa_error)?; + if builder.ingredients.iter().find(|i| i.is_parent()).is_none() { + let mut source_ingredient = + Ingredient::from_file(source).map_err(Error::from_c2pa_error)?; if source_ingredient.manifest_data().is_some() { - manifest - .set_parent(source_ingredient) - .map_err(Error::from_c2pa_error)?; + source_ingredient.set_parent(true); + builder.add_ingredient(source_ingredient); } } let signer = signer_info.signer()?; - #[allow(deprecated)] - manifest - .embed(&source, &dest, &*signer) - .map_err(Error::from_c2pa_error) + // todo allow source = + builder + .sign_file(signer, source, dest) + .map_err(Error::from_c2pa_error)?; } #[cfg(test)] diff --git a/c_api/src/lib.rs b/c_api/src/lib.rs index c30ccf31c..3a187b347 100644 --- a/c_api/src/lib.rs +++ b/c_api/src/lib.rs @@ -14,7 +14,7 @@ mod c2pa_stream; mod c_api; mod error; -#[cfg(feature = "json_api")] +#[cfg(feature = "file_io")] mod json_api; mod signer_info; @@ -24,6 +24,4 @@ pub use c2pa::{ pub use c2pa_stream::*; pub use c_api::*; pub use error::{Error, Result}; -#[cfg(feature = "json_api")] -pub use json_api::{read_file, read_ingredient_file, sdk_version, sign_file}; pub use signer_info::SignerInfo; diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 880d143cc..0dc542fd1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -34,7 +34,7 @@ c2pa = { workspace = true , features = [ "file_io", "add_thumbnails", "pdf" -], default-features = false } +]} clap = { version = "4.5.10", features = ["derive", "env"] } env_logger = "0.11.7" glob = "0.3.1" From 49a5f4b8bc7025a356d344af7abdf593f07173dd Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Thu, 22 May 2025 13:57:01 -0700 Subject: [PATCH 25/29] chore: repair make test moves some Reader functionality to Store store tests under v1_api until we resolve issues. --- Makefile | 14 ++-- c_api/Makefile | 44 +++++------ c_api/src/c_api.rs | 11 ++- c_api/src/json_api.rs | 20 +++-- sdk/src/asset_handlers/c2pa_io.rs | 14 +++- sdk/src/ingredient.rs | 28 ++----- sdk/src/jumbf_io.rs | 2 +- sdk/src/manifest.rs | 1 + sdk/src/manifest_store.rs | 21 +---- sdk/src/reader.rs | 44 ++++++----- sdk/src/store.rs | 122 +++++++++++++++++++++--------- sdk/src/utils/test_signer.rs | 2 +- 12 files changed, 181 insertions(+), 142 deletions(-) diff --git a/Makefile b/Makefile index 10c10fc52..b599c666b 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,12 @@ ifeq ($(OS),Windows_NT) PLATFORM := win else UNAME := $(shell uname) - ifeq ($(UNAME),Linux) - PLATFORM := linux - endif - ifeq ($(UNAME),Darwin) - PLATFORM := mac - endif + ifeq ($(UNAME),Linux) + PLATFORM := linux + endif + ifeq ($(UNAME),Darwin) + PLATFORM := mac + endif endif check-format: @@ -22,7 +22,7 @@ clippy: cargo clippy --features="file_io" --all-targets -- -D warnings test-local: - cargo test --features="file_io, fetch_remote_manifests, add_thumbnails" --all-targets + cargo test --features="file_io, fetch_remote_manifests, add_thumbnails, v1_api" --all-targets # Builds and views documentation test-wasm: diff --git a/c_api/Makefile b/c_api/Makefile index ac21109be..7947a7f4b 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -8,30 +8,30 @@ ifeq ($(OS),Windows_NT) PLATFORM := win else UNAME := $(shell uname) - ifeq ($(UNAME),Linux) - PLATFORM := linux - endif - ifeq ($(UNAME),Darwin) - PLATFORM := mac - endif + ifeq ($(UNAME),Linux) + PLATFORM := linux + endif + ifeq ($(UNAME),Darwin) + PLATFORM := mac + endif endif TARGET_DIR := ../target # Helper function to create a zip file define make_zip - set -e; \ - echo "Reading version from $(1)/c2pa.h"; \ - if [ "$(PLATFORM)" = "win" ]; then \ - VERSION=$$(findstr "^// Version:" $(1)/c2pa.h | awk -F": " "{print \$$2}"); \ - else \ - VERSION=$$(grep '^// Version:' $(1)/c2pa.h | sed 's/^\/\/ Version: //'); \ - fi; \ - mkdir -p $(TARGET_DIR)/artifacts $(1)/include $(1)/lib; \ - cp $(1)/c2pa.h $(1)/include/; \ - cp $(1)/libc2pa_c.* $(1)/lib/; \ - (cd $(1) && zip -9 -r ../../artifacts/c2pa-v$${VERSION}-$(2).zip include lib); \ - echo "Zip file created: $(TARGET_DIR)/artifacts/c2pa-v$${VERSION}-$(2).zip" + set -e; \ + echo "Reading version from $(1)/c2pa.h"; \ + if [ "$(PLATFORM)" = "win" ]; then \ + VERSION=$$(findstr "^// Version:" $(1)/c2pa.h | awk -F": " "{print \$$2}"); \ + else \ + VERSION=$$(grep '^// Version:' $(1)/c2pa.h | sed 's/^\/\/ Version: //'); \ + fi; \ + mkdir -p $(TARGET_DIR)/artifacts $(1)/include $(1)/lib; \ + cp $(1)/c2pa.h $(1)/include/; \ + cp $(1)/libc2pa_c.* $(1)/lib/; \ + (cd $(1) && zip -9 -r ../../artifacts/c2pa-v$${VERSION}-$(2).zip include lib); \ + echo "Zip file created: $(TARGET_DIR)/artifacts/c2pa-v$${VERSION}-$(2).zip" endef check-format: @@ -52,9 +52,9 @@ fmt: # These are for building the c2patool release bin on various platforms release-win-x86_64: - rustup update stable-msvc - rustup target add x86_64-pc-windows-msvc - cargo build --target=x86_64-pc-windows-msvc --release --no-default-features --features "rust_native_crypto, file_io" + rustup update stable-msvc + rustup target add x86_64-pc-windows-msvc + cargo build --target=x86_64-pc-windows-msvc --release --no-default-features --features "rust_native_crypto, file_io" cargo test --target=x86_64-pc-windows-msvc --release ---no-default-features --features "rust_native_crypto, file_io" # powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 @@ -85,7 +85,7 @@ release-mac-universal: release-mac-arm release-mac-x86 cd $(TARGET_DIR)/universal-apple-darwin/release && \ zip -r9 libc2pa_c.dylib.dSYM.zip libc2pa_c.dylib.dSYM && \ rm -rf libc2pa_c.dylib.dSYM && \ - ls -l + ls -l strip -x $(TARGET_DIR)/universal-apple-darwin/release/libc2pa_c.dylib @$(call make_zip,$(TARGET_DIR)/universal-apple-darwin/release,universal-apple-darwin) diff --git a/c_api/src/c_api.rs b/c_api/src/c_api.rs index e51c80b9e..5707c1d3a 100644 --- a/c_api/src/c_api.rs +++ b/c_api/src/c_api.rs @@ -16,6 +16,8 @@ use std::{ os::raw::{c_char, c_int, c_uchar, c_void}, }; +#[cfg(feature = "file_io")] +use c2pa::Ingredient; // C has no namespace so we prefix things with C2PA to make them unique use c2pa::{ assertions::DataHash, identity::validator::CawgValidator, settings::load_settings_from_str, @@ -25,7 +27,7 @@ use scopeguard::guard; use tokio::runtime::Runtime; // cawg validator requires async #[cfg(feature = "file_io")] -use crate::json_api::{read_file, read_ingredient_file, sign_file}; +use crate::json_api::{read_file, sign_file}; use crate::{c2pa_stream::C2paStream, error::Error, signer_info::SignerInfo}; // Work around limitations in cbindgen. @@ -334,7 +336,7 @@ pub unsafe extern "C" fn c2pa_read_ingredient_file( ) -> *mut c_char { let path = from_cstr_or_return_null!(path); let data_dir = from_cstr_or_return_null!(data_dir); - result = Ingredient::from_file_with_folder(path, data_dir).map_err(Error::from_c2pa_error); + let result = Ingredient::from_file_with_folder(path, data_dir).map_err(Error::from_c2pa_error); match result { Ok(ingredient) => to_c_string(ingredient.to_string()), @@ -505,7 +507,7 @@ pub unsafe extern "C" fn c2pa_reader_from_stream( /// ``` #[cfg(feature = "file_io")] #[no_mangle] -pub unsafe fn c2pa_reader_from_file(path: *const c_char) -> Result { +pub unsafe fn c2pa_reader_from_file(path: *const c_char) -> *mut C2paReader { let path = from_cstr_or_return_null!(path); let result = C2paReader::from_file(&path); return_boxed!(post_validate(result)) @@ -1340,6 +1342,7 @@ mod tests { } #[test] + #[cfg(feature = "file_io")] fn test_c2pa_read_file_null_path() { let data_dir = CString::new("/tmp").unwrap(); let result = unsafe { c2pa_read_file(std::ptr::null(), data_dir.as_ptr()) }; @@ -1350,6 +1353,7 @@ mod tests { } #[test] + #[cfg(feature = "file_io")] fn test_c2pa_read_ingredient_file_null_path() { let data_dir = CString::new("/tmp").unwrap(); let result = unsafe { c2pa_read_ingredient_file(std::ptr::null(), data_dir.as_ptr()) }; @@ -1360,6 +1364,7 @@ mod tests { } #[test] + #[cfg(feature = "file_io")] fn test_c2pa_sign_file_null_source_path() { let dest_path = CString::new("/tmp/output.jpg").unwrap(); let manifest = CString::new("{}").unwrap(); diff --git a/c_api/src/json_api.rs b/c_api/src/json_api.rs index 90c031584..8f0443330 100644 --- a/c_api/src/json_api.rs +++ b/c_api/src/json_api.rs @@ -10,16 +10,13 @@ // specific language governing permissions and limitations under // each license. -use c2pa::{identity::validator::CawgValidator, Ingredient, Manifest, Reader}; +use std::path::PathBuf; + +use c2pa::{identity::validator::CawgValidator, Ingredient, Reader, Relationship}; use tokio::runtime::Runtime; use crate::{Error, Result, SignerInfo}; -/// Returns the version of the c2pa SDK used in this library -pub fn sdk_version() -> String { - String::from(c2pa::VERSION) -} - /// Returns ManifestStore JSON string from a file path. /// /// If data_dir is provided, any thumbnail or c2pa data will be written to that folder. @@ -52,7 +49,7 @@ pub fn sign_file( signer_info: &SignerInfo, data_dir: Option, ) -> Result> { - let mut builder = c2pa::Builder::rom_json(manifest_json).map_err(Error::from_c2pa_error)?; + let mut builder = c2pa::Builder::from_json(manifest_json).map_err(Error::from_c2pa_error)?; // if data_dir is provided, set the base path for the manifest if let Some(path) = data_dir { @@ -60,20 +57,21 @@ pub fn sign_file( } // If the source file has a manifest store, and no parent is specified, treat the source's manifest store as the parent. - if builder.ingredients.iter().find(|i| i.is_parent()).is_none() { + if !builder.definition.ingredients.iter().any(|i| i.is_parent()) { let mut source_ingredient = Ingredient::from_file(source).map_err(Error::from_c2pa_error)?; if source_ingredient.manifest_data().is_some() { - source_ingredient.set_parent(true); + source_ingredient.set_relationship(Relationship::ParentOf); builder.add_ingredient(source_ingredient); } } let signer = signer_info.signer()?; + // todo allow source = builder - .sign_file(signer, source, dest) - .map_err(Error::from_c2pa_error)?; + .sign_file(&*signer, source, dest) + .map_err(Error::from_c2pa_error) } #[cfg(test)] diff --git a/sdk/src/asset_handlers/c2pa_io.rs b/sdk/src/asset_handlers/c2pa_io.rs index 6fc853c4f..043ab1753 100644 --- a/sdk/src/asset_handlers/c2pa_io.rs +++ b/sdk/src/asset_handlers/c2pa_io.rs @@ -171,9 +171,17 @@ pub mod tests { .save_cai_store(&temp_path, &manifest) .expect("save cai store"); - let store = Store::load_from_asset( - &temp_path, - false, + let mut temp_file = std::fs::File::open(&temp_path).expect("open temp file"); + let manifest_2 = c2pa_io.read_cai(&mut temp_file).expect("read cai store"); + + assert_eq!(&manifest, &manifest_2); + // validate against our source stream and the saved / loaded manifest + let stream = std::fs::File::open(&path).expect("open temp file"); + let store = Store::from_manifest_data_and_stream( + &manifest, + "image/jpeg", + &stream, + true, &mut StatusTracker::with_error_behavior(ErrorBehavior::StopOnFirstError), ) .expect("loading store"); diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs index 3dad9c0d5..73cc3e7fc 100644 --- a/sdk/src/ingredient.rs +++ b/sdk/src/ingredient.rs @@ -867,7 +867,6 @@ impl Ingredient { let mut validation_log = StatusTracker::default(); // retrieve the manifest bytes from embedded, sidecar or remote and convert to store if found - //let jumbf_stream = Store::load_jumbf_from_stream(format, stream); let jumbf_result = match self.manifest_data() { Some(data) => Ok(data.into_owned()), None => Store::load_jumbf_from_stream(format, stream), @@ -876,26 +875,13 @@ impl Ingredient { // We can't use functional combinators since we can't use async callbacks (https://github.com/rust-lang/rust/issues/62290) let (result, manifest_bytes) = match jumbf_result { Ok(manifest_bytes) => { - let jumbf_store = Store::from_jumbf(&manifest_bytes, &mut validation_log); - let result = match jumbf_store { - Ok(mut store) => { - if _sync { - match store.verify_from_stream(stream, format, &mut validation_log) { - Ok(_) => Ok(store), - Err(err) => Err(err), - } - } else { - match store - .verify_from_stream_async(stream, format, &mut validation_log) - .await - { - Ok(_) => Ok(store), - Err(err) => Err(err), - } - } - } - Err(e) => Err(e), - }; + let result = Store::from_manifest_data_and_stream( + &manifest_bytes, + format, + &mut *stream, + true, + &mut validation_log, + ); (result, Some(manifest_bytes)) } Err(err) => (Err(err), None), diff --git a/sdk/src/jumbf_io.rs b/sdk/src/jumbf_io.rs index b03d8f4b9..39ea5ec24 100644 --- a/sdk/src/jumbf_io.rs +++ b/sdk/src/jumbf_io.rs @@ -253,7 +253,7 @@ pub fn save_jumbf_to_file, P2: AsRef>( /// search_bytes - bytes to be replaced /// replace_bytes - replacement bytes /// returns the location where splice occurred -#[cfg(test)] // this only used in unit tests +#[cfg(feature = "v1_api")] // this only used in Store unit tests, update this when those tests are updated #[cfg(feature = "file_io")] pub(crate) fn update_file_jumbf( out_path: &Path, diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 6cedc732f..e95e17f16 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1800,6 +1800,7 @@ pub(crate) mod tests { #[test] #[cfg(feature = "file_io")] + #[cfg(feature = "v1_api")] #[allow(deprecated)] fn test_redaction() { const ASSERTION_LABEL: &str = "stds.schema-org.CreativeWork"; diff --git a/sdk/src/manifest_store.rs b/sdk/src/manifest_store.rs index ac4c442ed..fc2eb706c 100644 --- a/sdk/src/manifest_store.rs +++ b/sdk/src/manifest_store.rs @@ -290,25 +290,8 @@ impl ManifestStore { ) -> Result { let mut validation_log = StatusTracker::default(); - let manifest_bytes = Store::load_jumbf_from_stream(format, &mut stream)?; - let store = Store::from_jumbf(&manifest_bytes, &mut validation_log)?; - if verify { - // verify store and claims - if _sync { - Store::verify_store( - &store, - &mut ClaimAssetData::Stream(&mut stream, format), - &mut validation_log, - )?; - } else { - Store::verify_store_async( - &store, - &mut ClaimAssetData::Stream(&mut stream, format), - &mut validation_log, - ) - .await?; - } - } + let store = Store::from_stream(format, &mut stream, verify, &mut validation_log)?; + Ok(Self::from_store(store, &validation_log)) } diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 64e87ee4a..d37c066c3 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -125,13 +125,16 @@ impl Reader { /// ``` #[async_generic()] pub fn from_stream(format: &str, mut stream: impl Read + Seek + Send) -> Result { - let manifest_bytes = Store::load_jumbf_from_stream(format, &mut stream)?; + let verify = get_settings_value::("verify.verify_after_reading")?; // defaults to true + let mut validation_log = StatusTracker::default(); - if _sync { - Self::from_manifest_data_and_stream(&manifest_bytes, format, &mut stream) + let store = if _sync { + Store::from_stream(format, &mut stream, verify, &mut validation_log) } else { - Self::from_manifest_data_and_stream_async(&manifest_bytes, format, &mut stream).await - } + Store::from_stream_async(format, &mut stream, verify, &mut validation_log).await + }?; + + Self::from_store(store, &validation_log) } #[cfg(feature = "file_io")] @@ -210,23 +213,30 @@ impl Reader { pub fn from_manifest_data_and_stream( c2pa_data: &[u8], format: &str, - mut stream: impl Read + Seek + Send, + stream: impl Read + Seek + Send, ) -> Result { let mut validation_log = StatusTracker::default(); - // first we convert the JUMBF into a usable store - let store = Store::from_jumbf(c2pa_data, &mut validation_log)?; - let verify = get_settings_value::("verify.verify_after_reading")?; // defaults to true - if verify { - let mut asset_data = ClaimAssetData::Stream(&mut stream, format); - if _sync { - Store::verify_store(&store, &mut asset_data, &mut validation_log) - } else { - Store::verify_store_async(&store, &mut asset_data, &mut validation_log).await - }?; - } + let store = if _sync { + Store::from_manifest_data_and_stream( + c2pa_data, + format, + stream, + verify, + &mut validation_log, + ) + } else { + Store::from_manifest_data_and_stream_async( + c2pa_data, + format, + stream, + verify, + &mut validation_log, + ) + .await + }?; Self::from_store(store, &validation_log) } diff --git a/sdk/src/store.rs b/sdk/src/store.rs index 258cdf353..e8820c856 100644 --- a/sdk/src/store.rs +++ b/sdk/src/store.rs @@ -3272,30 +3272,6 @@ impl Store { ) } - // verify from a buffer without file i/o - #[async_generic()] - pub fn verify_from_stream( - &mut self, - reader: &mut dyn CAIRead, - asset_type: &str, - validation_log: &mut StatusTracker, - ) -> Result<()> { - if _sync { - Store::verify_store( - self, - &mut ClaimAssetData::Stream(reader, asset_type), - validation_log, - ) - } else { - Store::verify_store_async( - self, - &mut ClaimAssetData::Stream(reader, asset_type), - validation_log, - ) - .await - } - } - // fetch remote manifest if possible #[cfg(all(feature = "fetch_remote_manifests", not(target_os = "wasi")))] fn fetch_remote_manifest(url: &str) -> Result> { @@ -3601,6 +3577,61 @@ impl Store { } } + /// Load store from a stream + #[async_generic] + pub fn from_stream( + format: &str, + mut stream: impl Read + Seek + Send, + verify: bool, + validation_log: &mut StatusTracker, + ) -> Result { + let manifest_bytes = Store::load_jumbf_from_stream(format, &mut stream)?; + + if _sync { + Self::from_manifest_data_and_stream( + &manifest_bytes, + format, + &mut stream, + verify, + validation_log, + ) + } else { + Self::from_manifest_data_and_stream_async( + &manifest_bytes, + format, + &mut stream, + verify, + validation_log, + ) + .await + } + } + + /// Load store from a manifest data and stream + #[async_generic()] + pub fn from_manifest_data_and_stream( + c2pa_data: &[u8], + format: &str, + mut stream: impl Read + Seek + Send, + verify: bool, + validation_log: &mut StatusTracker, + ) -> Result { + // first we convert the JUMBF into a usable store + let store = Store::from_jumbf(c2pa_data, validation_log)?; + + //let verify = get_settings_value::("verify.verify_after_reading")?; // defaults to true + + if verify { + let mut asset_data = ClaimAssetData::Stream(&mut stream, format); + if _sync { + Store::verify_store(&store, &mut asset_data, validation_log) + } else { + Store::verify_store_async(&store, &mut asset_data, validation_log).await + }?; + } + Ok(store) + } + /// Load Store from a in-memory asset /// asset_type: asset extension or mime type /// data: reference to bytes of the the file @@ -3892,6 +3923,7 @@ pub enum InvalidClaimError { } #[cfg(test)] +#[cfg(feature = "v1_api")] // only test for v1_api until we update these tests #[cfg(feature = "file_io")] pub mod tests { #![allow(clippy::expect_used)] @@ -3902,19 +3934,24 @@ pub mod tests { use memchr::memmem; use serde::Serialize; - use sha2::{Digest, Sha256}; + use sha2::Digest; + #[cfg(feature = "file_io")] + use sha2::Sha256; use super::*; + #[cfg(all(feature = "file_io", feature = "v1_api"))] + use crate::jumbf_io::update_file_jumbf; use crate::{ assertion::AssertionJson, assertions::{labels::BOX_HASH, Action, Actions, BoxHash, Uuid}, claim::AssertionStoreJsonFormat, crypto::raw_signature::SigningAlg, hashed_uri::HashedUri, - jumbf_io::{get_assetio_handler_from_path, update_file_jumbf}, + jumbf_io::get_assetio_handler_from_path, status_tracker::{LogItem, StatusTracker}, utils::{ hash_utils::Hasher, + io_utils::tempdirectory, patch::patch_file, test::{ create_test_claim, fixture_path, temp_dir_path, temp_fixture_path, @@ -5492,11 +5529,21 @@ pub mod tests { let mut report = StatusTracker::default(); - let output_data = output_stream.into_inner(); + output_stream.set_position(0); - // can we read back in - let _new_store = Store::load_from_memory("mp4", &output_data, true, &mut report).unwrap(); + let manifest_bytes = Store::load_jumbf_from_stream("video/mp4", &mut input_stream).unwrap(); + let _new_store = { + Store::from_manifest_data_and_stream( + &manifest_bytes, + "video/mp4", + &mut output_stream, + false, + &mut report, + ) + .unwrap() + }; + println!("report = {report:?}"); assert!(!report.has_any_error()); } @@ -5719,12 +5766,12 @@ pub mod tests { // compare returned to external assert_eq!(saved_manifest, loaded_manifest); - // Load the exported file into a buffer - let file_buffer = std::fs::read(&op).unwrap(); + // Open the exported file + let file = std::fs::File::open(&op).unwrap(); let mut validation_log = StatusTracker::with_error_behavior(ErrorBehavior::StopOnFirstError); - let result = Store::load_from_memory("png", &file_buffer, true, &mut validation_log); + let result = Store::from_stream("png", &file, false, &mut validation_log); assert!(result.is_err()); @@ -6579,7 +6626,7 @@ pub mod tests { store.commit_claim(claim1).unwrap(); - let mut result: Vec = Vec::new(); + let result: Vec = Vec::new(); let mut result_stream = Cursor::new(result); store @@ -6587,15 +6634,16 @@ pub mod tests { .await .unwrap(); - // convert our cursor back into a buffer - result = result_stream.into_inner(); + result_stream.rewind().unwrap(); // make sure we can read from new file let mut report = StatusTracker::default(); - let new_store = Store::load_from_memory("jpeg", &result, false, &mut report).unwrap(); + let new_store = Store::from_stream("jpeg", &mut result_stream, true, &mut report).unwrap(); println!("new_store: {}", new_store); + let result = result_stream.into_inner(); + Store::verify_store_async( &new_store, &mut ClaimAssetData::Bytes(&result, "jpg"), @@ -6692,7 +6740,7 @@ pub mod tests { "mp4", &mut init_stream, &output_fragments, - true, + false, &mut validation_log, ) .unwrap(); diff --git a/sdk/src/utils/test_signer.rs b/sdk/src/utils/test_signer.rs index 3b0ee5d62..8114f52c2 100644 --- a/sdk/src/utils/test_signer.rs +++ b/sdk/src/utils/test_signer.rs @@ -33,7 +33,7 @@ pub(crate) fn test_signer(alg: SigningAlg) -> Box { )) } -#[cfg(feature = "file_io")] // only used in file_io tests currently +#[cfg(feature = "v1_api")] // this only used in Store unit tests, update this when those tests are updated /// Creates a [`Signer`] instance for testing purposes using test credentials. pub(crate) fn test_cawg_signer( alg: SigningAlg, From 83aaaec7784be25db8d25973f2e6cfa578f97799 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Thu, 22 May 2025 13:57:27 -0700 Subject: [PATCH 26/29] chore: clear warning --- sdk/src/jumbf_io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/jumbf_io.rs b/sdk/src/jumbf_io.rs index 39ea5ec24..b2a144f82 100644 --- a/sdk/src/jumbf_io.rs +++ b/sdk/src/jumbf_io.rs @@ -253,7 +253,7 @@ pub fn save_jumbf_to_file, P2: AsRef>( /// search_bytes - bytes to be replaced /// replace_bytes - replacement bytes /// returns the location where splice occurred -#[cfg(feature = "v1_api")] // this only used in Store unit tests, update this when those tests are updated +#[allow(dead_code)] // this only used in Store unit tests, update this when those tests are updated #[cfg(feature = "file_io")] pub(crate) fn update_file_jumbf( out_path: &Path, From 1758b1af721a239020a53e303a03d36bbab07be3 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 22 May 2025 20:23:17 -0400 Subject: [PATCH 27/29] fix: Fix CI. Now that `json_api` has been removed the WASI test isn't as different. --- .github/workflows/ci.yml | 5 +---- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bd18001d..1eca86188 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,6 @@ jobs: outputs: rust-native-features: ${{ steps.get-features.outputs.rust-native-features }} openssl-features: ${{ steps.get-features.outputs.openssl-features }} - wasi-features: ${{ steps.get-features.outputs.wasi-features }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -37,10 +36,8 @@ jobs: FEATURES=$(cargo metadata --format-version=1 | jq -r '[.packages[] | select(.name=="c2pa" or .name=="c2pa-c") | .features | keys | map(select(. != "default")) | .[]] | unique | join(" ")') RUST_NATIVE_FEATURES=$(echo $FEATURES | sed 's/openssl//g') OPENSSL_FEATURES=$(echo $FEATURES | sed 's/rust_native_crypto//g') - WASI_FEATURES=$(echo $RUST_NATIVE_FEATURES | sed 's/json_api//g') echo "rust-native-features=$RUST_NATIVE_FEATURES" >> "$GITHUB_OUTPUT" echo "openssl-features=$OPENSSL_FEATURES" >> "$GITHUB_OUTPUT" - echo "wasi-features=$WASI_FEATURES" >> "$GITHUB_OUTPUT" tests: name: Unit tests @@ -379,7 +376,7 @@ jobs: CC: /opt/wasi-sdk/bin/clang WASI_SDK_PATH: /opt/wasi-sdk RUST_MIN_STACK: 16777216 - FEATURES: ${{needs.get-features.outputs.wasi-features}} + FEATURES: ${{needs.get-features.outputs.rust-native-features}} run: | cargo +nightly-2025-05-14 test --target wasm32-wasip2 -p c2pa -p c2patool --features "$FEATURES" --no-default-features diff --git a/Cargo.toml b/Cargo.toml index b898f59a6..e2069dc18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ version = "0.51.1" [workspace.dependencies] -c2pa = { path = "sdk", default-features = true } +c2pa = { path = "sdk", default-features = false } [profile.release] strip = true # Automatically strip symbols from the binary. From 88f60f6f6d1884978af70a54cbd940d9b288e92e Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 22 May 2025 20:50:18 -0400 Subject: [PATCH 28/29] fix: remove c2pa-c from ci job feature selection. All features are now named in c2pa crate. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1eca86188..dec07474b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: - name: Get all features id: get-features run: | - FEATURES=$(cargo metadata --format-version=1 | jq -r '[.packages[] | select(.name=="c2pa" or .name=="c2pa-c") | .features | keys | map(select(. != "default")) | .[]] | unique | join(" ")') + FEATURES=$(cargo metadata --format-version=1 | jq -r '[.packages[] | select(.name=="c2pa") | .features | keys | map(select(. != "default")) | .[]] | unique | join(" ")') RUST_NATIVE_FEATURES=$(echo $FEATURES | sed 's/openssl//g') OPENSSL_FEATURES=$(echo $FEATURES | sed 's/rust_native_crypto//g') echo "rust-native-features=$RUST_NATIVE_FEATURES" >> "$GITHUB_OUTPUT" From 3ed5f01ac3f9fe43806c2fb2eff1bcf2037a1660 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Thu, 22 May 2025 18:33:26 -0700 Subject: [PATCH 29/29] build: fix the make release workflow --- Cargo.lock | 2 +- c_api/Makefile | 17 +++++++++-------- cli/Cargo.toml | 10 +--------- export_schema/Cargo.toml | 7 +------ make_test_images/Cargo.toml | 9 --------- setup-rust-openssl.ps1 | 10 ++++++++++ 6 files changed, 22 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c1b5a3a3..68936338c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1575,7 +1575,7 @@ dependencies = [ [[package]] name = "export_schema" -version = "0.36.1" +version = "0.51.1" dependencies = [ "anyhow", "c2pa", diff --git a/c_api/Makefile b/c_api/Makefile index 7947a7f4b..36cab05b4 100644 --- a/c_api/Makefile +++ b/c_api/Makefile @@ -18,6 +18,8 @@ endif TARGET_DIR := ../target +CARGO_BUILD_FLAGS = --release --no-default-features --features "rust_native_crypto, file_io" + # Helper function to create a zip file define make_zip set -e; \ @@ -54,24 +56,23 @@ fmt: release-win-x86_64: rustup update stable-msvc rustup target add x86_64-pc-windows-msvc - cargo build --target=x86_64-pc-windows-msvc --release --no-default-features --features "rust_native_crypto, file_io" - cargo test --target=x86_64-pc-windows-msvc --release ---no-default-features --features "rust_native_crypto, file_io" -# powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 + cargo build --target=x86_64-pc-windows-msvc $(CARGO_BUILD_FLAGS) + release-win-aarch64: rustup update stable-msvc rustup target add aarch64-pc-windows-msvc - cargo build --target=aarch64-pc-windows-msvc --release + cargo build --target=aarch64-pc-windows-msvc $(CARGO_BUILD_FLAGS) # powershell -ExecutionPolicy Bypass -File ../../setup-rust-openssl.ps1 release-mac-arm: rustup target add aarch64-apple-darwin - MACOSX_DEPLOYMENT_TARGET=11.1 cargo build --target=aarch64-apple-darwin --release + MACOSX_DEPLOYMENT_TARGET=11.1 cargo build --target=aarch64-apple-darwin $(CARGO_BUILD_FLAGS) install_name_tool -id @rpath/libc2pa_c.dylib $(TARGET_DIR)/aarch64-apple-darwin/release/libc2pa_c.dylib release-mac-x86: rustup target add x86_64-apple-darwin - MACOSX_DEPLOYMENT_TARGET=10.15 cargo build --target=x86_64-apple-darwin --release + MACOSX_DEPLOYMENT_TARGET=10.15 cargo build --target=x86_64-apple-darwin $(CARGO_BUILD_FLAGS) install_name_tool -id @rpath/libc2pa_c.dylib $(TARGET_DIR)/x86_64-apple-darwin/release/libc2pa_c.dylib release-mac-universal: release-mac-arm release-mac-x86 @@ -98,12 +99,12 @@ release-mac-universal: release-mac-arm release-mac-x86 release-linux-gnu-x86: rustup target add x86_64-unknown-linux-gnu - cargo build --target=x86_64-unknown-linux-gnu --release + cargo build --target=x86_64-unknown-linux-gnu $(CARGO_BUILD_FLAGS) @$(call make_zip,$(TARGET_DIR)/x86_64-unknown-linux-gnu/release,x86_64-unknown-linux-gnu) release-linux-gnu-arm: rustup target add aarch64-unknown-linux-gnu - cargo build --target=aarch64-unknown-linux-gnu --release + cargo build --target=aarch64-unknown-linux-gnu $(CARGO_BUILD_FLAGS) @$(call make_zip,$(TARGET_DIR)/aarch64-unknown-linux-gnu/release,aarch64-unknown-linux-gnu) # make release diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0dc542fd1..73574f687 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,11 +15,6 @@ edition = "2018" homepage = "https://contentauthenticity.org" repository = "https://github.com/contentauth/c2pa-rs/tree/main/cli" -[features] -default = ["openssl"] -openssl = ["c2pa/openssl"] -rust_native_crypto = ["c2pa/rust_native_crypto"] - [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } # Workaround for https://github.com/est31/cargo-udeps/issues/293. @@ -27,9 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } [dependencies] anyhow = "1.0" atree = "0.5.2" - c2pa = { workspace = true , features = [ - "fetch_remote_manifests", "file_io", "add_thumbnails", @@ -64,5 +57,4 @@ assert_cmd = "2.0.14" httpmock = "0.7.0" predicates = "3.1" -[package.metadata.binstall] -# Use defaults + diff --git a/export_schema/Cargo.toml b/export_schema/Cargo.toml index 7b1f2a21e..22380d234 100644 --- a/export_schema/Cargo.toml +++ b/export_schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "export_schema" -version = "0.36.1" +version.workspace = true authors = ["Dave Kozma "] license = "MIT OR Apache-2.0" edition = "2018" @@ -10,11 +10,6 @@ rust-version = "1.82.0" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } # Workaround for https://github.com/est31/cargo-udeps/issues/293. -[features] -default = ["openssl"] -openssl = ["c2pa/openssl"] -rust_native_crypto = ["c2pa/rust_native_crypto"] - [dependencies] anyhow = "1.0.40" c2pa = { path = "../sdk", features = ["json_schema"], default-features = false } diff --git a/make_test_images/Cargo.toml b/make_test_images/Cargo.toml index 67d7582f9..e7b0d18ad 100644 --- a/make_test_images/Cargo.toml +++ b/make_test_images/Cargo.toml @@ -10,10 +10,6 @@ rust-version = "1.82.0" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } # Workaround for https://github.com/est31/cargo-udeps/issues/293. -[[bin]] -name = "make_test_images" -required-features = ["default"] - [dependencies] anyhow = "1.0.40" c2pa = { workspace = true } @@ -30,8 +26,3 @@ serde = "1.0.197" serde_json = { version = "1.0.117", features = ["preserve_order"] } tempfile = "3.15.0" -[features] -# prevents these features from being always enabled in the workspace -default = ["c2pa/file_io", "openssl"] -openssl = ["c2pa/openssl"] -rust_native_crypto = ["c2pa/rust_native_crypto"] diff --git a/setup-rust-openssl.ps1 b/setup-rust-openssl.ps1 index 61e3941ca..abb09d9af 100644 --- a/setup-rust-openssl.ps1 +++ b/setup-rust-openssl.ps1 @@ -60,6 +60,16 @@ try { [Environment]::SetEnvironmentVariable($name, $value, [EnvironmentVariableTarget]::Process) } } + + # Add LLVM (clang) to PATH (Ring requires this) + $llvmBin = "C:\Program Files\LLVM\bin" + if (Test-Path $llvmBin) { + Write-Host "Adding LLVM (clang) to PATH: $llvmBin" + $env:PATH = "$llvmBin;$env:PATH" + [Environment]::SetEnvironmentVariable("PATH", "$llvmBin;$([Environment]::GetEnvironmentVariable('PATH', [EnvironmentVariableTarget]::User))", [EnvironmentVariableTarget]::User) + } else { + Write-Host "Warning: LLVM (clang) not found at $llvmBin" + } # Configure and build OpenSSL Write-Host "Configuring and building OpenSSL..."