diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd5d471..68a8fc9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -89,10 +89,11 @@ build_linux: script: - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' - retry docker pull $IMAGE:$CI_COMMIT_SHORT_SHA-linux - - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux cmake -S . -B build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux cmake -S . -B build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENRA3_DISTRO_TAG=ubuntu26.04 - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux cmake --build build/linux -j - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux ctest --test-dir build/linux --output-on-failure - - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux bash -c "mkdir -p artifacts/linux && cp build/linux/bin/openra3 artifacts/linux/" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux bash -c "cd build/linux && cpack -G DEB" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux bash -c "mkdir -p artifacts/linux && cp build/linux/bin/openra3 build/linux/*.deb artifacts/linux/" artifacts: name: "$CI_PROJECT_NAME-linux-$CI_COMMIT_SHORT_SHA" paths: @@ -116,9 +117,178 @@ build_windows: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-x86_64.cmake -DCMAKE_BUILD_TYPE=Release - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows cmake --build build/windows -j - - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows bash -c "mkdir -p artifacts/windows && cp build/windows/bin/openra3.exe build/windows/bin/SDL3.dll artifacts/windows/" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows cmake --build build/windows --target openra3_msi + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows bash -c "cd build/windows && cpack -G ZIP" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows bash -c "mkdir -p artifacts/windows && cp build/windows/bin/openra3.exe build/windows/bin/SDL3.dll build/windows/bin/*.msi build/windows/*.zip artifacts/windows/" artifacts: name: "$CI_PROJECT_NAME-windows-$CI_COMMIT_SHORT_SHA" paths: - artifacts/windows/ expire_in: 7 days + +# --- arm64 + Debian toolchain images ----------------------------------------- +linux_arm64_image: + stage: image + image: docker:latest + services: *dind + tags: + - docker + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - | + retry docker build \ + --cache-from type=registry,ref=$IMAGE:cache-linux-arm64,insecure=true \ + --cache-to type=registry,ref=$IMAGE:cache-linux-arm64,mode=max,insecure=true \ + --build-arg APT_MIRROR=$APT_MIRROR \ + --target dev \ + -t $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 \ + -f Dockerfile.linux-arm64 . + - retry docker push $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 + +windows_arm64_image: + stage: image + image: docker:latest + services: *dind + tags: + - docker + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - | + retry docker build \ + --cache-from type=registry,ref=$IMAGE:cache-windows-arm64,insecure=true \ + --cache-to type=registry,ref=$IMAGE:cache-windows-arm64,mode=max,insecure=true \ + --build-arg APT_MIRROR=$APT_MIRROR \ + --target dev \ + -t $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 \ + -f Dockerfile.win-arm64 . + - retry docker push $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 + +debian_image: + stage: image + image: docker:latest + services: *dind + tags: + - docker + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - | + retry docker build \ + --cache-from type=registry,ref=$IMAGE:cache-debian,insecure=true \ + --cache-to type=registry,ref=$IMAGE:cache-debian,mode=max,insecure=true \ + --build-arg APT_MIRROR=$APT_MIRROR \ + --target dev \ + -t $IMAGE:$CI_COMMIT_SHORT_SHA-debian \ + -f Dockerfile.debian . + - retry docker push $IMAGE:$CI_COMMIT_SHORT_SHA-debian + +debian_arm64_image: + stage: image + image: docker:latest + services: *dind + tags: + - docker + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - | + retry docker build \ + --cache-from type=registry,ref=$IMAGE:cache-debian-arm64,insecure=true \ + --cache-to type=registry,ref=$IMAGE:cache-debian-arm64,mode=max,insecure=true \ + --build-arg APT_MIRROR=$APT_MIRROR \ + --target dev \ + -t $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 \ + -f Dockerfile.debian-arm64 . + - retry docker push $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 + +# --- build each target (binary + packages) ----------------------------------- +build_linux_arm64: + stage: build + image: docker:latest + services: *dind + tags: + - docker + needs: + - linux_arm64_image + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - retry docker pull $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 cmake -S . -B build/linux-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -DOPENRA3_DISTRO_TAG=ubuntu26.04 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 cmake --build build/linux-arm64 -j + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 bash -c "cd build/linux-arm64 && cpack -G DEB" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-linux-arm64 bash -c "mkdir -p artifacts/linux-arm64 && cp build/linux-arm64/bin/openra3 build/linux-arm64/*.deb artifacts/linux-arm64/" + artifacts: + name: "$CI_PROJECT_NAME-linux-arm64-$CI_COMMIT_SHORT_SHA" + paths: + - artifacts/linux-arm64/ + expire_in: 7 days + +build_windows_arm64: + stage: build + image: docker:latest + services: *dind + tags: + - docker + needs: + - windows_arm64_image + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - retry docker pull $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 cmake -S . -B build/windows-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-aarch64.cmake -DCMAKE_BUILD_TYPE=Release + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 cmake --build build/windows-arm64 -j + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 bash -c "cd build/windows-arm64 && cpack -G ZIP" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-windows-arm64 bash -c "mkdir -p artifacts/windows-arm64 && cp build/windows-arm64/bin/openra3.exe build/windows-arm64/bin/SDL3.dll build/windows-arm64/*.zip artifacts/windows-arm64/" + artifacts: + name: "$CI_PROJECT_NAME-windows-arm64-$CI_COMMIT_SHORT_SHA" + paths: + - artifacts/windows-arm64/ + expire_in: 7 days + +build_debian: + stage: build + image: docker:latest + services: *dind + tags: + - docker + needs: + - debian_image + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - retry docker pull $IMAGE:$CI_COMMIT_SHORT_SHA-debian + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian cmake -S . -B build/debian -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json -DOPENRA3_DISTRO_TAG=debian13 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian cmake --build build/debian -j + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian ctest --test-dir build/debian --output-on-failure + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian bash -c "cd build/debian && cpack -G DEB" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian bash -c "mkdir -p artifacts/debian && cp build/debian/bin/openra3 build/debian/*.deb artifacts/debian/" + artifacts: + name: "$CI_PROJECT_NAME-debian-$CI_COMMIT_SHORT_SHA" + paths: + - artifacts/debian/ + expire_in: 7 days + +build_debian_arm64: + stage: build + image: docker:latest + services: *dind + tags: + - docker + needs: + - debian_arm64_image + before_script: *retry + script: + - retry sh -c 'echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin' + - retry docker pull $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 cmake -S . -B build/debian-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -DOPENRA3_AARCH64_CC=clang-19 -DOPENRA3_AARCH64_CXX=clang++-19 -DOPENRA3_AARCH64_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json -DOPENRA3_DISTRO_TAG=debian13 + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 cmake --build build/debian-arm64 -j + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 bash -c "cd build/debian-arm64 && cpack -G DEB" + - docker run --rm -v "$(pwd):/work" -w /work $IMAGE:$CI_COMMIT_SHORT_SHA-debian-arm64 bash -c "mkdir -p artifacts/debian-arm64 && cp build/debian-arm64/bin/openra3 build/debian-arm64/*.deb artifacts/debian-arm64/" + artifacts: + name: "$CI_PROJECT_NAME-debian-arm64-$CI_COMMIT_SHORT_SHA" + paths: + - artifacts/debian-arm64/ + expire_in: 7 days \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a002059..3b8ae86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_SCAN_FOR_MODULES ON) -project(OpenRA3 VERSION 0.4.0 LANGUAGES C CXX) +project(OpenRA3 VERSION 0.5.0 LANGUAGES C CXX) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) @@ -52,9 +52,12 @@ endfunction() # --- SDL3: pkg-config on Linux, or an explicit MinGW root for Windows -------- add_library(openra3_sdl3 INTERFACE) set(OPENRA3_HAS_SDL3 OFF) +# The triple-named subdirectory inside a MinGW SDL3 development package +# (`//{include,lib,bin}`); x86_64 unless a toolchain overrides it. +set(OPENRA3_SDL3_MINGW_TRIPLE "x86_64-w64-mingw32" CACHE STRING "SDL3 MinGW triple subdirectory") if(OPENRA3_SDL3_ROOT) - target_include_directories(openra3_sdl3 INTERFACE "${OPENRA3_SDL3_ROOT}/x86_64-w64-mingw32/include") - target_link_libraries(openra3_sdl3 INTERFACE "${OPENRA3_SDL3_ROOT}/x86_64-w64-mingw32/lib/libSDL3.dll.a") + target_include_directories(openra3_sdl3 INTERFACE "${OPENRA3_SDL3_ROOT}/${OPENRA3_SDL3_MINGW_TRIPLE}/include") + target_link_libraries(openra3_sdl3 INTERFACE "${OPENRA3_SDL3_ROOT}/${OPENRA3_SDL3_MINGW_TRIPLE}/lib/libSDL3.dll.a") set(OPENRA3_HAS_SDL3 ON) else() find_package(PkgConfig QUIET) @@ -293,10 +296,78 @@ openra3_target_defaults(openra3) if(WIN32 AND OPENRA3_SDL3_ROOT) add_custom_command(TARGET openra3 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${OPENRA3_SDL3_ROOT}/x86_64-w64-mingw32/bin/SDL3.dll" + "${OPENRA3_SDL3_ROOT}/${OPENRA3_SDL3_MINGW_TRIPLE}/bin/SDL3.dll" "$") endif() +# --- packaging (.deb / .msi / portable archives) ----------------------------- +# CPack produces the release artifacts in one shot: +# Linux -> DEB (dependencies derived from the binary with dpkg-shlibdeps) +# plus a portable .tar.gz +# Windows -> a Windows Installer .msi (built with wixl from msitools when the +# WiX tools are absent, so the Linux cross image can make it) plus a +# portable .zip with the exe and SDL3.dll +# OPENRA3_DISTRO_TAG (e.g. ubuntu26.04) is appended to the Linux file name so the +# per-distro images do not collide. +install(TARGETS openra3 RUNTIME DESTINATION bin) +if(WIN32 AND OPENRA3_SDL3_ROOT) + install(FILES "${OPENRA3_SDL3_ROOT}/${OPENRA3_SDL3_MINGW_TRIPLE}/bin/SDL3.dll" DESTINATION bin) +endif() + +set(OPENRA3_DISTRO_TAG "" CACHE STRING "Distro tag appended to package file names (e.g. ubuntu26.04)") +set(CPACK_PACKAGE_NAME "openra3") +set(CPACK_PACKAGE_VENDOR "OpenRA3") +set(CPACK_PACKAGE_CONTACT "OpenRA3 ") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenRA3 - a from-scratch reimplementation of Red Alert 3") +set(CPACK_PACKAGE_HOMEPAGE_URL "https://git.ender.cool/EnderTheCoder/openra3") +set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +set(CPACK_PACKAGE_EXECUTABLES "openra3" "OpenRA3") +set(CPACK_STRIP_FILES ON) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +endif() + +if(WIN32) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(OPENRA3_WIN_ARCH "arm64") + else() + set(OPENRA3_WIN_ARCH "x86_64") + endif() + set(CPACK_PACKAGE_FILE_NAME "openra3-${PROJECT_VERSION}-windows-${OPENRA3_WIN_ARCH}") + # Portable .zip (exe + SDL3.dll). + set(CPACK_GENERATOR "ZIP") + + # A Windows Installer (.msi) straight from the Linux cross build via wixl + # (msitools). wixl 0.106 has no arm64 support, so the MSI is offered for + # x86_64 and ARM64 ships the portable zip. + find_program(OPENRA3_WIXL wixl) + if(OPENRA3_WIXL AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging/openra3.wxs.in" + "${CMAKE_CURRENT_BINARY_DIR}/openra3.wxs" @ONLY) + add_custom_target(openra3_msi + COMMAND "${OPENRA3_WIXL}" --arch x64 + -D "exe=$" + -D "dll=${OPENRA3_SDL3_ROOT}/${OPENRA3_SDL3_MINGW_TRIPLE}/bin/SDL3.dll" + -o "$/${CPACK_PACKAGE_FILE_NAME}.msi" + "${CMAKE_CURRENT_BINARY_DIR}/openra3.wxs" + DEPENDS openra3 + COMMENT "Building Windows Installer (${CPACK_PACKAGE_FILE_NAME}.msi) with wixl" + VERBATIM) + endif() +else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64") + else() + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") + endif() + set(CPACK_PACKAGE_FILE_NAME "openra3_${PROJECT_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}${OPENRA3_DISTRO_TAG}") + set(CPACK_GENERATOR "TGZ;DEB") + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + set(CPACK_DEBIAN_PACKAGE_SECTION "games") + set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") +endif() +include(CPack) + # --- extracted assets --------------------------------------------------------- # At build time, extract the retail assets into /assets so the # executable is self-contained (no --game-dir at run time). This drives the diff --git a/Dockerfile b/Dockerfile index a671754..3b3fad4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,8 @@ RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ clang-21 \ clang-tools-21 \ cmake \ + dpkg-dev \ + file \ gdb \ git \ libc++-21-dev \ @@ -45,9 +47,10 @@ ENV CXX=clang++-21 WORKDIR /work COPY . . -RUN cmake -S . -B build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release \ +RUN cmake -S . -B build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENRA3_DISTRO_TAG=ubuntu26.04 \ && cmake --build build/linux -j \ - && ctest --test-dir build/linux --output-on-failure + && ctest --test-dir build/linux --output-on-failure \ + && (cd build/linux && cpack -G DEB) # deploy target: runtime dependencies + final binary, minimal and fast. FROM ubuntu:26.04 AS deploy diff --git a/Dockerfile.debian b/Dockerfile.debian new file mode 100644 index 0000000..e71c399 --- /dev/null +++ b/Dockerfile.debian @@ -0,0 +1,87 @@ +# syntax=docker/dockerfile:1 + +# Debian build environment (latest stable, Debian 13 "trixie") producing a .deb +# alongside the binary. Separate from Dockerfile (Ubuntu 26.04) because the +# distro and its libc++/SDL3 versions differ, and a .deb's dependencies must be +# generated against the distro it targets. +# +# Toolchain: clang-19 + libc++-19 (for `import std;`). Debian 13 ships CMake +# 3.31, whose experimental `import std` gate value the project does not target, +# so an upstream CMake is installed from the Kitware tarball. + +FROM debian:stable AS dev + +ENV DEBIAN_FRONTEND=noninteractive + +ARG APT_MIRROR="" +RUN if [ -n "$APT_MIRROR" ]; then \ + sed -i -e "s|http://deb.debian.org/debian|${APT_MIRROR}|g" \ + -e "s|http://security.debian.org/debian-security|${APT_MIRROR}|g" \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true; \ + fi + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + for attempt in 1 2 3 4 5; do \ + apt-get -o Acquire::Retries=5 update && break; \ + echo "apt-get update failed (attempt $attempt), retrying"; \ + sleep 5; \ + done \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + ca-certificates \ + clang-19 \ + clang-tools-19 \ + curl \ + dpkg-dev \ + file \ + libc++-19-dev \ + libc++abi-19-dev \ + libsdl3-dev \ + libunwind-19-dev \ + lld-19 \ + ninja-build \ + pkg-config \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +# Upstream CMake, because Debian 13's 3.31 experimental gate does not enable the +# `import std;` support the project relies on. +ARG CMAKE_VERSION=4.2.3 +RUN mkdir -p /opt/cmake \ + && curl -fL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \ + | tar -xz -C /opt/cmake --strip-components=1 +ENV PATH="/opt/cmake/bin:${PATH}" + +ENV CC=clang-19 +ENV CXX=clang++-19 + +WORKDIR /work +COPY . . + +RUN cmake -S . -B build/debian -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json \ + -DOPENRA3_DISTRO_TAG=debian13 \ + && cmake --build build/debian -j \ + && ctest --test-dir build/debian --output-on-failure \ + && (cd build/debian && cpack -G DEB) + +# deploy target: runtime dependencies + final binary, minimal and fast. +FROM debian:stable AS deploy + +ENV DEBIAN_FRONTEND=noninteractive + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + apt-get -o Acquire::Retries=5 update \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + libc++1-19 \ + libc++abi1-19 \ + libsdl3-0 \ + libvulkan1 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=dev /work/build/debian/bin/openra3 /app/openra3 + +ENTRYPOINT ["/app/openra3"] diff --git a/Dockerfile.debian-arm64 b/Dockerfile.debian-arm64 new file mode 100644 index 0000000..303321d --- /dev/null +++ b/Dockerfile.debian-arm64 @@ -0,0 +1,86 @@ +# syntax=docker/dockerfile:1 + +# Debian build environment for Linux on ARM64 (aarch64-linux-gnu), producing an +# arm64 .deb. Cross-compiled from amd64 with Debian's clang-19 + libc++-19 and +# the arm64 packages installed via dpkg multiarch. + +FROM debian:stable AS dev + +ENV DEBIAN_FRONTEND=noninteractive + +ARG APT_MIRROR="" +RUN if [ -n "$APT_MIRROR" ]; then \ + sed -i -e "s|http://deb.debian.org/debian|${APT_MIRROR}|g" \ + -e "s|http://security.debian.org/debian-security|${APT_MIRROR}|g" \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true; \ + fi + +RUN dpkg --add-architecture arm64 + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + for attempt in 1 2 3 4 5; do \ + apt-get -o Acquire::Retries=5 update && break; \ + echo "apt-get update failed (attempt $attempt), retrying"; \ + sleep 5; \ + done \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + ca-certificates \ + clang-19 \ + clang-tools-19 \ + curl \ + dpkg-dev \ + file \ + gcc-aarch64-linux-gnu \ + libc++-19-dev:arm64 \ + libc++abi-19-dev:arm64 \ + libsdl3-dev:arm64 \ + libunwind-19-dev:arm64 \ + lld-19 \ + ninja-build \ + pkg-config \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +ARG CMAKE_VERSION=4.2.3 +RUN mkdir -p /opt/cmake \ + && curl -fL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \ + | tar -xz -C /opt/cmake --strip-components=1 +ENV PATH="/opt/cmake/bin:${PATH}" + +ENV CC=clang-19 +ENV CXX=clang++-19 +# Point pkg-config at the arm64 packages so SDL3 resolves to the aarch64 build. +ENV PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig + +WORKDIR /work +COPY . . + +RUN cmake -S . -B build/debian-arm64 -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DOPENRA3_AARCH64_CC=clang-19 \ + -DOPENRA3_AARCH64_CXX=clang++-19 \ + -DOPENRA3_AARCH64_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json \ + -DOPENRA3_DISTRO_TAG=debian13 \ + && cmake --build build/debian-arm64 -j \ + && (cd build/debian-arm64 && cpack -G DEB) + +FROM --platform=linux/arm64 debian:stable AS deploy + +ENV DEBIAN_FRONTEND=noninteractive + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + apt-get -o Acquire::Retries=5 update \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + libc++1-19 \ + libc++abi1-19 \ + libsdl3-0 \ + libvulkan1 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=dev /work/build/debian-arm64/bin/openra3 /app/openra3 + +ENTRYPOINT ["/app/openra3"] diff --git a/Dockerfile.linux-arm64 b/Dockerfile.linux-arm64 new file mode 100644 index 0000000..48830dd --- /dev/null +++ b/Dockerfile.linux-arm64 @@ -0,0 +1,84 @@ +# syntax=docker/dockerfile:1 + +# Linux on ARM64 cross-build environment (aarch64-linux-gnu), isolated from the +# x86_64 Linux image and the Windows images. +# +# Toolchain: clang-21 + libc++ with the arm64 libc++ (for `import std;`), the +# arm64 glibc from `gcc-aarch64-linux-gnu`, arm64 SDL3 from `libsdl3-dev:arm64`, +# and lld as the linker. The arm64 packages are installed with dpkg multiarch +# (`arm64` added to the sources); the native clang/cmake build tools stay amd64. + +FROM ubuntu:26.04 AS dev + +ENV DEBIAN_FRONTEND=noninteractive + +ARG APT_MIRROR="" +RUN if [ -n "$APT_MIRROR" ]; then \ + sed -i -e "s|http://archive.ubuntu.com/ubuntu|${APT_MIRROR}|g" \ + -e "s|http://security.ubuntu.com/ubuntu|${APT_MIRROR}|g" \ + -e "s|http://ports.ubuntu.com/ubuntu-ports|${APT_MIRROR}|g" \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true; \ + fi + +# Enable the arm64 architecture on top of the emulated amd64 userland. +RUN dpkg --add-architecture arm64 + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + for attempt in 1 2 3 4 5; do \ + apt-get -o Acquire::Retries=5 update && break; \ + echo "apt-get update failed (attempt $attempt), retrying"; \ + sleep 5; \ + done \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + ca-certificates \ + clang-21 \ + cmake \ + dpkg-dev \ + file \ + gcc-aarch64-linux-gnu \ + libc++-21-dev:arm64 \ + libc++abi-21-dev:arm64 \ + libsdl3-dev:arm64 \ + libunwind-21-dev:arm64 \ + lld-21 \ + ninja-build \ + pkg-config \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +ENV CC=clang-21 +ENV CXX=clang++-21 +# Point pkg-config at the arm64 packages so SDL3 resolves to the aarch64 build. +ENV PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig + +WORKDIR /work +COPY . . + +RUN cmake -S . -B build/linux-arm64 -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DOPENRA3_DISTRO_TAG=ubuntu26.04 \ + && cmake --build build/linux-arm64 -j \ + && (cd build/linux-arm64 && cpack -G DEB) + +# deploy target: runtime dependencies + final binary, minimal and fast. This is +# an arm64 image; build it on (or with emulation for) an arm64 host. +FROM --platform=linux/arm64 ubuntu:26.04 AS deploy + +ENV DEBIAN_FRONTEND=noninteractive + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + apt-get -o Acquire::Retries=5 update \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + libc++1 \ + libc++abi1 \ + libsdl3-0 \ + libvulkan1 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=dev /work/build/linux-arm64/bin/openra3 /app/openra3 + +ENTRYPOINT ["/app/openra3"] diff --git a/Dockerfile.win b/Dockerfile.win index 214df49..65decb8 100644 --- a/Dockerfile.win +++ b/Dockerfile.win @@ -31,6 +31,7 @@ RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ curl \ ninja-build \ python3 \ + wixl \ xz-utils \ && rm -rf /var/lib/apt/lists/* @@ -54,7 +55,9 @@ COPY . . RUN cmake -S . -B build/windows -G Ninja \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-x86_64.cmake \ -DCMAKE_BUILD_TYPE=Release \ - && cmake --build build/windows -j + && cmake --build build/windows -j \ + && cmake --build build/windows --target openra3_msi \ + && (cd build/windows && cpack -G ZIP) # package target: the .exe plus the SDL3 runtime DLL. FROM ubuntu:26.04 AS package diff --git a/Dockerfile.win-arm64 b/Dockerfile.win-arm64 new file mode 100644 index 0000000..3f3047d --- /dev/null +++ b/Dockerfile.win-arm64 @@ -0,0 +1,77 @@ +# syntax=docker/dockerfile:1 + +# Windows on ARM64 cross-build environment (aarch64-w64-mingw32), isolated from +# the x86_64 Windows image and the Linux images. +# +# Toolchain: the same multi-target llvm-mingw as Dockerfile.win (clang + libc++ + +# the libc++ `std` module, MSVCRT runtime), targeting aarch64. The official SDL +# release ships no MinGW ARM64 dev package, so SDL3 comes from MSYS2's clangarm64 +# repository, staged into the `/{include,lib,bin}` layout the toolchain +# expects. + +FROM ubuntu:26.04 AS dev + +ENV DEBIAN_FRONTEND=noninteractive + +ARG APT_MIRROR="" +RUN if [ -n "$APT_MIRROR" ]; then \ + sed -i -e "s|http://archive.ubuntu.com/ubuntu|${APT_MIRROR}|g" \ + -e "s|http://security.ubuntu.com/ubuntu|${APT_MIRROR}|g" \ + -e "s|http://ports.ubuntu.com/ubuntu-ports|${APT_MIRROR}|g" \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true; \ + fi + +RUN --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + for attempt in 1 2 3 4 5; do \ + apt-get -o Acquire::Retries=5 update && break; \ + echo "apt-get update failed (attempt $attempt), retrying"; \ + sleep 5; \ + done \ + && apt-get -o Acquire::Retries=5 install -y --no-install-recommends \ + ca-certificates \ + cmake \ + curl \ + ninja-build \ + python3 \ + xz-utils \ + zstd \ + && rm -rf /var/lib/apt/lists/* + +# Pinned toolchain + SDL3 versions (override with --build-arg to bump). +ARG LLVM_MINGW_VERSION=20260908 +ARG LLVM_MINGW_FLAVOR=msvcrt +# SDL3 for aarch64-w64-mingw32 from MSYS2's clangarm64 repo (name includes the +# MSYS2 package release, hence the `-1`). +ARG MSYS2_SDL3_PKG=mingw-w64-clang-aarch64-sdl3-3.4.16-1-any.pkg.tar.zst + +RUN mkdir -p /opt/llvm-mingw \ + && curl -fL "https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-${LLVM_MINGW_FLAVOR}-ubuntu-22.04-x86_64.tar.xz" \ + | tar -xJ -C /opt/llvm-mingw --strip-components=1 + +RUN mkdir -p /opt/sdl3-aarch64/aarch64-w64-mingw32/include /opt/sdl3-aarch64/aarch64-w64-mingw32/lib /opt/sdl3-aarch64/aarch64-w64-mingw32/bin \ + && curl -fL "https://repo.msys2.org/mingw/clangarm64/${MSYS2_SDL3_PKG}" -o /tmp/sdl3.pkg.tar.zst \ + && mkdir -p /tmp/sdl3 && tar --zstd -xf /tmp/sdl3.pkg.tar.zst -C /tmp/sdl3 \ + && cp -r /tmp/sdl3/clangarm64/include/SDL3 /opt/sdl3-aarch64/aarch64-w64-mingw32/include/ \ + && cp /tmp/sdl3/clangarm64/lib/libSDL3.dll.a /opt/sdl3-aarch64/aarch64-w64-mingw32/lib/ \ + && cp /tmp/sdl3/clangarm64/bin/SDL3.dll /opt/sdl3-aarch64/aarch64-w64-mingw32/bin/ \ + && rm -rf /tmp/sdl3 /tmp/sdl3.pkg.tar.zst + +ENV OPENRA3_LLVM_MINGW_ROOT=/opt/llvm-mingw +ENV OPENRA3_SDL3_ROOT=/opt/sdl3-aarch64 + +WORKDIR /work +COPY . . + +RUN cmake -S . -B build/windows-arm64 -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-aarch64.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + && cmake --build build/windows-arm64 -j \ + && (cd build/windows-arm64 && cpack -G ZIP) + +# package target: the .exe plus the SDL3 runtime DLL. +FROM ubuntu:26.04 AS package + +WORKDIR /app +COPY --from=dev /work/build/windows-arm64/bin/openra3.exe /app/ +COPY --from=dev /work/build/windows-arm64/bin/SDL3.dll /app/ diff --git a/README.md b/README.md index 79c727c..c41773d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Ghidra. ## Status -OpenRA3 is at **v0.4.0**. The engine compiles and runs headless, and a **minimal +OpenRA3 is at **v0.5.0**. The engine compiles and runs headless, and a **minimal skirmish** is playable: it reads a real multiplayer map out of your install, recovers the player start waypoints, and simulates two sides building a base, extracting ore and fighting until one side is wiped out. The balance is the @@ -122,13 +122,29 @@ their compilers and standard libraries never interfere. The host needs no toolchain: each target builds inside its own image. ```bash -# Linux -> build/linux/bin/openra3 +# Linux (amd64) -> build/linux/bin/openra3 + .deb scripts/build-linux.sh -# Windows -> build/windows/bin/openra3.exe (+ SDL3.dll) +# Linux/arm64 -> build/linux-arm64/bin/openra3 + .deb (cross) +scripts/build-linux-arm64.sh + +# Debian (amd64) -> build/debian/bin/openra3 + .deb +scripts/build-debian.sh + +# Debian (arm64) -> build/debian-arm64/bin/openra3 + .deb (cross) +scripts/build-debian-arm64.sh + +# Windows (x86_64) -> build/windows/bin/openra3.exe + SDL3.dll, .zip, .msi scripts/build-windows.sh + +# Windows (arm64) -> build/windows-arm64/bin/openra3.exe + SDL3.dll, .zip (cross) +scripts/build-windows-arm64.sh ``` +Every target is cross-built from x86_64 Linux in its own image: llvm-mingw for +the Windows targets, clang + libc++ with dpkg multiarch for the arm64 targets, +and Debian/Ubuntu-specific images for the `.deb` packages. + Or drive Docker directly: ```bash @@ -160,6 +176,25 @@ openra3.exe render --game-dir "C:\Red Alert 3" --vulkan Vulkan is provided by **vendored volk + headers** (`third_party/`), resolved at runtime, so neither image needs a Vulkan SDK. +## Packages + +CPack produces the release artifacts; the Docker images and CI run it for every +target. + +| Target | Portable | Installer | +| --- | --- | --- | +| Linux amd64 (Ubuntu 26.04) | `.tar.gz` | `openra3__amd64ubuntu26.04.deb` | +| Linux arm64 (Ubuntu 26.04) | `.tar.gz` | `openra3__arm64ubuntu26.04.deb` | +| Linux amd64 (Debian 13) | `.tar.gz` | `openra3__amd64debian13.deb` | +| Linux arm64 (Debian 13) | `.tar.gz` | `openra3__arm64debian13.deb` | +| Windows x86_64 | `openra3--windows-x86_64.zip` | `openra3--windows-x86_64.msi` | +| Windows arm64 | `openra3--windows-arm64.zip` | (WiX-only; see below) | + +The `.deb` dependencies are derived from the binary with `dpkg-shlibdeps`. The +`.msi` is built with **wixl** (msitools) straight from the Linux cross image; +wixl 0.106 has no arm64 support, so Windows/ARM64 ships the portable `.zip` +(the MSI toolchain for ARM64 would be WiX v4 via the .NET SDK). + ## Logging Every run writes `openra3.log` next to the executable through the vendored diff --git a/VERSION b/VERSION index 60a2d3e..79a2734 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 \ No newline at end of file +0.5.0 \ No newline at end of file diff --git a/cmake/packaging/openra3.wxs.in b/cmake/packaging/openra3.wxs.in new file mode 100644 index 0000000..a074d5d --- /dev/null +++ b/cmake/packaging/openra3.wxs.in @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmake/toolchains/clang-aarch64-linux-gnu.cmake b/cmake/toolchains/clang-aarch64-linux-gnu.cmake new file mode 100644 index 0000000..f08cd12 --- /dev/null +++ b/cmake/toolchains/clang-aarch64-linux-gnu.cmake @@ -0,0 +1,53 @@ +# Cross-compile for Linux on ARM64 (aarch64-linux-gnu) from x86_64. +# +# clang-21 + libc++ (for `import std;`) with the arm64 libc++ and SDL3 taken +# from Ubuntu's arm64 packages (installed with dpkg multiarch), and the arm64 +# glibc headers/libs from `gcc-aarch64-linux-gnu`. lld links the result; the C +# multiarch include directory is added explicitly because clang does not always +# infer Debian's `bits/` layout from the target triple alone. + +# The `import std` gate must be set before the compiler is probed; a toolchain +# file is processed earlier than the project's own top-level settings. +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(OPENRA3_AARCH64_TRIPLE "aarch64-linux-gnu") +# Multiarch paths the arm64 packages install into. +set(OPENRA3_AARCH64_INCLUDE "/usr/include/${OPENRA3_AARCH64_TRIPLE}") +set(OPENRA3_AARCH64_LIB "/usr/lib/${OPENRA3_AARCH64_TRIPLE}") + +# Compiler + libc++ module description are cache vars so a distro with a +# differently-versioned clang (e.g. Debian's clang-19) can override on the +# command line. +set(OPENRA3_AARCH64_CC "clang-21" CACHE STRING "aarch64 C compiler") +set(OPENRA3_AARCH64_CXX "clang++-21" CACHE STRING "aarch64 C++ compiler") +set(OPENRA3_AARCH64_STDLIB_MODULES_JSON "/usr/lib/llvm-21/lib/libc++.modules.json" CACHE FILEPATH + "libc++ std module description for the aarch64 target") + +set(CMAKE_C_COMPILER ${OPENRA3_AARCH64_CC}) +set(CMAKE_CXX_COMPILER ${OPENRA3_AARCH64_CXX}) +set(CMAKE_C_COMPILER_TARGET ${OPENRA3_AARCH64_TRIPLE}) +set(CMAKE_CXX_COMPILER_TARGET ${OPENRA3_AARCH64_TRIPLE}) +# CMake's standard-library detection does not pass COMPILER_TARGET, so without +# this it probes the host standard library. +set(CMAKE_C_COMPILER_ARG1 "--target=${OPENRA3_AARCH64_TRIPLE}") +set(CMAKE_CXX_COMPILER_ARG1 "--target=${OPENRA3_AARCH64_TRIPLE}") + +# libc++ standard-library module description for the aarch64 target. On a +# multiarch image only the arm64 libc++ is installed, so the standard path +# already resolves to the aarch64 module description. +set(CMAKE_CXX_STDLIB_MODULES_JSON "${OPENRA3_AARCH64_STDLIB_MODULES_JSON}") + +# Strip with the cross binutils, so CPack can strip the arm64 binary. +set(CMAKE_STRIP aarch64-linux-gnu-strip) + +set(CMAKE_C_FLAGS_INIT "-isystem ${OPENRA3_AARCH64_INCLUDE}") +set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ -isystem ${OPENRA3_AARCH64_INCLUDE}") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-stdlib=libc++ -fuse-ld=lld -L${OPENRA3_AARCH64_LIB}") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++ -fuse-ld=lld -L${OPENRA3_AARCH64_LIB}") + +# Run arm64 test binaries through qemu when it is installed, so `ctest` works +# during the image build; harmless when the tests are only cross-compiled. +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-aarch64-static) diff --git a/cmake/toolchains/llvm-mingw-aarch64.cmake b/cmake/toolchains/llvm-mingw-aarch64.cmake new file mode 100644 index 0000000..6806256 --- /dev/null +++ b/cmake/toolchains/llvm-mingw-aarch64.cmake @@ -0,0 +1,50 @@ +# Cross-compile for Windows on ARM64 (aarch64-w64-mingw32) with llvm-mingw: +# clang + libc++ + the libc++ `std` module, targeting the MSVCRT MinGW runtime. +# The same llvm-mingw release is multi-target, so only the target triple, the +# SDL3 SDK and the sysroot paths differ from the x86_64 toolchain. + +# The `import std` gate must be set before the compiler is probed; a toolchain +# file is processed earlier than the project's own top-level settings. +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(OPENRA3_LLVM_MINGW_ROOT "/opt/llvm-mingw" CACHE PATH "llvm-mingw installation root") +if(NOT EXISTS "${OPENRA3_LLVM_MINGW_ROOT}/bin/clang++") + message(FATAL_ERROR "llvm-mingw not found at ${OPENRA3_LLVM_MINGW_ROOT} (expected bin/clang++)") +endif() + +# llvm-mingw's per-target prefix/sysroot for the ARM64 target. +set(OPENRA3_MINGW_TRIPLE "aarch64-w64-mingw32") + +set(CMAKE_C_COMPILER "${OPENRA3_LLVM_MINGW_ROOT}/bin/clang") +set(CMAKE_CXX_COMPILER "${OPENRA3_LLVM_MINGW_ROOT}/bin/clang++") +set(CMAKE_C_COMPILER_TARGET ${OPENRA3_MINGW_TRIPLE}) +set(CMAKE_CXX_COMPILER_TARGET ${OPENRA3_MINGW_TRIPLE}) +# CMake's standard-library detection does not pass COMPILER_TARGET, so without +# this it probes the host standard library. Putting the target in ARG1 makes +# the probe see libc++ (the MinGW target's library). +set(CMAKE_C_COMPILER_ARG1 "--target=${OPENRA3_MINGW_TRIPLE}") +set(CMAKE_CXX_COMPILER_ARG1 "--target=${OPENRA3_MINGW_TRIPLE}") + +# libc++ standard-library module description for the MinGW target. Must be set +# before the compiler is probed so CMake can build `import std;`. +set(CMAKE_CXX_STDLIB_MODULES_JSON "${OPENRA3_LLVM_MINGW_ROOT}/${OPENRA3_MINGW_TRIPLE}/lib/libc++.modules.json") + +# Select libc++ explicitly so CMake's `import std` detection recognises the +# standard library (llvm-mingw defaults to it, but CMake keys off -stdlib=). +set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-stdlib=libc++") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++") + +# SDL3 for aarch64-w64-mingw32. The official SDL release ships no MinGW ARM64 +# dev package, so the image stages one from MSYS2's clangarm64 repo under this +# root in the same `/{include,lib,bin}` layout. +set(OPENRA3_SDL3_ROOT "/opt/sdl3-aarch64" CACHE PATH "SDL3 aarch64 MinGW development package root") +set(OPENRA3_SDL3_MINGW_TRIPLE "${OPENRA3_MINGW_TRIPLE}" CACHE STRING "SDL3 MinGW triple subdirectory") + +set(CMAKE_FIND_ROOT_PATH "${OPENRA3_LLVM_MINGW_ROOT}/${OPENRA3_MINGW_TRIPLE}") +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/cmake/toolchains/llvm-mingw-x86_64.cmake b/cmake/toolchains/llvm-mingw-x86_64.cmake index e91a711..17b70fc 100644 --- a/cmake/toolchains/llvm-mingw-x86_64.cmake +++ b/cmake/toolchains/llvm-mingw-x86_64.cmake @@ -36,6 +36,8 @@ set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++") # Official SDL3 MinGW development package (headers + import library + DLL). set(OPENRA3_SDL3_ROOT "/opt/sdl3-mingw" CACHE PATH "SDL3 MinGW development package root") +# The triple-named subdirectory inside the SDL3 MinGW package. +set(OPENRA3_SDL3_MINGW_TRIPLE "x86_64-w64-mingw32" CACHE STRING "SDL3 MinGW triple subdirectory") set(CMAKE_FIND_ROOT_PATH "${OPENRA3_LLVM_MINGW_ROOT}/x86_64-w64-mingw32") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/scripts/build-debian-arm64.sh b/scripts/build-debian-arm64.sh new file mode 100644 index 0000000..ab98798 --- /dev/null +++ b/scripts/build-debian-arm64.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Build the Debian (latest stable) Linux/ARM64 target (.deb + binary). +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +IMAGE="${OPENRA3_DEBIAN_ARM64_IMAGE:-openra3-debian-arm64:local}" +BUILD_DIR="${1:-build/debian-arm64}" + +docker build --target dev -f "$ROOT/Dockerfile.debian-arm64" -t "$IMAGE" "$ROOT" +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake -S . -B "$BUILD_DIR" -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DOPENRA3_AARCH64_CC=clang-19 -DOPENRA3_AARCH64_CXX=clang++-19 \ + -DOPENRA3_AARCH64_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json \ + -DOPENRA3_DISTRO_TAG=debian13 +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake --build "$BUILD_DIR" -j +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" bash -c "cd $BUILD_DIR && cpack -G DEB" + +echo "Debian arm64: $ROOT/$BUILD_DIR/bin/openra3 (+ .deb)" diff --git a/scripts/build-debian.sh b/scripts/build-debian.sh new file mode 100644 index 0000000..5a9fd33 --- /dev/null +++ b/scripts/build-debian.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Build the Debian (latest stable) target (.deb + binary) with the isolated image. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +IMAGE="${OPENRA3_DEBIAN_IMAGE:-openra3-debian:local}" +BUILD_DIR="${1:-build/debian}" + +docker build --target dev -f "$ROOT/Dockerfile.debian" -t "$IMAGE" "$ROOT" +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake -S . -B "$BUILD_DIR" -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-19/lib/libc++.modules.json \ + -DOPENRA3_DISTRO_TAG=debian13 +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake --build "$BUILD_DIR" -j +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" bash -c "cd $BUILD_DIR && cpack -G DEB" + +echo "Debian: $ROOT/$BUILD_DIR/bin/openra3 (+ .deb)" diff --git a/scripts/build-linux-arm64.sh b/scripts/build-linux-arm64.sh new file mode 100644 index 0000000..ef3b5c3 --- /dev/null +++ b/scripts/build-linux-arm64.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Build the Linux/ARM64 target (.deb + binary) with the isolated cross image. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +IMAGE="${OPENRA3_LINUX_ARM64_IMAGE:-openra3-linux-arm64:local}" +BUILD_DIR="${1:-build/linux-arm64}" + +docker build --target dev -f "$ROOT/Dockerfile.linux-arm64" -t "$IMAGE" "$ROOT" +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake -S . -B "$BUILD_DIR" -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-aarch64-linux-gnu.cmake \ + -DCMAKE_BUILD_TYPE=Release -DOPENRA3_DISTRO_TAG=ubuntu26.04 +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake --build "$BUILD_DIR" -j +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" bash -c "cd $BUILD_DIR && cpack -G DEB" + +echo "Linux arm64: $ROOT/$BUILD_DIR/bin/openra3 (+ .deb)" diff --git a/scripts/build-windows-arm64.sh b/scripts/build-windows-arm64.sh new file mode 100644 index 0000000..e110c15 --- /dev/null +++ b/scripts/build-windows-arm64.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Build the Windows/ARM64 target (portable .zip) with the isolated cross image. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +IMAGE="${OPENRA3_WINDOWS_ARM64_IMAGE:-openra3-windows-arm64:local}" +BUILD_DIR="${1:-build/windows-arm64}" + +docker build --target dev -f "$ROOT/Dockerfile.win-arm64" -t "$IMAGE" "$ROOT" +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake -S . -B "$BUILD_DIR" -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-aarch64.cmake \ + -DCMAKE_BUILD_TYPE=Release +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" cmake --build "$BUILD_DIR" -j +docker run --rm -v "$ROOT:/work" -w /work "$IMAGE" bash -c "cd $BUILD_DIR && cpack -G ZIP" + +echo "Windows arm64: $ROOT/$BUILD_DIR/bin/openra3.exe (+ .zip)"