diff --git a/.github/workflows/eepp-linux-build-check.yml b/.github/workflows/eepp-linux-build-check.yml index 061a51850..4a56f136f 100644 --- a/.github/workflows/eepp-linux-build-check.yml +++ b/.github/workflows/eepp-linux-build-check.yml @@ -2,6 +2,9 @@ name: Linux on: [push, pull_request] +permissions: + contents: write + jobs: Linux: runs-on: ubuntu-24.04 @@ -27,6 +30,35 @@ jobs: ./premake5 --disable-static-build --with-debug-symbols gmake cd make/linux make all -j$(nproc) -e config=release_x86_64 + - name: Set SDK version + id: sdk_version + run: | + if [[ "$GITHUB_REF" == refs/tags/eepp-* ]]; then + echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + else + echo "version=nightly" >> "$GITHUB_OUTPUT" + fi + - name: Package eepp SDK + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + run: | + bash projects/scripts/package_sdk.sh linux x86_64 --strip --version ${{ steps.sdk_version.outputs.version }} + - name: Upload SDK package + if: always() + uses: actions/upload-artifact@v4 + with: + name: linux-eepp-sdk-x86_64 + path: projects/linux/sdk/eepp-sdk-*.tar.gz + - name: Publish stable release package + if: startsWith(github.ref, 'refs/tags/eepp-') + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.sdk_version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: false + fail_on_unmatched_files: true + files: | + projects/linux/sdk/eepp-sdk-linux-x86_64-*.tar.gz - name: Unit Tests run: | cd projects/scripts diff --git a/.github/workflows/eepp-macos-build-check.yml b/.github/workflows/eepp-macos-build-check.yml index 8fc72ae59..b00df8f36 100644 --- a/.github/workflows/eepp-macos-build-check.yml +++ b/.github/workflows/eepp-macos-build-check.yml @@ -2,6 +2,9 @@ name: macOS on: [push, pull_request] +permissions: + contents: write + jobs: MacOS: runs-on: macos-latest @@ -21,6 +24,36 @@ jobs: run: | premake5 --disable-static-build --with-debug-symbols gmake make -C make/macosx/ -j$(sysctl -n hw.ncpu) -e config=release_arm64 + - name: Set SDK version + id: sdk_version + run: | + if [[ "$GITHUB_REF" == refs/tags/eepp-* ]]; then + echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + else + echo "version=nightly" >> "$GITHUB_OUTPUT" + fi + - name: Package eepp SDK + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + run: | + bash projects/scripts/package_sdk.sh macos arm64 --version ${{ steps.sdk_version.outputs.version }} + - name: Upload SDK package + if: always() + uses: actions/upload-artifact@v4 + with: + name: macos-eepp-sdk-arm64 + path: projects/macos/sdk/eepp-sdk-*.tar.gz + - name: Publish stable release package + if: startsWith(github.ref, 'refs/tags/eepp-') + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.sdk_version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: false + fail_on_unmatched_files: true + files: | + projects/macos/sdk/eepp-sdk-macos-arm64-*.tar.gz + - name: Unit Tests - name: Unit Tests run: | set +e diff --git a/.github/workflows/eepp-mingw-nightly.yml b/.github/workflows/eepp-mingw-nightly.yml new file mode 100644 index 000000000..0751b8541 --- /dev/null +++ b/.github/workflows/eepp-mingw-nightly.yml @@ -0,0 +1,65 @@ +name: Windows MinGW Nightly + +on: + push: + branches: + - 'develop' + tags: + - 'eepp-*' + + workflow_dispatch: + +permissions: write-all + +jobs: + build_windows_mingw: + name: Windows x86_64 MinGW SDK + runs-on: ubuntu-24.04 + steps: + - name: Configure Git + run: | + git config --global core.autocrlf false + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ github.ref }} + fetch-depth: 2 + submodules: 'recursive' + - name: Install dependencies + run: | + sudo add-apt-repository -y universe + sudo add-apt-repository -y multiverse + sudo apt update + sudo apt install -y mingw-w64 gcc-12 g++-12 zip wget + wget https://cdn.ensoft.dev/eepp-assets/premake-5.0.0-beta6-linux.tar.gz + tar xvzf premake-5.0.0-beta6-linux.tar.gz + - name: Set SDK version + id: sdk_version + run: | + if [[ "$GITHUB_REF" == refs/tags/eepp-* ]]; then + echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + else + echo "version=nightly" >> "$GITHUB_OUTPUT" + fi + - name: Build + run: | + bash projects/mingw32/make.sh -e config=release_x86_64 -j$(nproc) + - name: Package eepp SDK + run: | + bash projects/scripts/package_sdk.sh windows x86_64 --strip --version ${{ steps.sdk_version.outputs.version }} + - name: Upload SDK package + uses: actions/upload-artifact@v4 + with: + name: windows-eepp-sdk-x86_64-mingw + path: projects/windows/sdk/eepp-sdk-*.zip + - name: Publish package + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.sdk_version.outputs.version }} + draft: false + prerelease: ${{ steps.sdk_version.outputs.version == 'nightly' }} + generate_release_notes: false + fail_on_unmatched_files: true + files: | + projects/windows/sdk/eepp-sdk-windows-x86_64-mingw-*.zip diff --git a/.github/workflows/eepp-windows-build-check.yml b/.github/workflows/eepp-windows-build-check.yml index 714aaec39..e873536d9 100644 --- a/.github/workflows/eepp-windows-build-check.yml +++ b/.github/workflows/eepp-windows-build-check.yml @@ -2,6 +2,9 @@ name: Windows on: [push, pull_request] +permissions: + contents: write + jobs: Windows: runs-on: windows-latest @@ -33,6 +36,38 @@ jobs: shell: cmd run: | msbuild .\make\windows\eepp.sln -m /p:Platform="x64" /p:Configuration="release" + - name: Set SDK version + id: sdk_version + shell: powershell + run: | + if ($env:GITHUB_REF -like "refs/tags/eepp-*") { + $tag = $env:GITHUB_REF -replace "^refs/tags/", "" + Add-Content $env:GITHUB_OUTPUT "version=$tag" + } else { + Add-Content $env:GITHUB_OUTPUT "version=nightly" + } + - name: Package eepp SDK + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + shell: powershell + run: | + .\projects\scripts\package_sdk.ps1 -Platform msvc -Version ${{ steps.sdk_version.outputs.version }} + - name: Upload SDK package + if: always() + uses: actions/upload-artifact@v4 + with: + name: windows-eepp-sdk-x86_64-msvc + path: projects\windows\sdk\eepp-sdk-*.zip + - name: Publish stable release package + if: startsWith(github.ref, 'refs/tags/eepp-') + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.sdk_version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: false + fail_on_unmatched_files: true + files: | + projects\windows\sdk\eepp-sdk-windows-x86_64-msvc-*.zip - name: Install Mesa for software rendering uses: f3d-app/install-mesa-windows-action@v1 with: diff --git a/.gitignore b/.gitignore index e7a8f5f41..e05a54a93 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,9 @@ ecode.dmg /bin/unit_tests/eepp* /bin/unit_tests/lib* /bin/unit_tests/output/* +/projects/linux/sdk/ +/projects/macos/sdk/ +/projects/windows/sdk/ /projects/linux/ecode/polyfill-glibc /bin/crashes/* /bin/config/* diff --git a/projects/scripts/eepp-sdk-README.md b/projects/scripts/eepp-sdk-README.md new file mode 100644 index 000000000..d476490b2 --- /dev/null +++ b/projects/scripts/eepp-sdk-README.md @@ -0,0 +1,53 @@ +# eepp SDK + +Self-contained snapshot of the [eepp](https://github.com/SpartanJ/eepp) framework: +runnable demos and tools, the assets they need, and the compiled libraries ready to be +linked against by your own applications. + +Version: @SDK_VERSION@ ("nightly" is a rolling build of the latest development +changes; eepp-%d.%d.%d versions are stable releases) + +## Package layout + +``` +bin/ Tools and examples/demos (release builds) +bin/assets/ Assets required by the shipped binaries +bin/ Runtime libraries co-located with the binaries +libs/// Libraries for linking against eepp +include/ Public C++ headers +docs/articles/ Framework documentation articles +``` + +## Running the demos and tools + +Every binary in `bin/` is ready to run: + +- **Windows:** double-click any `.exe`. +- **Linux:** run any binary from a file manager or a terminal, for example + `bin/ecode`. The binaries locate the shared libraries relative to their own + location (`$ORIGIN` rpath), so the package can live anywhere on disk. +- **macOS:** the shipped binaries and libraries are ad-hoc signed and resolve + their dependencies through `@loader_path`, so they can be launched straight + from Finder or a terminal. + +If the SDL2/SDL3 runtime library was not bundled next to the binaries (see +`bin/`), install it with your system package manager (for example +`libsdl2-2.0-0` on Debian/Ubuntu). + +## Linking against eepp + +Add `include/` to your include path and link against the libraries in +`libs///`: + +- Dynamic linking: link against the shared library (`eepp.dll` / `libeepp.so` / + `libeepp.dylib` and the matching import library when applicable). +- The optional modules (`eepp-maps`, `eepp-physics`) and the `eterm` / + `languages-syntax-highlighting` static libraries are also provided. + +Start with the documentation in `docs/articles/` and the sources of the shipped +examples (available in the repository under `src/examples/`) to learn the API. + +## Notes + +- These are unstable nightly builds; APIs may change at any time. +- Report issues at https://github.com/SpartanJ/eepp/issues diff --git a/projects/scripts/package_sdk.ps1 b/projects/scripts/package_sdk.ps1 new file mode 100644 index 000000000..47fdb3c56 --- /dev/null +++ b/projects/scripts/package_sdk.ps1 @@ -0,0 +1,163 @@ +# Packages the eepp SDK for Windows (MSVC and MinGW). +# +# Usage: package_sdk.ps1 [-Platform ] [-Version ] +# +# -Version accepts "nightly" (default) or a stable release tag of the form +# eepp-%d.%d.%d (the tag prefix is stripped from the package names). +# +# Expects the release build to be present in bin\ and libs\windows\x86_64 +# (see the CI workflows). Produces projects\windows\sdk\eepp-sdk-windows-x86_64--.zip. +# +# Package layout mirrors the repository root: +# bin\assets + binaries, bin\ runtime DLLs, libs\windows\x86_64\, +# include\ and docs\articles\. + +param( + [string]$Platform = "msvc", + [string]$Version = "nightly" +) + +$ErrorActionPreference = "Stop" + +$RepoRoot = (Resolve-Path "$PSScriptRoot\..\..").Path +Push-Location $RepoRoot + +try { + $Arch = "x86_64" + $SdkDirName = "eepp-sdk" + + # Stable release tags use the eepp-%d.%d.%d format; strip the tag prefix + # for the package names. Anything else must be "nightly". + if ($Version -eq "nightly") { + $ArchiveSuffix = "nightly" + } elseif ($Version -match "^eepp-\d+\.\d+\.\d+$") { + $ArchiveSuffix = $Version.Substring("eepp-".Length) + } else { + throw "Invalid version '$Version' (expected nightly or eepp-%d.%d.%d)" + } + $Staging = "projects\windows\sdk\$SdkDirName" + + if (Test-Path "projects\windows\sdk") { + Remove-Item -Recurse -Force "projects\windows\sdk" + } + New-Item -ItemType Directory -Force -Path "$Staging\bin", "$Staging\libs\windows\$Arch", "$Staging\docs" | Out-Null + + # ----------------------------------------------------------------------- + # Assets: everything except the unit-test / benchmark-only directories. + # ----------------------------------------------------------------------- + + $TestOnlyAssetDirs = @("html", "logo", "textfiles", "textformat") + $TestOnlyAssetFiles = @("test.zip") + + New-Item -ItemType Directory -Force -Path "$Staging\bin\assets" | Out-Null + + Get-ChildItem "bin\assets" | ForEach-Object { + if ($TestOnlyAssetDirs -notcontains $_.Name -and $TestOnlyAssetFiles -notcontains $_.Name) { + Copy-Item -Recurse -Path $_.FullName -Destination "$Staging\bin\assets\$($_.Name)" + } + } + + # ----------------------------------------------------------------------- + # Binaries: every release executable in bin\ is packaged (any new + # "eepp-*" binary is picked up automatically) plus the fixed tool set: + # ecode, eterm and eeiv. Unit tests live in bin\unit_tests and benchmarks + # in bin\benchmarks; they are never matched by this filter. + # ----------------------------------------------------------------------- + + function Add-Binary { + param([string]$Name) + + $Source = "bin\$Name" + if (-not (Test-Path $Source)) { + Write-Warning "Binary not found, skipping: $Source" + return + } + + Copy-Item -Path $Source -Destination "$Staging\bin\$Name" + } + + $Binaries = @(Get-ChildItem "bin" -File | Where-Object { $_.Name -like "eepp-*" } | Select-Object -ExpandProperty Name) + foreach ($Name in $Binaries) { + Add-Binary -Name $Name + } + Add-Binary -Name "ecode.exe" + Add-Binary -Name "eterm.exe" + Add-Binary -Name "eeiv.exe" + + # ----------------------------------------------------------------------- + # Libraries: shared libraries required at runtime plus the import/static + # libraries useful for linking. Release configurations only. MSVC and + # MinGW produce different import library flavors; missing files (for + # example a MinGW import library on an MSVC build) are skipped with a + # warning. + # ----------------------------------------------------------------------- + + $SharedLibs = @("eepp.dll", "eepp-maps.dll", "eepp-physics.dll") + + if ($Platform -eq "mingw") { + # MinGW import libraries (libeepp*.a, generated along with the DLLs) + # plus the statically linked modules and tools. + $LinkLibs = @( + "libeepp.a", + "libeepp-maps.a", + "libeepp-physics.a", + "libeepp-maps-static.a", + "libeepp-physics-static.a", + "libeterm.a", + "liblanguages-syntax-highlighting.a" + ) + } else { + $LinkLibs = @( + "eepp.lib", + "eepp-maps.lib", + "eepp-physics.lib", + "eepp-maps-static.lib", + "eepp-physics-static.lib", + "eterm.lib", + "languages-syntax-highlighting.lib" + ) + } + + foreach ($Lib in $SharedLibs) { + $Source = "libs\windows\$Arch\$Lib" + if (-not (Test-Path $Source)) { + Write-Warning "Library not found, skipping: $Source" + continue + } + Copy-Item -Path $Source -Destination "$Staging\bin\$Lib" + Copy-Item -Path $Source -Destination "$Staging\libs\windows\$Arch\$Lib" + } + + foreach ($Lib in $LinkLibs) { + $Source = "libs\windows\$Arch\$Lib" + if (-not (Test-Path $Source)) { + Write-Warning "Library not found, skipping: $Source" + continue + } + Copy-Item -Path $Source -Destination "$Staging\libs\windows\$Arch\$Lib" + } + + # ----------------------------------------------------------------------- + # Headers, documentation and package README. + # ----------------------------------------------------------------------- + + Copy-Item -Recurse -Path "include" -Destination "$Staging\include" + Copy-Item -Recurse -Path "docs\articles" -Destination "$Staging\docs\articles" + (Get-Content "projects\scripts\eepp-sdk-README.md" -Raw) -replace '@SDK_VERSION@', $Version | Set-Content "$Staging\README.md" + + # SDL2 runtime DLL next to the binaries. + $SdlDll = "bin\SDL2.dll" + if (Test-Path $SdlDll) { + Copy-Item -Path $SdlDll -Destination "$Staging\bin\SDL2.dll" + } + + # ----------------------------------------------------------------------- + # Zip. + # ----------------------------------------------------------------------- + + $ZipName = "eepp-sdk-windows-$Arch-$Platform-$ArchiveSuffix.zip" + Compress-Archive -LiteralPath $Staging -DestinationPath "projects\windows\sdk\$ZipName" -Force + Write-Output "Generated projects\windows\sdk\$ZipName" +} finally { + Pop-Location +} diff --git a/projects/scripts/package_sdk.sh b/projects/scripts/package_sdk.sh new file mode 100755 index 000000000..bff0460df --- /dev/null +++ b/projects/scripts/package_sdk.sh @@ -0,0 +1,424 @@ +#!/bin/bash + +# Packages the eepp SDK for Linux, macOS and MinGW (cross). +# +# Usage: ./package_sdk.sh [--strip] [--version ] +# Examples: +# ./package_sdk.sh linux x86_64 --strip +# ./package_sdk.sh macos arm64 +# ./package_sdk.sh windows x86_64 --strip (MinGW cross build) +# +# --version accepts "nightly" (default) or a stable release tag of the form +# eepp-%d.%d.%d (the tag prefix is stripped from the package names). +# +# Expects the release build to be present in bin/ and libs/ (see the CI workflows). +# Produces projects//sdk/eepp-sdk---nightly.tar.gz +# (or eepp-sdk-windows--mingw-nightly.zip for MinGW builds). +# +# Package layout mirrors the repository root: +# bin/assets + binaries, bin/ runtime libraries, libs///, +# include/ and docs/articles/. + +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "Usage: $0 [--strip] [--version ]" + exit 1 +fi + +PLATFORM="$1" +ARCH="$2" +STRIP_BINARIES=false +SDK_VERSION="nightly" +while [ $# -gt 2 ]; do + case "$3" in + --strip) + STRIP_BINARIES=true + ;; + --version) + SDK_VERSION="${4:-}" + if [ -z "$SDK_VERSION" ]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + shift + ;; + -*) + echo "Unknown option: $3" + exit 1 + ;; + esac + shift +done + +CANONPATH=$(readlink -f "$0") +DIRPATH="$(dirname "$CANONPATH")" +cd "$DIRPATH/../.." || exit 1 +ROOT="$PWD" + +SDK_DIRNAME="eepp-sdk" +STAGING="projects/$PLATFORM/sdk/$SDK_DIRNAME" + +# Repository layout name used for libs/// (premake's os.target()). +LIBS_PLATFORM="$PLATFORM" +if [ "$PLATFORM" == "macos" ]; then + LIBS_PLATFORM="macosx" +fi + +# Stable release tags use the eepp-%d.%d.%d format; strip the tag prefix for +# the package names. Anything else must be "nightly". +case "$SDK_VERSION" in + nightly) + ARCHIVE_SUFFIX="nightly" + ;; + eepp-*.*) + if ! [[ "$SDK_VERSION" =~ ^eepp-[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: invalid version '$SDK_VERSION' (expected nightly or eepp-%d.%d.%d)" >&2 + exit 1 + fi + ARCHIVE_SUFFIX="${SDK_VERSION#eepp-}" + ;; + *) + echo "Error: invalid version '$SDK_VERSION' (expected nightly or eepp-%d.%d.%d)" >&2 + exit 1 + ;; +esac + +# Strip tool: the MinGW cross build needs the binutils of the target +# toolchain; a native strip cannot handle PE binaries. +if [ "$PLATFORM" == "windows" ]; then + STRIP_CMD="x86_64-w64-mingw32-strip" + if ! command -v "$STRIP_CMD" > /dev/null 2>&1; then + echo "Warning: $STRIP_CMD not found, binaries will not be stripped" >&2 + STRIP_CMD="" + fi +else + STRIP_CMD="strip" +fi + +rm -rf "projects/$PLATFORM/sdk" +mkdir -p "$STAGING/bin" "$STAGING/libs/$LIBS_PLATFORM/$ARCH" "$STAGING/docs" + +# --------------------------------------------------------------------------- +# Assets: everything except the unit-test / benchmark-only asset directories. +# --------------------------------------------------------------------------- + +mkdir -p "$STAGING/bin/assets" + +# Directories only consumed by unit tests or benchmarks. +TEST_ONLY_ASSET_DIRS=( + html + logo + textfiles + textformat +) + +# Individual files only consumed by unit tests or benchmarks. +TEST_ONLY_ASSET_FILES=( + test.zip +) + +is_test_only() { + local rel="$1" + local entry + for entry in "${TEST_ONLY_ASSET_DIRS[@]}"; do + if [ "$rel" == "$entry" ]; then + return 0 + fi + done + for entry in "${TEST_ONLY_ASSET_FILES[@]}"; do + if [ "$rel" == "$entry" ]; then + return 0 + fi + done + return 1 +} + +for entry in bin/assets/*; do + rel="${entry#bin/assets/}" + if is_test_only "$rel"; then + continue + fi + cp -r "$entry" "$STAGING/bin/assets/" +done + +# --------------------------------------------------------------------------- +# Binaries: every release executable in bin/ is packaged (any new "eepp-*" +# binary is picked up automatically) plus the fixed tool set: ecode, eterm and +# eeiv. Unit tests and benchmarks live outside bin/ and are never matched. +# --------------------------------------------------------------------------- + +# Only accept the executable format of the target platform: prevents stale +# cross-compile artifacts (for example MinGW .exe files lying around in bin/ +# of a Linux checkout) from leaking into the wrong package. +is_executable() { + case "$PLATFORM" in + macos) + case "$(file -b "$1")" in + Mach-O*) return 0 ;; + esac + ;; + windows) + case "$(file -b "$1")" in + *PE32*) return 0 ;; + esac + ;; + *) + case "$(file -b "$1")" in + ELF*) return 0 ;; + esac + ;; + esac + return 1 +} + +copy_binary() { + local src="$1" + + if [ ! -f "$src" ]; then + echo "Warning: binary not found, skipping: $src" >&2 + return 0 + fi + + if ! is_executable "$src"; then + return 0 + fi + + cp "$src" "$STAGING/bin/" + if [ "$STRIP_BINARIES" = true ] && [ -n "$STRIP_CMD" ]; then + "$STRIP_CMD" "$STAGING/bin/$(basename "$src")" + fi +} + +for entry in bin/eepp-*; do + [ -e "$entry" ] || continue + case "$entry" in + *-debug | *.dll | *.so | *.dylib | *.a | *.data | *.html | *.js | *.wasm) + continue + ;; + esac + copy_binary "$entry" +done + +if [ "$PLATFORM" == "windows" ]; then + copy_binary bin/ecode.exe + copy_binary bin/eterm.exe + copy_binary bin/eeiv.exe +else + copy_binary bin/ecode + copy_binary bin/eterm + copy_binary bin/eeiv +fi + +# --------------------------------------------------------------------------- +# Libraries: shared libraries required at runtime plus the static libraries +# useful for linking. Release configurations only ("*-debug*" is skipped). +# --------------------------------------------------------------------------- + +LIBS_SRC="libs/$LIBS_PLATFORM/$ARCH" +if [ ! -d "$LIBS_SRC" ]; then + LIBS_SRC="libs/$LIBS_PLATFORM" +fi + +if [ "$PLATFORM" == "macos" ]; then + SHARED_LIBS=(libeepp.dylib libeepp-maps.dylib libeepp-physics.dylib) + STATIC_LIBS=( + libeepp-maps-static.a + libeepp-physics-static.a + libeterm.a + liblanguages-syntax-highlighting.a + ) +elif [ "$PLATFORM" == "windows" ]; then + SHARED_LIBS=(eepp.dll eepp-maps.dll eepp-physics.dll) + # MinGW import libraries (libeepp*.a, generated along with the DLLs) plus + # the statically linked modules and tools. + STATIC_LIBS=( + libeepp.a + libeepp-maps.a + libeepp-physics.a + libeepp-maps-static.a + libeepp-physics-static.a + libeterm.a + liblanguages-syntax-highlighting.a + ) +else + SHARED_LIBS=(libeepp.so libeepp-maps.so libeepp-physics.so) + STATIC_LIBS=( + libeepp-maps-static.a + libeepp-physics-static.a + libeterm.a + liblanguages-syntax-highlighting.a + ) +fi + +copy_lib() { + local src="$1" + local dest_dir="$2" + local name + name="$(basename "$src")" + + if [ ! -f "$src" ]; then + echo "Warning: library not found, skipping: $src" >&2 + return 0 + fi + + cp -L "$src" "$dest_dir/" + if [ "$STRIP_BINARIES" = true ]; then + case "$name" in + *.a) + # Static archives only tolerate debug-symbol stripping: a full + # strip corrupts the archive's object members. + case "$PLATFORM" in + macos) + strip -S "$dest_dir/$name" 2>/dev/null || true + ;; + windows) + [ -n "$STRIP_CMD" ] && "$STRIP_CMD" -g "$dest_dir/$name" 2>/dev/null || true + ;; + *) + "$STRIP_CMD" --strip-debug "$dest_dir/$name" 2>/dev/null || true + ;; + esac + ;; + *) + case "$PLATFORM" in + macos) + # cctools strip has no --strip-unneeded; -x keeps local + # symbols (needed for linking) and drops debug info. + strip -x "$dest_dir/$name" 2>/dev/null || true + ;; + *) + # Shared libraries stay runnable and linkable after + # removing the unneeded symbols. + "$STRIP_CMD" --strip-unneeded "$dest_dir/$name" 2>/dev/null || true + ;; + esac + ;; + esac + fi +} + +for target in "$STAGING/bin" "$STAGING/libs/$LIBS_PLATFORM/$ARCH"; do + for lib in "${SHARED_LIBS[@]}"; do + copy_lib "$LIBS_SRC/$lib" "$target" + done +done + +for lib in "${STATIC_LIBS[@]}"; do + copy_lib "$LIBS_SRC/$lib" "$STAGING/libs/$LIBS_PLATFORM/$ARCH" +done + +# --------------------------------------------------------------------------- +# Headers, documentation and package README. +# --------------------------------------------------------------------------- + +cp -r include "$STAGING/include" +cp -r docs/articles "$STAGING/docs/articles" +sed "s/@SDK_VERSION@/$SDK_VERSION/g" projects/scripts/eepp-sdk-README.md > "$STAGING/README.md" + +# --------------------------------------------------------------------------- +# macOS: make the package relocatable. The build links against homebrew's +# SDL2 and against libs/// through absolute or homebrew paths; +# rewrite every dependency to @loader_path and re-sign ad-hoc (mirroring what +# projects/macos/ecode/build.app.sh does for ecode.app). +# --------------------------------------------------------------------------- + +fix_macos_ids() { + local bin_dir="$STAGING/bin" + + if [ "$PLATFORM" != "macos" ]; then + return 0 + fi + + # Point the shared libraries at their bundled SDL2 dependency. + for lib in "${SHARED_LIBS[@]}"; do + [ -f "$bin_dir/$lib" ] || continue + install_name_tool -change "$(otool -L "$bin_dir/$lib" | awk '/SDL2/ {print $1; exit}')" \ + "@loader_path/libSDL2-2.0.0.dylib" "$bin_dir/$lib" 2>/dev/null || true + done + + # The executables record the absolute path of the just-built libeepp.dylib; + # rewrite it (and any other eepp dependency) to its bundled location. + for exe in "$bin_dir"/*; do + [ -f "$exe" ] && is_executable "$exe" || continue + while read -r dep; do + case "$dep" in + *@loader_path* | */eepp-sdk/*) + continue + ;; + esac + case "$(basename "$dep")" in + libeepp.dylib | libeepp-maps.dylib | libeepp-physics.dylib) + install_name_tool -change "$dep" "@loader_path/$(basename "$dep")" "$exe" + ;; + libSDL2*.dylib) + if [ -f "$bin_dir/libSDL2-2.0.0.dylib" ]; then + install_name_tool -change "$dep" "@loader_path/libSDL2-2.0.0.dylib" "$exe" + fi + ;; + esac + done < <(otool -L "$exe" | tail -n +2 | awk '{print $1}') + codesign --force --sign - "$exe" 2>/dev/null || true + done + + for lib in "${SHARED_LIBS[@]}"; do + [ -f "$bin_dir/$lib" ] || continue + install_name_tool -id "@loader_path/$lib" "$bin_dir/$lib" + codesign --force --sign - "$bin_dir/$lib" 2>/dev/null || true + done + + codesign --force --sign - "$STAGING/libs/$LIBS_PLATFORM/$ARCH"/*.dylib 2>/dev/null || true +} + +# --------------------------------------------------------------------------- +# Bundle SDL2 next to the binaries when available. Optional: the package +# README documents the fallback to the system SDL2. +# --------------------------------------------------------------------------- + +bundle_sdl2() { + if [ "$PLATFORM" == "windows" ]; then + # Premake already drops the SDL2 DLL into bin/ when configured with + # --windows-mingw-build. + if [ -f bin/SDL2.dll ]; then + cp -L bin/SDL2.dll "$STAGING/bin/" + else + echo "Warning: bin/SDL2.dll not found, the tools will require it at runtime" >&2 + fi + elif [ "$PLATFORM" == "macos" ]; then + SDL2_PATH="$(brew --prefix)/opt/sdl2/lib/libSDL2-2.0.0.dylib" + if [ -f "$SDL2_PATH" ]; then + cp -L "$SDL2_PATH" "$STAGING/bin/" + chmod +w "$STAGING/bin/libSDL2-2.0.0.dylib" + install_name_tool -id "@loader_path/libSDL2-2.0.0.dylib" "$STAGING/bin/libSDL2-2.0.0.dylib" + codesign --force --sign - "$STAGING/bin/libSDL2-2.0.0.dylib" 2>/dev/null || true + fi + else + SDL2_PATH="$(ldd "$STAGING/bin/eepp-ui-hello-world" 2>/dev/null | awk '/libSDL[23]/ {print $3; exit}')" + if [ -n "$SDL2_PATH" ] && [ -f "$SDL2_PATH" ]; then + cp -L "$SDL2_PATH" "$STAGING/bin/" + fi + fi +} + +bundle_sdl2 +fix_macos_ids + +# --------------------------------------------------------------------------- +# Package archive: zip for Windows (keeps the +x bits intact in tar.gz for +# Unix platforms). +# --------------------------------------------------------------------------- + +ARCHIVE_BASE="eepp-sdk-$PLATFORM-$ARCH" +if [ "$PLATFORM" == "windows" ]; then + ARCHIVE_NAME="$ARCHIVE_BASE-mingw-$ARCHIVE_SUFFIX.zip" + cd "projects/$PLATFORM/sdk" + zip -qr "$ARCHIVE_NAME" "$SDK_DIRNAME" + cd "$ROOT" +else + ARCHIVE_NAME="$ARCHIVE_BASE-$ARCHIVE_SUFFIX.tar.gz" + cd "projects/$PLATFORM/sdk" + tar -czf "$ARCHIVE_NAME" "$SDK_DIRNAME" + cd "$ROOT" +fi + +echo "Generated projects/$PLATFORM/sdk/$ARCHIVE_NAME" \ No newline at end of file