Add native installer packaging to CI for all platforms

Linux: DEB with /opt/wowee prefix and /usr/local/bin/wowee wrapper script
Windows x86-64: NSIS installer with DLL bundling and Start Menu shortcut
Windows ARM64: ZIP archive with bundled DLLs
macOS ARM64: .app bundle via dylibbundler + DMG via hdiutil

Assets are bundled into all packages (Original Music excluded). StormLib
is installed where available so asset_extract is included in packages.
This commit is contained in:
Kelsi 2026-02-18 18:18:30 -08:00
parent 456aa90eda
commit 5b3b6df544
2 changed files with 179 additions and 14 deletions

View file

@ -16,8 +16,10 @@ jobs:
include:
- arch: x86-64
runner: ubuntu-24.04
deb_arch: amd64
- arch: arm64
runner: ubuntu-24.04-arm
deb_arch: arm64
steps:
- name: Checkout
@ -50,7 +52,8 @@ jobs:
libswscale-dev \
libavutil-dev \
libunicorn-dev \
libx11-dev
libx11-dev \
libstormlib-dev || true
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
@ -58,11 +61,14 @@ jobs:
- name: Build
run: cmake --build build --parallel $(nproc)
- name: Upload artifacts
- name: Package (DEB)
run: cd build && cpack -G DEB
- name: Upload DEB
uses: actions/upload-artifact@v4
with:
name: wowee-${{ matrix.arch }}
path: build/bin/
name: wowee-linux-${{ matrix.arch }}-deb
path: build/wowee-*.deb
if-no-files-found: error
build-macos:
@ -84,7 +90,10 @@ jobs:
- name: Install dependencies
run: |
brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg unicorn
brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg unicorn \
stormlib dylibbundler || true
# dylibbundler may not be in all brew mirrors; install separately to not block others
brew install dylibbundler 2>/dev/null || true
- name: Configure
run: |
@ -98,11 +107,56 @@ jobs:
- name: Build
run: cmake --build build --parallel $(sysctl -n hw.logicalcpu)
- name: Upload artifacts
- name: Create .app bundle
run: |
mkdir -p Wowee.app/Contents/{MacOS,Frameworks,Resources}
# Wrapper launch script — cd to MacOS/ so ./assets/ resolves correctly
printf '#!/bin/bash\ncd "$(dirname "$0")"\nexec ./wowee_bin "$@"\n' \
> Wowee.app/Contents/MacOS/wowee
chmod +x Wowee.app/Contents/MacOS/wowee
# Actual binary
cp build/bin/wowee Wowee.app/Contents/MacOS/wowee_bin
# Assets (exclude proprietary music)
rsync -a --exclude='Original Music' build/bin/assets/ \
Wowee.app/Contents/MacOS/assets/
# Bundle dylibs (if dylibbundler available)
if command -v dylibbundler &>/dev/null; then
dylibbundler -od -b \
-x Wowee.app/Contents/MacOS/wowee_bin \
-d Wowee.app/Contents/Frameworks/ \
-p @executable_path/../Frameworks/
fi
# Info.plist
cat > Wowee.app/Contents/Info.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>CFBundleExecutable</key><string>wowee</string>
<key>CFBundleIdentifier</key><string>com.wowee.app</string>
<key>CFBundleName</key><string>Wowee</string>
<key>CFBundleVersion</key><string>1.0.0</string>
<key>CFBundleShortVersionString</key><string>1.0.0</string>
<key>CFBundlePackageType</key><string>APPL</string>
</dict></plist>
EOF
# Ad-hoc codesign (allows running on the local machine)
codesign --force --deep --sign - Wowee.app
- name: Create DMG
run: hdiutil create -volname Wowee -srcfolder Wowee.app -ov -format UDZO Wowee.dmg
- name: Upload DMG
uses: actions/upload-artifact@v4
with:
name: wowee-macos-${{ matrix.arch }}
path: build/bin/
name: wowee-macos-${{ matrix.arch }}-dmg
path: Wowee.dmg
if-no-files-found: error
build-windows-arm:
@ -142,11 +196,23 @@ jobs:
shell: msys2 {0}
run: cmake --build build --parallel $(nproc)
- name: Upload artifacts
- name: Bundle DLLs
shell: msys2 {0}
run: |
ldd build/bin/wowee.exe \
| awk '/=> \// { print $3 }' \
| grep -iv '^/c/Windows' \
| xargs -I{} sh -c 'cp -n "{}" build/bin/ 2>/dev/null || true'
- name: Package (ZIP)
shell: msys2 {0}
run: cd build && cpack -G ZIP
- name: Upload ZIP
uses: actions/upload-artifact@v4
with:
name: wowee-windows-arm64
path: build/bin/
name: wowee-windows-arm64-zip
path: build/wowee-*.zip
if-no-files-found: error
build-windows:
@ -173,6 +239,7 @@ jobs:
mingw-w64-x86_64-zlib
mingw-w64-x86_64-ffmpeg
mingw-w64-x86_64-unicorn
mingw-w64-x86_64-nsis
git
- name: Clone ImGui
@ -187,9 +254,21 @@ jobs:
shell: msys2 {0}
run: cmake --build build --parallel $(nproc)
- name: Upload artifacts
- name: Bundle DLLs
shell: msys2 {0}
run: |
ldd build/bin/wowee.exe \
| awk '/=> \// { print $3 }' \
| grep -iv '^/c/Windows' \
| xargs -I{} sh -c 'cp -n "{}" build/bin/ 2>/dev/null || true'
- name: Package (NSIS)
shell: msys2 {0}
run: cd build && cpack -G NSIS
- name: Upload installer
uses: actions/upload-artifact@v4
with:
name: wowee-windows-x86-64
path: build/bin/
name: wowee-windows-x86-64-installer
path: build/wowee-*.exe
if-no-files-found: error

View file

@ -389,6 +389,29 @@ install(TARGETS wowee
ARCHIVE DESTINATION lib
)
# Install tools alongside main binary
foreach(_tool dbc_to_csv blp_convert auth_probe auth_login_probe)
if(TARGET ${_tool})
install(TARGETS ${_tool} RUNTIME DESTINATION bin)
endif()
endforeach()
if(STORMLIB_LIBRARY AND STORMLIB_INCLUDE_DIR)
install(TARGETS asset_extract RUNTIME DESTINATION bin)
endif()
# Install built-in assets (exclude proprietary music)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/assets
DESTINATION bin
PATTERN "Original Music" EXCLUDE)
# On Windows, install any DLLs that were bundled into the build output dir
# (populated by the CI workflow's DLL-bundling step before cpack runs)
if(WIN32)
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
DESTINATION bin
FILES_MATCHING PATTERN "*.dll")
endif()
# Linux desktop integration (launcher + icon)
if(UNIX AND NOT APPLE)
set(WOWEE_LINUX_ICON_PATH "${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/256x256/apps/wowee.png")
@ -512,3 +535,66 @@ message(STATUS " SDL2: ${SDL2_VERSION}")
message(STATUS " OpenSSL: ${OPENSSL_VERSION}")
message(STATUS " ImGui: ${IMGUI_DIR}")
message(STATUS "")
# ---- CPack packaging ----
set(CPACK_PACKAGE_NAME "wowee")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "World of Warcraft client emulator")
set(CPACK_PACKAGE_VENDOR "Wowee")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Wowee")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
if(WIN32)
set(CPACK_GENERATOR "NSIS")
set(CPACK_NSIS_DISPLAY_NAME "Wowee")
set(CPACK_NSIS_PACKAGE_NAME "Wowee")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
# Run wowee from bin/ so that ./assets/ resolves correctly.
# SetOutPath sets the shortcut's working directory in NSIS.
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"SetOutPath '$INSTDIR\\bin'\nCreateShortCut '$SMPROGRAMS\\$STARTMENU_FOLDER\\Wowee.lnk' '$INSTDIR\\bin\\wowee.exe'")
set(CPACK_NSIS_DELETE_ICONS_EXTRA
"Delete '$SMPROGRAMS\\$STARTMENU_FOLDER\\Wowee.lnk'")
elseif(APPLE)
set(CPACK_GENERATOR "DragNDrop")
else()
# Linux — generate postinst/prerm wrapper scripts
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/packaging)
# postinst: write a wrapper script at /usr/local/bin/wowee that cd's to
# the install dir so ./assets/ resolves correctly.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst
[[#!/bin/sh
cat > /usr/local/bin/wowee << 'WOWEE_WRAPPER'
#!/bin/sh
cd /opt/wowee/bin
exec ./wowee "$@"
WOWEE_WRAPPER
chmod +x /usr/local/bin/wowee
]])
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm
"#!/bin/sh\nrm -f /usr/local/bin/wowee\n")
file(CHMOD
${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst
${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm
PERMISSIONS
OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ
WORLD_EXECUTE WORLD_READ)
set(CPACK_GENERATOR "DEB")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/wowee")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Wowee")
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_DEPENDS
"libsdl2-2.0-0, libglew2.2 | libglew2.1, libssl3, zlib1g")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
"${CMAKE_CURRENT_BINARY_DIR}/packaging/postinst;${CMAKE_CURRENT_BINARY_DIR}/packaging/prerm")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
endif()
endif()
include(CPack)