Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
208 changes: 168 additions & 40 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,70 +13,187 @@ jobs:
include:
- os: ubuntu-latest
name: Linux x64
toolchain: clang
- os: macos-15
name: macOS Apple Silicon
toolchain: clang
# - os: windows-latest
# name: Windows MSVC
# toolchain: msvc
- os: windows-latest
name: Windows MSVC
name: Windows Clang
toolchain: clang

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Dependencies (Linux)
- name: Install Build Tools (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y cmake ninja-build g++ clang libsqlite3-dev git libgrpc++-dev protobuf-compiler-grpc libspdlog-dev
sudo apt-get install -y cmake ninja-build g++ clang pkg-config

- name: Install Dependencies (macOS)
- name: Install Build Tools (macOS)
if: runner.os == 'macOS'
run: |
brew install cmake ninja sqlite pkg-config grpc protobuf spdlog
brew install cmake ninja pkg-config

- name: Cache Boost
id: cache-boost
uses: actions/cache@v4
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: third_party/boost
key: boost-1.90.0-${{ runner.os }}
key: ${{ runner.os }}-${{ matrix.toolchain }}-ccache

- name: Setup ccache
- name: Setup MSVC Developer Command Prompt
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1

- name: Select Windows storage for vcpkg
if: runner.os == 'Windows'
id: win_storage
shell: pwsh
run: |
$candidates = @()
foreach ($p in @($env:RUNNER_TEMP, $env:GITHUB_WORKSPACE, 'D:\', 'C:\')) {
if (-not $p) { continue }
if (-not (Test-Path $p)) { continue }
$resolved = (Resolve-Path $p).Path
$qualifier = Split-Path -Qualifier $resolved
$driveName = $qualifier.TrimEnd('\').TrimEnd(':')
$drive = Get-PSDrive -Name $driveName -ErrorAction SilentlyContinue
if ($drive) {
$candidates += [pscustomobject]@{
Root = $qualifier
Free = [int64]$drive.Free
}
}
}

if (-not $candidates) {
throw "Could not determine a writable storage location for vcpkg."
}

$best = $candidates | Sort-Object Free -Descending | Select-Object -First 1
$base = Join-Path $best.Root "vcpkg-cache"

$archives = Join-Path $base "archives"
$downloads = Join-Path $base "downloads"
$buildtrees = Join-Path $base "buildtrees"
$packages = Join-Path $base "packages"

New-Item -ItemType Directory -Force -Path $archives, $downloads, $buildtrees, $packages | Out-Null

"VCPKG_DEFAULT_BINARY_CACHE=$archives" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"VCPKG_DOWNLOADS=$downloads" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

"vcpkg_cache_dir=$archives" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"vcpkg_downloads_dir=$downloads" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append

# --- THE FIX: Create Junctions to redirect C: to D: ---
# 1. Remove existing directories if GitHub pre-created them
Remove-Item -Path "C:\vcpkg\buildtrees" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "C:\vcpkg\packages" -Recurse -Force -ErrorAction SilentlyContinue

# 2. Create the junctions
New-Item -ItemType Junction -Path "C:\vcpkg\buildtrees" -Target $buildtrees | Out-Null
New-Item -ItemType Junction -Path "C:\vcpkg\packages" -Target $packages | Out-Null

# --- PROOF OF REDIRECTION ---
Write-Host "Testing the Junctions..."
Set-Content -Path "C:\vcpkg\buildtrees\proof.txt" -Value "This is actually on the D drive!"
if (Test-Path "$buildtrees\proof.txt") {
Write-Host "SUCCESS: C:\vcpkg\buildtrees is successfully routing to the D: drive!"
} else {
Write-Error "FAILURE: Junction didn't work."
}

$bestGb = [math]::Round($best.Free / 1GB, 2)
Write-Host "Selected vcpkg storage root: $($best.Root)"
Write-Host "Selected drive free space: $bestGb GB"

- name: Restore vcpkg binary archives (Unix)
if: runner.os != 'Windows'
uses: hendrikmuhs/ccache-action@v1.2
id: vcpkg_cache_restore_unix
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-ccache
path: ~/.cache/vcpkg/archives
key: vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
restore-keys: |
vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-

- name: Cache vcpkg dependencies
- name: Restore vcpkg binary archives (Windows)
if: runner.os == 'Windows'
uses: actions/cache@v4
id: vcpkg_cache_restore_windows
uses: actions/cache/restore@v4
with:
path: build/vcpkg_installed
key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }}
path: ${{ steps.win_storage.outputs.vcpkg_cache_dir }}
key: vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
restore-keys: |
vcpkg-${{ runner.os }}-
vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-

- name: Clone Boost
if: steps.cache-boost.outputs.cache-hit != 'true'
shell: bash
- name: Ensure vcpkg baseline commit is available (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p third_party
git clone --branch boost-1.90.0 https://github.com/boostorg/boost.git third_party/boost
cd third_party/boost
git submodule update --init --recursive
BASELINE=$(python3 -c "import json; print(json.load(open('vcpkg.json', encoding='utf-8'))['builtin-baseline'])")
git -C "$VCPKG_INSTALLATION_ROOT" fetch --no-tags origin "$BASELINE" || git -C "$VCPKG_INSTALLATION_ROOT" fetch --tags --prune origin
git -C "$VCPKG_INSTALLATION_ROOT" cat-file -e "${BASELINE}^{commit}"

- name: Ensure vcpkg baseline commit is available (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$baseline = (Get-Content vcpkg.json | ConvertFrom-Json).'builtin-baseline'
git -C "$env:VCPKG_INSTALLATION_ROOT" fetch --no-tags origin $baseline
if ($LASTEXITCODE -ne 0) {
git -C "$env:VCPKG_INSTALLATION_ROOT" fetch --tags --prune origin
}
git -C "$env:VCPKG_INSTALLATION_ROOT" cat-file -e "$baseline`^{commit}"

- name: Configure CMake (Unix)
if: runner.os != 'Windows'
run: cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DBOOST_SOURCE_DIR=${{ github.workspace }}/third_party/boost
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
TRIPLET="x64-linux" # vcpkg's x64-linux defaults to static libraries
else
TRIPLET="arm64-osx-release" # Force static linking on macOS
fi

cmake -G Ninja -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_TARGET_TRIPLET=$TRIPLET

- name: Save vcpkg binary archives (Unix)
if: ${{ runner.os != 'Windows' && always() && steps.vcpkg_cache_restore_unix.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: ~/.cache/vcpkg/archives
key: vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}

- name: Build (Unix)
if: runner.os != 'Windows'
run: cmake --build build --config Release

- name: Configure CMake (Windows)
if: runner.os == 'Windows'
run: cmake -B build -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static -DRPS_MSVC_STATIC_RUNTIME=ON -DBOOST_SOURCE_DIR="${{ github.workspace }}/third_party/boost"
- name: Configure CMake (Windows MSVC)
if: runner.os == 'Windows' && matrix.toolchain == 'msvc'
run: cmake -G Ninja -B build -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DRPS_MSVC_STATIC_RUNTIME=ON

- name: Configure CMake (Windows Clang)
if: runner.os == 'Windows' && matrix.toolchain == 'clang'
run: cmake -G Ninja -B build -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DRPS_MSVC_STATIC_RUNTIME=ON

- name: Save vcpkg binary archives (Windows)
if: ${{ runner.os == 'Windows' && always() && steps.vcpkg_cache_restore_windows.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: ${{ steps.win_storage.outputs.vcpkg_cache_dir }}
key: vcpkg-archives-${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}

- name: Build (Windows)
if: runner.os == 'Windows'
Expand All @@ -92,22 +209,33 @@ jobs:
cp build/apps/rps-vstscannermaster/vstscannermaster release_stage/
cp build/examples/cpp/rps-example-client release_stage/
cd release_stage
zip -r ../rps-binaries-${{ matrix.os }}.zip ./*
zip -r "../rps-binaries-${{ matrix.name }}.zip" ./*

- name: Stage & Zip Binaries (Windows)
if: runner.os == 'Windows'
- name: Stage & Zip Binaries (Windows MSVC)
if: runner.os == 'Windows' && matrix.toolchain == 'msvc'
run: |
New-Item -ItemType Directory -Force -Path release_stage
Copy-Item build\apps\rps-server\rps-server.exe release_stage\
Copy-Item build\apps\rps-standalone\rps-standalone.exe release_stage\
Copy-Item build\apps\rps-pluginscanner\rps-pluginscanner.exe release_stage\
Copy-Item build\apps\rps-vstscannermaster\vstscannermaster.exe release_stage\
Copy-Item build\examples\cpp\rps-example-client.exe release_stage\
Compress-Archive -Path release_stage\* -DestinationPath "rps-binaries-${{ matrix.name }}.zip"

- name: Stage & Zip Binaries (Windows Clang)
if: runner.os == 'Windows' && matrix.toolchain == 'clang'
run: |
New-Item -ItemType Directory -Force -Path release_stage
Copy-Item build\apps\rps-server\Release\rps-server.exe release_stage\
Copy-Item build\apps\rps-standalone\Release\rps-standalone.exe release_stage\
Copy-Item build\apps\rps-pluginscanner\Release\rps-pluginscanner.exe release_stage\
Copy-Item build\apps\rps-vstscannermaster\Release\vstscannermaster.exe release_stage\
Copy-Item build\examples\cpp\Release\rps-example-client.exe release_stage\
Compress-Archive -Path release_stage\* -DestinationPath rps-binaries-${{ matrix.os }}.zip
Copy-Item build\apps\rps-server\rps-server.exe release_stage\
Copy-Item build\apps\rps-standalone\rps-standalone.exe release_stage\
Copy-Item build\apps\rps-pluginscanner\rps-pluginscanner.exe release_stage\
Copy-Item build\apps\rps-vstscannermaster\vstscannermaster.exe release_stage\
Copy-Item build\examples\cpp\rps-example-client.exe release_stage\
Compress-Archive -Path release_stage\* -DestinationPath "rps-binaries-${{ matrix.name }}.zip"

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: rps-binaries-${{ matrix.os }}
path: rps-binaries-${{ matrix.os }}.zip
name: rps-binaries-${{ matrix.name }}
path: rps-binaries-${{ matrix.name }}.zip
retention-days: 7
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ kiloHearts.log

.vscode

plans/
plans/
build_ninja_msvc/vcpkg-manifest-install.log
build_ninja_msvc/CMakeCache.txt
build_ninja_msvc/CMakeFiles/cmake.check_cache

_private
69 changes: 40 additions & 29 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@ cmake_minimum_required(VERSION 3.25)
cmake_policy(SET CMP0167 NEW)

project(rps-plugin-scanner
VERSION 0.2.0
DESCRIPTION "Reliable Plugin Scanner"
VERSION 0.2.1
DESCRIPTION "RPS"
LANGUAGES C CXX
)

# x64-windows* vcpkg triplets produce MSVC-ABI binaries. Using GNU-targeting
# clang++ (e.g. MSYS2 clang64) with those libraries causes linker failures
# such as missing LIBCMTD/OLDNAMES import libs.
if(WIN32
AND VCPKG_TARGET_TRIPLET MATCHES "^x64-windows"
AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
message(FATAL_ERROR
"Incompatible toolchain combination detected:\n"
" compiler: ${CMAKE_CXX_COMPILER}\n"
" triplet: ${VCPKG_TARGET_TRIPLET}\n\n"
"The selected vcpkg triplet uses MSVC ABI libraries, but this clang++ "
"targets GNU/MinGW. Use one of:\n"
" 1) clang-cl or cl.exe with -DVCPKG_TARGET_TRIPLET=x64-windows-static\n"
" 2) clang++ with a MinGW triplet (for example x64-mingw-static).")
endif()

# Enforce strictly C++23
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -21,11 +38,17 @@ else()
option(RPS_MSVC_STATIC_RUNTIME "Use static MSVC runtime (/MT)" OFF)
endif()

if(MSVC AND RPS_MSVC_STATIC_RUNTIME)
if(WIN32
AND RPS_MSVC_STATIC_RUNTIME
AND (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# Resolve LNK4098 by ignoring the runtime we're not using for each config
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:LIBCMTD")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:LIBCMT")
# Resolve LNK4098 by ignoring the runtime we're not using for each config.
# Keep this only for cl.exe-style drivers; clang++ (MSVC target) does not
# accept raw '/NODEFAULTLIB:...' in CMAKE_EXE_LINKER_FLAGS.
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:LIBCMTD")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:LIBCMT")
endif()
endif()

# Disable Boost Auto-Linking on Windows (CMake handles libraries explicitly)
Expand All @@ -35,7 +58,6 @@ add_definitions(-DBOOST_ALL_NO_LIB)
add_library(rps_warnings INTERFACE)
if(MSVC)
target_compile_options(rps_warnings INTERFACE /W4 /WX /permissive-)
target_compile_definitions(rps_warnings INTERFACE NOMINMAX WIN32_LEAN_AND_MEAN)
else()
target_compile_options(rps_warnings INTERFACE -Wall -Wextra -Wpedantic -Werror)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand All @@ -44,33 +66,22 @@ else()
endif()
endif()

if(WIN32)
target_compile_definitions(rps_warnings INTERFACE
NOMINMAX
WIN32_LEAN_AND_MEAN
_CRT_SECURE_NO_WARNINGS
)
endif()

# Force static linking
if(WIN32 AND NOT MSVC)
if(WIN32 AND NOT MSVC AND NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
endif()

# Boost: build from local source tree via add_subdirectory
# Override with: cmake -DBOOST_SOURCE_DIR=/path/to/boost
# or: export BOOST_SOURCE_DIR=/path/to/boost && cmake -B build
if(DEFINED ENV{BOOST_SOURCE_DIR} AND NOT DEFINED BOOST_SOURCE_DIR)
set(BOOST_SOURCE_DIR "$ENV{BOOST_SOURCE_DIR}" CACHE PATH "Path to Boost source tree (requires Boost 1.90+)")
else()
set(BOOST_SOURCE_DIR "${CMAKE_SOURCE_DIR}/third_party/boost" CACHE PATH "Path to Boost source tree (requires Boost 1.90+)")
endif()
if(NOT EXISTS "${BOOST_SOURCE_DIR}/CMakeLists.txt")
message(FATAL_ERROR
"Boost CMake source tree not found at: ${BOOST_SOURCE_DIR}\n"
"Note: The official boost.org tarball does NOT include CMake support.\n"
"You must clone Boost from GitHub:\n"
" git clone https://github.com/boostorg/boost.git /path/to/boost\n"
" cd /path/to/boost && git checkout boost-1.90.0\n"
" git submodule update --init --recursive\n"
"Then pass: cmake -DBOOST_SOURCE_DIR=/path/to/boost\n"
)
endif()
set(BOOST_INCLUDE_LIBRARIES json program_options filesystem process interprocess uuid dll date_time)
add_subdirectory(${BOOST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/_deps/boost EXCLUDE_FROM_ALL)
# Boost: managed entirely by vcpkg
find_package(Boost REQUIRED COMPONENTS json program_options filesystem process interprocess uuid dll date_time crc)

# Find SQLite3
# Prefer the static library; fall back to shared via find_package
Expand Down
Loading
Loading