Skip to content

Fix linking issues

Fix linking issues #28

name: Emscripten Build
on:
push:
pull_request:
workflow_dispatch:
jobs:
build-emscripten:
runs-on: ubuntu-latest
timeout-minutes: 90 # increase as needed (default is 360 minutes max)
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
cmake \
ninja-build \
python3 \
python3-pip \
wget \
git
- name: Cache build files
uses: actions/cache@v3
with:
path: |
build-emscripten/
emscripten-deps/
key: ${{ runner.os }}-emscripten-build-${{ github.sha }}
restore-keys: |
${{ runner.os }}-emscripten-build-
- name: Build Emscripten dependencies
run: |
mkdir -p emscripten-deps
cd emscripten-deps
# Create a simple wrapper that provides zlib and libpng from Emscripten ports
# This allows CMake's find_package to work with Emscripten's built-in libraries
# Create pkg-config files for Emscripten's built-in zlib
mkdir -p install/lib/pkgconfig
cat > install/lib/pkgconfig/zlib.pc << 'EOF'
prefix=/emsdk/upstream/emscripten/cache/sysroot
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: zlib
Description: zlib compression library (Emscripten port)
Version: 1.2.11
Libs: -lz
Cflags: -I${includedir}
EOF
# Create CMake config for zlib
mkdir -p install/lib/cmake/ZLIB
cat > install/lib/cmake/ZLIB/ZLIBConfig.cmake << 'EOF'
set(ZLIB_FOUND TRUE)
set(ZLIB_INCLUDE_DIRS "/include")
set(ZLIB_LIBRARIES "z")
set(ZLIB_LIBRARY "z")
set(ZLIB_INCLUDE_DIR "/include")
if(NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
set_target_properties(ZLIB::ZLIB PROPERTIES
INTERFACE_COMPILE_OPTIONS "-s;USE_ZLIB=1"
INTERFACE_LINK_OPTIONS "-s;USE_ZLIB=1"
INTERFACE_LINK_LIBRARIES "z"
)
endif()
EOF
# Create CMake config for SDL2 (Emscripten port)
mkdir -p install/lib/cmake/SDL2
cat > install/lib/cmake/SDL2/SDL2Config.cmake << 'EOF'
set(SDL2_FOUND TRUE)
set(SDL2_INCLUDE_DIRS "/include/SDL2")
set(SDL2_LIBRARIES "SDL2")
if(NOT TARGET SDL2::SDL2)
add_library(SDL2::SDL2 INTERFACE IMPORTED)
set_target_properties(SDL2::SDL2 PROPERTIES
INTERFACE_COMPILE_OPTIONS "-s;USE_SDL=2"
INTERFACE_LINK_OPTIONS "-s;USE_SDL=2"
INTERFACE_LINK_LIBRARIES "SDL2"
)
endif()
# Also create SDL2-static for compatibility
if(NOT TARGET SDL2::SDL2-static)
add_library(SDL2::SDL2-static INTERFACE IMPORTED)
set_target_properties(SDL2::SDL2-static PROPERTIES
INTERFACE_COMPILE_OPTIONS "-s;USE_SDL=2"
INTERFACE_LINK_OPTIONS "-s;USE_SDL=2"
INTERFACE_LINK_LIBRARIES "SDL2"
)
endif()
# Also create SDL2main for compatibility
if(NOT TARGET SDL2::SDL2main)
add_library(SDL2::SDL2main INTERFACE IMPORTED)
endif()
EOF
# Build a minimal libzip without zlib dependency checks
if [ ! -d "libzip-1.10.1" ]; then
wget https://github.com/nih-at/libzip/releases/download/v1.10.1/libzip-1.10.1.tar.gz
tar -xzf libzip-1.10.1.tar.gz
cd libzip-1.10.1
# Patch CMakeLists.txt to skip zlib version check
sed -i 's/find_package(ZLIB 1.1.2 REQUIRED)/find_package(ZLIB REQUIRED)/' CMakeLists.txt
mkdir -p build && cd build
# Configure with Emscripten's zlib
# First ensure ZLIB can be found
export ZLIB_ROOT=$PWD/../../../emscripten-deps/install
export PKG_CONFIG_PATH=$PWD/../../../emscripten-deps/install/lib/pkgconfig:$PKG_CONFIG_PATH
CFLAGS="-s USE_ZLIB=1" LDFLAGS="-s USE_ZLIB=1" emcmake cmake .. \
-DENABLE_COMMONCRYPTO=OFF \
-DENABLE_GNUTLS=OFF \
-DENABLE_MBEDTLS=OFF \
-DENABLE_OPENSSL=OFF \
-DENABLE_WINDOWS_CRYPTO=OFF \
-DENABLE_BZIP2=OFF \
-DENABLE_LZMA=OFF \
-DENABLE_ZSTD=OFF \
-DBUILD_TOOLS=OFF \
-DBUILD_REGRESS=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_DOC=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_PREFIX_PATH=$PWD/../../../emscripten-deps/install \
-DZLIB_DIR=$PWD/../../../emscripten-deps/install/lib/cmake/ZLIB \
-DCMAKE_INSTALL_PREFIX=$PWD/../../../emscripten-deps/install
emmake make -j4
emmake make install
# Patch the installed libzip config to not require ZLIB::ZLIB
echo "Patching libzip config to work with Emscripten..."
sed -i 's/ZLIB::ZLIB/z/g' $PWD/../../../emscripten-deps/install/lib/cmake/libzip/libzip-targets.cmake || true
sed -i 's/INTERFACE_LINK_LIBRARIES "ZLIB::ZLIB"/INTERFACE_LINK_LIBRARIES "z"/g' $PWD/../../../emscripten-deps/install/lib/cmake/libzip/libzip-targets.cmake || true
# Debug: Check what was actually installed
echo "Checking installed files for libzip:"
ls -la $PWD/../../../emscripten-deps/install/lib/cmake/ || true
ls -la $PWD/../../../emscripten-deps/install/lib/ || true
cd ../..
fi
# Install nlohmann_json (use single header version for simplicity)
echo "Installing nlohmann_json..."
mkdir -p install/include/nlohmann
wget https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp \
-O install/include/nlohmann/json.hpp
# Create a minimal CMake config for nlohmann_json
mkdir -p install/lib/cmake/nlohmann_json
cat > install/lib/cmake/nlohmann_json/nlohmann_jsonConfig.cmake << 'EOF'
# Config file for nlohmann_json
set(nlohmann_json_FOUND TRUE)
set(nlohmann_json_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../../include")
if(NOT TARGET nlohmann_json::nlohmann_json)
add_library(nlohmann_json::nlohmann_json INTERFACE IMPORTED)
set_target_properties(nlohmann_json::nlohmann_json PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/../../../include"
)
endif()
EOF
echo "nlohmann_json installed as single header"
# Verify nlohmann_json installation
echo "Verifying nlohmann_json installation:"
ls -la install/include/nlohmann/ || echo "Include directory not found"
ls -la install/lib/cmake/nlohmann_json/ || echo "CMake config directory not found"
cat install/lib/cmake/nlohmann_json/nlohmann_jsonConfig.cmake || echo "Config file not found"
# Build tinyxml2
if [ ! -d "tinyxml2-10.0.0" ]; then
wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz
tar -xzf 10.0.0.tar.gz
cd tinyxml2-10.0.0
mkdir -p build && cd build
emcmake cmake .. \
-Dtinyxml2_BUILD_TESTING=OFF \
-DCMAKE_INSTALL_PREFIX=$PWD/../../../emscripten-deps/install
emmake make -j4
emmake make install
cd ../..
fi
# Build spdlog (use older version that works better with Emscripten)
echo "Building spdlog..."
if [ ! -d "spdlog-1.12.0" ]; then
echo "Building spdlog 1.12.0 (better Emscripten compatibility)..."
wget https://github.com/gabime/spdlog/archive/refs/tags/v1.12.0.tar.gz -O spdlog-1.12.0.tar.gz
tar -xzf spdlog-1.12.0.tar.gz
cd spdlog-1.12.0
mkdir -p build && cd build
# Configure as header-only to avoid compilation issues
emcmake cmake .. \
-DSPDLOG_BUILD_EXAMPLE=OFF \
-DSPDLOG_BUILD_TESTS=OFF \
-DSPDLOG_BUILD_BENCH=OFF \
-DSPDLOG_INSTALL=ON \
-DSPDLOG_HEADER_ONLY=ON \
-DSPDLOG_FMT_EXTERNAL=OFF \
-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_INSTALL_PREFIX=$PWD/../../../emscripten-deps/install
emmake make -j4
emmake make install
cd ../..
fi
# Comprehensive dependency verification
echo "=== Verifying all installed dependencies ==="
echo "Current directory: $PWD"
echo ""
echo "1. Checking zlib (Emscripten port):"
ls -la install/lib/cmake/ZLIB/ || echo "ZLIB cmake config not found"
echo ""
echo "2. Checking SDL2 (Emscripten port):"
ls -la install/lib/cmake/SDL2/ || echo "SDL2 cmake config not found"
echo ""
echo "3. Checking libzip:"
ls -la install/lib/cmake/libzip/ || echo "libzip cmake config not found"
ls -la install/lib/*libzip* || echo "libzip library not found"
echo ""
echo "4. Checking nlohmann_json:"
ls -la install/include/nlohmann/json.hpp || echo "json.hpp not found"
ls -la install/lib/cmake/nlohmann_json/nlohmann_jsonConfig.cmake || echo "nlohmann_json cmake config not found"
echo ""
echo "5. Checking tinyxml2:"
ls -la install/lib/cmake/tinyxml2/ || echo "tinyxml2 cmake config not found"
ls -la install/lib/*tinyxml2* || echo "tinyxml2 library not found"
echo ""
echo "6. Checking spdlog:"
ls -la install/lib/cmake/spdlog/ || echo "spdlog cmake config not found"
ls -la install/lib/*spdlog* || echo "spdlog library not found"
echo ""
echo "All CMake configs in install/lib/cmake:"
find install/lib/cmake -name "*Config.cmake" -o -name "*config.cmake" 2>/dev/null || echo "No cmake configs found"
echo ""
echo "Complete install directory structure:"
find install -type d | head -30
- name: Configure CMake for Emscripten
run: |
export EMSCRIPTEN=1
export CMAKE_PREFIX_PATH=$PWD/emscripten-deps/install
# Ensure Emscripten's zlib is available
export CFLAGS="-s USE_ZLIB=1 -s USE_LIBPNG=1"
export LDFLAGS="-s USE_ZLIB=1 -s USE_LIBPNG=1"
# Help CMake find all libraries specifically
export ZLIB_DIR=$PWD/emscripten-deps/install/lib/cmake/ZLIB
export SDL2_DIR=$PWD/emscripten-deps/install/lib/cmake/SDL2
export libzip_DIR=$PWD/emscripten-deps/install/lib/cmake/libzip
export nlohmann_json_DIR=$PWD/emscripten-deps/install/lib/cmake/nlohmann_json
export tinyxml2_DIR=$PWD/emscripten-deps/install/lib/cmake/tinyxml2
export spdlog_DIR=$PWD/emscripten-deps/install/lib/cmake/spdlog
# Debug: verify paths exist before configuring
echo "Verifying CMake config paths before configuration:"
echo "ZLIB_DIR: $ZLIB_DIR"
ls -la $ZLIB_DIR/*.cmake 2>/dev/null || echo "ZLIB config not found"
echo "libzip_DIR: $libzip_DIR"
ls -la $libzip_DIR/*.cmake 2>/dev/null || echo "libzip config not found"
echo "nlohmann_json_DIR: $nlohmann_json_DIR"
ls -la $nlohmann_json_DIR/*.cmake 2>/dev/null || echo "nlohmann_json config not found"
echo "tinyxml2_DIR: $tinyxml2_DIR"
ls -la $tinyxml2_DIR/*.cmake 2>/dev/null || echo "tinyxml2 config not found"
echo "spdlog_DIR: $spdlog_DIR"
ls -la $spdlog_DIR/*.cmake 2>/dev/null || echo "spdlog config not found"
emcmake cmake -S . -B build-emscripten \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_PREFIX_PATH=$PWD/emscripten-deps/install \
-DZLIB_DIR=$PWD/emscripten-deps/install/lib/cmake/ZLIB \
-DSDL2_DIR=$PWD/emscripten-deps/install/lib/cmake/SDL2 \
-Dlibzip_DIR=$PWD/emscripten-deps/install/lib/cmake/libzip \
-Dnlohmann_json_DIR=$PWD/emscripten-deps/install/lib/cmake/nlohmann_json \
-Dtinyxml2_DIR=$PWD/emscripten-deps/install/lib/cmake/tinyxml2 \
-Dspdlog_DIR=$PWD/emscripten-deps/install/lib/cmake/spdlog \
-DCMAKE_C_FLAGS="-s USE_ZLIB=1 -s USE_LIBPNG=1 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1" \
-DCMAKE_CXX_FLAGS="-s USE_ZLIB=1 -s USE_LIBPNG=1 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -DSPDLOG_HEADER_ONLY" \
-DCMAKE_EXE_LINKER_FLAGS="-s USE_ZLIB=1 -s USE_LIBPNG=1 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2" \
-DBUILD_CROWD_CONTROL=OFF \
-DBUILD_REMOTE_CONTROL=OFF \
-DSUPPRESS_WARNINGS=ON \
-DUSE_OPENGLES=ON
- name: Build soh.o2r
run: |
cmake --build build-emscripten --target GenerateSohOtr || true
# Copy any existing OTR files if the build step fails
if [ -f "soh/soh.o2r" ]; then
cp soh/soh.o2r build-emscripten/soh/
fi
- name: Build Ship of Harkinian for Web
run: |
cmake --build build-emscripten --config Release
- name: Prepare Web Distribution
run: |
mkdir -p web-dist
cp build-emscripten/soh/soh.html web-dist/index.html || true
cp build-emscripten/soh/soh.js web-dist/ || true
cp build-emscripten/soh/soh.wasm web-dist/ || true
cp build-emscripten/soh/soh.data web-dist/ || true
cp web/index.html web-dist/index.html || true
# Copy OTR files if available
if [ -f "build-emscripten/soh/soh.o2r" ]; then
cp build-emscripten/soh/soh.o2r web-dist/
fi
- name: Upload Web Build Artifact
uses: actions/upload-artifact@v4
with:
name: soh-web-build
path: web-dist/
retention-days: 7
- name: Deploy to GitHub Pages (optional)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./web-dist
destination_dir: web
keep_files: true
test-web-build:
needs: build-emscripten
runs-on: ubuntu-latest
steps:
- name: Download Web Build
uses: actions/download-artifact@v3
with:
name: soh-web-build
path: web-dist/
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install HTTP Server
run: npm install -g http-server
- name: Test Web Server
run: |
# Start HTTP server in background
http-server web-dist -p 8080 &
SERVER_PID=$!
# Wait for server to start
sleep 5
# Check if files are accessible
curl -f http://localhost:8080/index.html || exit 1
curl -f http://localhost:8080/soh.js || exit 1
curl -f http://localhost:8080/soh.wasm || exit 1
# Kill the server
kill $SERVER_PID
- name: Validate Build Files
run: |
# Check file sizes
echo "Build file sizes:"
ls -lh web-dist/
# Verify WASM file
file web-dist/soh.wasm | grep WebAssembly || exit 1
# Check JavaScript file
if [ ! -s web-dist/soh.js ]; then
echo "Error: soh.js is empty"
exit 1
fi