Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions .github/scripts/stage-native-runtime-unix.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -ne 3 ]]; then
echo "usage: $0 <linux|macos> <classifier> <main-lib>" >&2
exit 1
fi

platform="$1"
classifier="$2"
main_lib="$3"

repo_root="$(pwd)"
native_dir="$repo_root/native/$classifier"
licenses_dir="$native_dir/licenses"

mkdir -p "$native_dir" "$licenses_dir"

cp "$repo_root/LICENSE" "$licenses_dir/LGPL-3.0.txt"
cp "$repo_root/THIRD_PARTY_NOTICES.md" "$licenses_dir/THIRD_PARTY_NOTICES.md"

if compgen -G "$repo_root/build/native/lib/*" > /dev/null; then
cp "$repo_root"/build/native/lib/* "$native_dir"/
fi

copy_if_exists() {
local source_path="$1"
local target_path="${2:-$native_dir/$(basename "$source_path")}"
if [[ -n "$source_path" && -f "$source_path" ]]; then
cp -L "$source_path" "$target_path"
fi
}

copy_notice_if_exists() {
local source_path="$1"
local target_name="$2"
if [[ -n "$source_path" && -f "$source_path" ]]; then
cp -L "$source_path" "$licenses_dir/$target_name"
fi
}

stage_linux_runtime() {
mapfile -t runtime_deps < <(
ldd "$native_dir/$main_lib" |
awk '/=> \// { print $3 }' |
grep -E '/lib(gmp|mpfr)\.so'
)

for dep in "${runtime_deps[@]}"; do
copy_if_exists "$dep"
done

copy_notice_if_exists "/usr/share/common-licenses/LGPL-3" "LGPL-3.0-system-copy.txt"
copy_notice_if_exists "/usr/share/doc/libgmp10/copyright" "gmp-copyright.txt"
copy_notice_if_exists "/usr/share/doc/libmpfr6/copyright" "mpfr-copyright.txt"
}

stage_macos_runtime() {
local main_lib_path="$native_dir/$main_lib"
local gmp_ref
local mpfr_ref
local gmp_name
local mpfr_name
local mpfr_lib_path
local mpfr_gmp_ref
local gmp_prefix
local mpfr_prefix

gmp_ref="$(otool -L "$main_lib_path" | awk '/libgmp.*\.dylib/ { print $1; exit }')"
mpfr_ref="$(otool -L "$main_lib_path" | awk '/libmpfr.*\.dylib/ { print $1; exit }')"

if [[ -z "$gmp_ref" ]]; then
gmp_prefix="$(brew --prefix gmp)"
gmp_ref="$(find -L "$gmp_prefix/lib" -maxdepth 1 -type f -name 'libgmp*.dylib' | sort | head -n1)"
fi
if [[ -z "$mpfr_ref" ]]; then
mpfr_prefix="$(brew --prefix mpfr)"
mpfr_ref="$(find -L "$mpfr_prefix/lib" -maxdepth 1 -type f -name 'libmpfr*.dylib' | sort | head -n1)"
fi

if [[ -z "$gmp_ref" || -z "$mpfr_ref" ]]; then
echo "failed to resolve macOS GMP/MPFR runtime libraries" >&2
exit 1
fi

copy_if_exists "$gmp_ref"
copy_if_exists "$mpfr_ref"

gmp_name="$(basename "$gmp_ref")"
mpfr_name="$(basename "$mpfr_ref")"

install_name_tool -id "@loader_path/$gmp_name" "$native_dir/$gmp_name"
install_name_tool -id "@loader_path/$mpfr_name" "$native_dir/$mpfr_name"

if otool -L "$main_lib_path" | grep -Fq "$gmp_ref"; then
install_name_tool -change "$gmp_ref" "@loader_path/$gmp_name" "$main_lib_path"
fi
if otool -L "$main_lib_path" | grep -Fq "$mpfr_ref"; then
install_name_tool -change "$mpfr_ref" "@loader_path/$mpfr_name" "$main_lib_path"
fi

mpfr_lib_path="$native_dir/$mpfr_name"
mpfr_gmp_ref="$(otool -L "$mpfr_lib_path" | awk '/libgmp.*\.dylib/ { print $1; exit }')"
if [[ -n "$mpfr_gmp_ref" && "$mpfr_gmp_ref" != "@loader_path/$gmp_name" ]]; then
install_name_tool -change "$mpfr_gmp_ref" "@loader_path/$gmp_name" "$mpfr_lib_path"
fi

gmp_prefix="$(brew --prefix gmp)"
mpfr_prefix="$(brew --prefix mpfr)"

copy_notice_if_exists "$(find "$gmp_prefix" -path '*/share/doc/*' -type f \( -iname 'COPYING*' -o -iname 'LICENSE*' \) | sort | head -n1)" "gmp-license.txt"
copy_notice_if_exists "$(find "$mpfr_prefix" -path '*/share/doc/*' -type f \( -iname 'COPYING*' -o -iname 'LICENSE*' \) | sort | head -n1)" "mpfr-license.txt"
}

case "$platform" in
linux)
stage_linux_runtime
;;
macos)
stage_macos_runtime
;;
*)
echo "unsupported platform: $platform" >&2
exit 1
;;
esac

ls -la "$native_dir"
112 changes: 112 additions & 0 deletions .github/scripts/stage-native-runtime-windows.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
param(
[Parameter(Mandatory = $true)]
[string]$Label,
[string]$Triplet = ""
)

$ErrorActionPreference = "Stop"

$repoRoot = (Get-Location).Path
$nativeDir = Join-Path $repoRoot "native\$Label"
$licensesDir = Join-Path $nativeDir "licenses"

New-Item -ItemType Directory -Force -Path $nativeDir, $licensesDir | Out-Null

if (Test-Path (Join-Path $repoRoot "build\native\lib")) {
Copy-Item -Path (Join-Path $repoRoot "build\native\lib\*") -Destination $nativeDir -Force
}

Copy-Item -Path (Join-Path $repoRoot "LICENSE") -Destination (Join-Path $licensesDir "LGPL-3.0.txt") -Force
Copy-Item -Path (Join-Path $repoRoot "THIRD_PARTY_NOTICES.md") -Destination (Join-Path $licensesDir "THIRD_PARTY_NOTICES.md") -Force

function Find-FirstFile {
param(
[string[]]$Roots,
[string[]]$Names,
[string]$ArchHint = ""
)

foreach ($root in $Roots) {
if ([string]::IsNullOrWhiteSpace($root) -or -not (Test-Path $root)) {
continue
}
$candidate = Get-ChildItem -Path $root -Recurse -File -ErrorAction SilentlyContinue |
Where-Object {
$Names -contains $_.Name -and
([string]::IsNullOrWhiteSpace($ArchHint) -or $_.FullName.ToLowerInvariant().Contains($ArchHint.ToLowerInvariant()))
} |
Select-Object -First 1
if ($candidate) {
return $candidate.FullName
}
}
return $null
}

if ($Label -eq "windows-x86-64") {
$compilerDir = if ($env:CXX) { Split-Path -Parent $env:CXX } else { $null }
$licenseRoots = @()
if ($compilerDir) {
$licenseRoots += Join-Path $compilerDir "..\share\licenses"
$licenseRoots += Join-Path $compilerDir "..\..\share\licenses"
}
$licenseRoots += @(
"C:\mingw64\share\licenses",
"C:\msys64\mingw64\share\licenses",
"C:\Program Files\Git\mingw64\share\licenses"
)

$gccRuntimeNotice = Find-FirstFile -Roots $licenseRoots -Names @("COPYING.RUNTIME")
if ($gccRuntimeNotice) {
Copy-Item -Path $gccRuntimeNotice -Destination (Join-Path $licensesDir "COPYING.RUNTIME.txt") -Force
}

$winpthreadNotice = Get-ChildItem -Path $licenseRoots -Recurse -File -ErrorAction SilentlyContinue |
Where-Object {
$_.FullName -match "winpthread|winpthreads" -and
($_.Name -eq "COPYING.winpthreads" -or $_.Name -eq "COPYING")
} |
Select-Object -First 1
if ($winpthreadNotice) {
Copy-Item -Path $winpthreadNotice.FullName -Destination (Join-Path $licensesDir "COPYING.winpthreads.txt") -Force
}
}

if ($Label -eq "windows-aarch64") {
$redistRoots = @()
if ($env:VCToolsRedistDir) {
$redistRoots += $env:VCToolsRedistDir
}
if ($env:VCINSTALLDIR) {
$redistRoots += Join-Path $env:VCINSTALLDIR "Redist\MSVC"
}
$redistRoots += @(
"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Redist\MSVC",
"C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Redist\MSVC",
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Redist\MSVC",
"C:\Program Files (x86)\Microsoft Visual Studio\Installer\Feedback\arm64"
)

foreach ($dllName in @("msvcp140.dll", "vcruntime140.dll", "vcruntime140_1.dll", "concrt140.dll")) {
$dllPath = Find-FirstFile -Roots $redistRoots -Names @($dllName) -ArchHint "arm64"
if (-not $dllPath) {
$dllPath = Find-FirstFile -Roots $redistRoots -Names @($dllName)
}
if ($dllPath) {
Copy-Item -Path $dllPath -Destination (Join-Path $nativeDir $dllName) -Force
} else {
Write-Warning "Failed to locate $dllName for $Label"
}
}

@"
Microsoft Visual C++ runtime files in this directory were staged from a
Visual Studio 2022 redistributable location on the build machine.

Redistribution is governed by the Visual Studio 2022 license terms and the
official distributable code list:
https://learn.microsoft.com/en-gb/visualstudio/releases/2022/redistribution
"@ | Set-Content -Path (Join-Path $licensesDir "MICROSOFT_VISUAL_CPP_REDIST_NOTICE.txt")
}

Get-ChildItem -Recurse $nativeDir
8 changes: 5 additions & 3 deletions .github/workflows/auto-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y libgmp-dev libmpfr-dev cmake
- run: chmod +x .github/scripts/stage-native-runtime-unix.sh
- name: Build
run: |
mkdir -p build/native native/${{ matrix.label }}
cmake -S src/main/cpp -B build/native -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native
cmake --build build/native --target install -j$(nproc)
cp build/native/lib/* native/${{ matrix.label }}/
.github/scripts/stage-native-runtime-unix.sh linux ${{ matrix.label }} ${{ matrix.lib }}
echo "=== built ==="
ls -la native/${{ matrix.label }}/
file native/${{ matrix.label }}/${{ matrix.lib }}
Expand All @@ -55,12 +56,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: brew install gmp mpfr cmake
- run: chmod +x .github/scripts/stage-native-runtime-unix.sh
- name: Build
run: |
mkdir -p build/native native/${{ matrix.label }}
cmake -S src/main/cpp -B build/native -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native
cmake --build build/native --target install -j$(sysctl -n hw.ncpu)
cp build/native/lib/* native/${{ matrix.label }}/
.github/scripts/stage-native-runtime-unix.sh macos ${{ matrix.label }} ${{ matrix.lib }}
echo "=== built ==="
ls -la native/${{ matrix.label }}/
file native/${{ matrix.label }}/${{ matrix.lib }}
Expand Down Expand Up @@ -132,7 +134,7 @@ jobs:
New-Item -Force -ItemType Directory -Path build/native, "native/${{ matrix.label }}"
cmake -S src/main/cpp -B build/native -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native "-DCMAKE_PREFIX_PATH=${{ github.workspace }}/vcpkg_installed/${{ matrix.vcpkg_triplet }}"
cmake --build build/native --target install
Copy-Item build/native/lib/* "native/${{ matrix.label }}/" -Force
.github/scripts/stage-native-runtime-windows.ps1 -Label '${{ matrix.label }}' -Triplet '${{ matrix.vcpkg_triplet }}'
echo "=== built ==="
cmd /c "dir native\${{ matrix.label }}"
- uses: actions/upload-artifact@v4
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/native-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Make native staging script executable
if: runner.os != 'Windows'
run: chmod +x .github/scripts/stage-native-runtime-unix.sh
- name: Configure MSVC for Windows ARM64
if: matrix.vcpkg_triplet == 'arm64-windows'
uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -127,11 +130,18 @@ jobs:
run: |
chmod +x gradlew 2>/dev/null || true
./gradlew build -x test -Dbigmath.native.classifier=${{ matrix.label }}
if [ "${{ runner.os }}" = "Linux" ]; then
.github/scripts/stage-native-runtime-unix.sh linux ${{ matrix.label }} libbigmath_ffm.so
else
.github/scripts/stage-native-runtime-unix.sh macos ${{ matrix.label }} libbigmath_ffm.dylib
fi
shell: bash
- name: Build native
if: runner.os == 'Windows'
shell: pwsh
run: .\gradlew.bat --% build -x test -Dbigmath.native.classifier=${{ matrix.label }}
run: |
.\gradlew.bat --% build -x test -Dbigmath.native.classifier=${{ matrix.label }}
.github/scripts/stage-native-runtime-windows.ps1 -Label '${{ matrix.label }}' -Triplet '${{ matrix.vcpkg_triplet }}'

- name: Save vcpkg binary cache
if: runner.os == 'Windows' && !cancelled()
Expand All @@ -143,7 +153,7 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: native-libs-${{ matrix.label }}
path: build/generated/local-native/${{ matrix.label }}/**
path: native/${{ matrix.label }}/**
retention-days: 7

android-build:
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/publish-on-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y libgmp-dev libmpfr-dev cmake
- run: chmod +x .github/scripts/stage-native-runtime-unix.sh
- name: Build
run: |
mkdir -p build/native native/${{ matrix.label }}
cmake -S src/main/cpp -B build/native -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native
cmake --build build/native --target install -j$(nproc)
cp build/native/lib/* native/${{ matrix.label }}/
.github/scripts/stage-native-runtime-unix.sh linux ${{ matrix.label }} ${{ matrix.lib }}
- uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.label }}
Expand All @@ -72,12 +73,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: brew install gmp mpfr cmake
- run: chmod +x .github/scripts/stage-native-runtime-unix.sh
- name: Build
run: |
mkdir -p build/native native/${{ matrix.label }}
cmake -S src/main/cpp -B build/native -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native
cmake --build build/native --target install -j$(sysctl -n hw.ncpu)
cp build/native/lib/* native/${{ matrix.label }}/
.github/scripts/stage-native-runtime-unix.sh macos ${{ matrix.label }} ${{ matrix.lib }}
- uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.label }}
Expand Down Expand Up @@ -146,7 +148,7 @@ jobs:
New-Item -Force -ItemType Directory -Path build/native, "native/${{ matrix.label }}"
cmake -S src/main/cpp -B build/native -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/native "-DCMAKE_PREFIX_PATH=${{ github.workspace }}/vcpkg_installed/${{ matrix.vcpkg_triplet }}"
cmake --build build/native --target install
Copy-Item build/native/lib/* "native/${{ matrix.label }}/" -Force
.github/scripts/stage-native-runtime-windows.ps1 -Label '${{ matrix.label }}' -Triplet '${{ matrix.vcpkg_triplet }}'
- uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.label }}
Expand Down
4 changes: 4 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Relevant loading logic lives in:
| GNU libstdc++ runtime | `libstdc++-6.dll` | GPL-3.0-or-later with GCC Runtime Library Exception 3.1 | https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html |
| GNU libgcc runtime | `libgcc_s_*.dll` | GPL-3.0-or-later with GCC Runtime Library Exception 3.1 | https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html |
| MinGW-w64 winpthreads | `libwinpthread-1.dll` | Upstream `COPYING.winpthreads` notice as shipped by MinGW-w64 | https://www.mingw-w64.org/ |
| Microsoft VC++ runtime | `msvcp140.dll`, `vcruntime140*.dll`, `concrt140.dll` | Redistributable in unmodified form by licensed Visual Studio users under the Visual Studio 2022 distributable code terms | https://learn.microsoft.com/en-gb/visualstudio/releases/2022/redistribution |

### License Texts

Expand All @@ -47,6 +48,9 @@ Relevant loading logic lives in:
- If you redistribute Windows runtime DLLs built from a MinGW-w64 toolchain,
ship the originating toolchain's `COPYING.RUNTIME` and
`COPYING.winpthreads` files alongside your binary artifact.
- When native artifacts bundle third-party runtime libraries, Bigmath-FFM also
stages a per-classifier `licenses/` directory next to those binaries so the
unpacked package carries the corresponding notices with it.

### Corresponding Source

Expand Down
Loading