Skip to content

Add CI #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci"
- "actions"
- package-ecosystem: "gitsubmodule"
directory: "/"
schedule:
interval: "daily"
labels:
- "mods"
139 changes: 139 additions & 0 deletions .github/workflows/build-mod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
name: Build mod

on:
workflow_call:
inputs:
target_name:
required: true
type: string
workflow_dispatch:
inputs:
target_name:
required: true
type: string

env:
WASI_SDK_URL: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb
CROSS_COMPILE_PACKAGES: libc6-dev-armhf-cross libgcc-s1-armhf-cross libgcc-13-dev-armhf-cross libc6-dev-i386-cross libgcc-s1-i386-cross libgcc-13-dev-i386-cross
# Workaround for missing compiled library in the WASI SDK
LIBCLANG_RT_BUILTINS_WASM32_A_URL: http://cdn.jsdelivr.net/gh/jedisct1/libclang_rt.builtins-wasm32.a/precompiled/llvm-19/libclang_rt.builtins-wasm32.a

jobs:
build:
name: ${{ matrix.target.platform }} ${{ matrix.target.arch }}
strategy:
fail-fast: false
matrix:
target:
- runner: ubuntu-latest
platform: wasm
arch: wasm
- runner: macos-latest
platform: darwin
arch: aarch64
- runner: macos-13
platform: darwin
arch: x86_64
- runner: ubuntu-latest
platform: linux
arch: x86
- runner: ubuntu-latest
platform: linux
arch: x86_64
- runner: ubuntu-24.04-arm
platform: linux
arch: aarch64
- runner: ubuntu-24.04-arm
platform: linux
arch: armhf
- runner: windows-latest
platform: windows
arch: x86
- runner: windows-latest
platform: windows
arch: x86_64
runs-on: ${{ matrix.target.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
ref: ${{ github.ref }}

# WASM build
- name: Install WASI SDK
if: matrix.target.arch == 'wasm'
run: |
curl -LO ${{ env.WASI_SDK_URL }} && \
sudo dpkg -i wasi-sdk-*-x86_64-linux.deb && \
rm *.deb && \
sudo curl -L ${{ env.LIBCLANG_RT_BUILTINS_WASM32_A_URL }} \
--output /opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi/libclang_rt.builtins-wasm32.a && \
ln -s /opt/wasi-sdk/share/wasi-sysroot wasm/wasi-sysroot
- name: Build ${{ inputs.target_name }} wasm
if: matrix.target.arch == 'wasm'
run: |
export PATH=$PATH:/opt/wasi-sdk/bin/ && \
cd wasm && \
python3 compile_mod.py ${{ inputs.target_name }}

# Native build
- name: Set cmake generator
if: matrix.target.arch != 'wasm'
shell: bash
run: |
if [[ ${{ runner.os }} == "Windows" ]]; then
export CMAKE_GENERATOR="Makefile" >> $GITHUB_ENV
else
export CMAKE_GENERATOR="Ninja" >> $GITHUB_ENV
fi
- name: Install 32bit cross-compilation libs
if: (matrix.target.arch == 'x86' || matrix.target.arch == 'armhf') && matrix.target.platform == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y ${{ env.CROSS_COMPILE_PACKAGES }}
- name: Build ${{ inputs.target_name }} ${{ matrix.target.platform }} ${{ matrix.target.arch }}
id: build
if: matrix.target.arch != 'wasm'
uses: threeal/cmake-action@v2.1.0
with:
generator: ${{ env.CMAKE_GENERATOR }}
cxx-compiler: clang++
c-compiler: clang
build-dir: build
build-args: --target ${{ inputs.target_name }}
options: |
Q2_BUILD_ARCH=${{ matrix.target.arch }}
CMAKE_BUILD_TYPE=RelWithDebInfo

- name: Find build output path
shell: bash
run: |
if [[ -z "${{ steps.build.outputs.build-dir }}" ]]; then
export ARTIFACT_PATH=$(pwd)/bin/${{ inputs.target_name }}
else
export ARTIFACT_PATH=${{ steps.build.outputs.build-dir }}/bin/${{ inputs.target_name }}
fi

mkdir -p $ARTIFACT_PATH/${{ matrix.target.platform }}

if [[ "${{ matrix.target.platform }}" == "windows" ]]; then
mv build/Debug/* $ARTIFACT_PATH/${{ matrix.target.platform }}/
elif [[ "${{ matrix.target.platform }}" == "wasm" ]]; then
find . -type f -name "game.wasm" -exec mv '{}' $ARTIFACT_PATH/${{ matrix.target.platform }}/ \;
rm -rf bin/ctc/obj
fi

echo ARTIFACT_PATH=$ARTIFACT_PATH >> $GITHUB_ENV
echo $ARTIFACT_PATH
ls -la $ARTIFACT_PATH/${{ matrix.target.platform }}
if [[ "${{ matrix.target.platform }}" == "linux" ]]; then
file $ARTIFACT_PATH/${{ matrix.target.platform }}/game${{ matrix.target.arch }}.so
fi

- name: Store builds
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.target_name }}-${{ matrix.target.platform }}-${{ matrix.target.arch }}
path: ${{ env.ARTIFACT_PATH }}
105 changes: 105 additions & 0 deletions .github/workflows/build-mods.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
name: Build mods

on:
workflow_dispatch:
inputs:
mods:
type: string
description: mod names to build (empty for all)
push:
paths:
- "sources/*"
branches:
- main
pull_request:

jobs:
builds:
name: Collect targets
runs-on: ubuntu-latest
outputs:
mods: ${{ steps.builds.outputs.modlist }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: Get changed files
if: ${{ github.event_name }} == "push"
id: changed_files_action
uses: tj-actions/changed-files@v45
with:
files: sources/*
- name: Get list of mods to build
id: builds
run: |
# Figure out which manifests need building
if [[ "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "pull_request" ]]; then
export MODS="${{ steps.changed_files_action.outputs.all_changed_files }}"
elif [[ "${{ inputs.mods }}" != "" ]]; then
export MODS="${{ inputs.mods }}"
fi
echo "::group::Mods"
echo "MODLIST=$(python3 get_mod_list.py)" >> $GITHUB_OUTPUT
echo $MODLIST | jq
echo "::endgroup::"

build-mod:
name: ${{ matrix.target }}
needs: builds
strategy:
fail-fast: false
matrix:
target: ${{ fromJson(needs.builds.outputs.mods) }}
uses: ./.github/workflows/build-mod.yml
with:
target_name: ${{ matrix.target }}

assemble-release:
name: Assemble release for ${{ matrix.target }}
if: always()
needs: [builds, build-mod]
strategy:
matrix:
target: ${{ fromJson(needs.builds.outputs.mods) }}
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Merge artifacts for ${{ matrix.target }}
if: ${{ github.ref != 'refs/heads/main' }}
uses: actions/upload-artifact/merge@v4
with:
pattern: ${{ matrix.target }}-*
name: ${{ matrix.target }}-${github_sha_short}
- name: Download artifacts for ${{ matrix.target }}
if: ${{ github.ref == 'refs/heads/main' }}
uses: actions/download-artifact@v4
with:
pattern: ${{ matrix.target }}-*
merge-multiple: true
path: build
- name: Create merged artifact
if: ${{ github.ref == 'refs/heads/main' }}
shell: bash
run: |
export github_sha_hash=${{ github.sha }}
export github_sha_short="${github_sha_hash:0:7}"
echo "COMMIT_SHORT=$github_sha_short" >> $GITHUB_ENV
cd build
tar cvzf ${{ matrix.target }}-${github_sha_short}.tar.gz *
- name: Create release
if: ${{ github.ref == 'refs/heads/main' }}
uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af
with:
allowUpdates: true
artifactErrorsFailBuild: true
artifacts: build/${{ matrix.target }}-${{ env.COMMIT_SHORT }}.tar.gz
commit: ${{ github.sha }}
tag: ${{ env.COMMIT_SHORT }}
name: ${{ matrix.target }} ${{ env.COMMIT_SHORT }}
generateReleaseNotes: true
removeArtifacts: true
replacesArtifacts: true
makeLatest: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
/wasm/libclang_rt.builtins-wasm32.a
/sources/baseq2/src
/sources/ctf/src
build
82 changes: 82 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.10)
project(q2mods)

# Variables used to control destination filenames and 32bit builds
string(TOLOWER ${CMAKE_SYSTEM_NAME} OS_HANDLE)
option(Q2_BUILD_ARCH "Target architecture to build (default: host architecture)" ${CMAKE_SYSTEM_PROCESSOR})

# Add cmake module path for special-case modules for certain mods
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# Loop over all subdirectories in `sources` and add each one as a mod target to build
file(GLOB MODS LIST_DIRECTORIES true "sources/*")
foreach(item ${MODS})
if(IS_DIRECTORY ${item})
cmake_path(GET item FILENAME mod)

# If we have a special-case cmake module for the mod, use that
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/mods/${mod}.cmake")
message(STATUS "Adding mod: cmake/mods/${mod}.cmake")
include(mods/${mod})

# Otherwise assume a standard mod setup
else()
set(MOD_SRC "")
file(GLOB MOD_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/*.C"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/*.H"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/src/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/src/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/src/*.C"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/${mod}/src/*.H"
)

# Warn on mods that don't find source files with the above setup
# so special case modules can be added
if(NOT MOD_SRC)
message(WARNING "No source files found for ${mod}")
else()
message("-- Adding mod: ${mod}")
add_library(${mod} SHARED ${MOD_SRC})
set_target_properties(${mod} PROPERTIES PREFIX "")
set_target_properties(${mod} PROPERTIES OUTPUT_NAME "bin/${mod}/${OS_HANDLE}/game${Q2_BUILD_ARCH}")
file(MAKE_DIRECTORY bin/${mod}/${OS_HANDLE})

# Handle 32bit builds
if(LINUX)
if (Q2_BUILD_ARCH STREQUAL "x86")
target_include_directories(${mod} SYSTEM BEFORE PUBLIC /usr/i686-linux-gnu/include)
target_compile_options(${mod} PUBLIC -m32)
target_link_directories(${mod} BEFORE PUBLIC
/usr/i686-linux-gnu/lib
/usr/lib/gcc-cross/i686-linux-gnu/13
)
target_link_options(${mod} PUBLIC -m32)
elseif (Q2_BUILD_ARCH STREQUAL "armhf")
target_include_directories(${mod} SYSTEM BEFORE PUBLIC /usr/arm-linux-gnueabihf/include)
target_compile_options(${mod} PUBLIC -m32 -mfloat-abi=hard -target arm-linux-gnueabihf)
target_link_directories(${mod} BEFORE PUBLIC
/usr/arm-linux-gnueabihf/lib
/usr/lib/gcc-cross/arm-linux-gnueabihf/13
)
target_link_options(${mod} PUBLIC -m32 -mfloat-abi=hard -target arm-linux-gnueabihf)
endif()
endif()

endif()
endif()

if(TARGET ${mod})
set_target_properties(${mod} PROPERTIES
PREFIX ""
OUTPUT_NAME "game${Q2_BUILD_ARCH}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${mod}/${OS_HANDLE}/"
CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${mod}/${OS_HANDLE}/"
)
endif()

endif()
endforeach()

28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
# Quake II Source Archive

This is an archive of Quake II game/mod sources. The repo will be used to compile cross-platform/cross-arch WASM binaries.
This is a sister project to https://github.com/Paril/quake2-wasm which provides an implementation of a game library that hosts a WebAssembly runtime, which can then load WASM binaries as game libraries. This allows game libraries to be cross-platform and compatible, no matter where they are run. As of this writing, the game DLL is the only implementation available, but the goal is to allow engines to implement this system down the road.

# Licenses

Licenses per-mod are included in the mods' source folders.

# How to Help

Submit sources to mods as issues, and we'll handle the rest. If the mod is actively maintained, submit the repository link.

# Sources in Repos

Currently, we're embedding the sources in this repo, however the plan for actively-maintained sources is to instead link them either via submodule or as a Python script to fetch their source, and use patches to fix any major code issues. We'll also likely submit patches back to the repo with explanations of our fixes, in case they are interested.

# How to Compile
In the `wasm` folder, do `py compile_mod.py <name> [debug|release]` to compile an individual mod. By default, debug is implied, but anything other than debug will result in a release build. To compile every mod, do `py compile_mods.py [debug|release]`.

## wasm only

You will need Python 3 and the [WASI SDK](https://github.com/WebAssembly/wasi-sdk) installed. For help installing the WASI SDK for use with this repository, check [the CI workflow](https://github.com/fpiesche/quake2-source-archive/blob/7e886d427086ba535541b57b6e33fd56c1d2aec1/.github/workflows/build-mod.yml#L65).

```bash
$ cd wasm
$ python3 ./compile_mods.py [debug|release] # build all mods
$ python3 ./compile_mod.py <mod name> [debug|release] # build a specific mod
```

## cmake

Ensure that the WASI SDK (see above), Python 3 and CMake are installed; [Ninja](https://ninja-build.org/) is an optional component that will speed up builds. If you want to be able to make cross-platform builds (eg. x86 built on an x86_64 machine), you'll also need the appropriate cross-compile packages. You can find a list of these (for Ubuntu running on x86_64) in [the GitHub workflow](https://github.com/fpiesche/quake2-source-archive/blob/7e886d427086ba535541b57b6e33fd56c1d2aec1/.github/workflows/build-mod.yml#L18).

```bash
$ mkdir build
$ cd build
$ cmake -GNinja .. # Configure build for current platform
$ cmake -GNinja -DQ2_BUILD_ARCH=[x86|x86_64|armhf|aarch64] # Configure builds for cross-compilation (eg. building 32bit x86 on a 64-bit system)
$ cmake --build . # build all mods
$ cmake --build . --target <mod name> # build only a specific mod
```
Loading