Skip to content
Merged
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
113 changes: 113 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: Binary release

on:
pull_request:
paths:
- .github/workflows/release.yml
- CMakeLists.txt
- cmake/**
- ci/release/**
- keygen-rs/**
- src/**
- tools/**
- contrib/**
- scripts/build-release.sh
- scripts/build-release.ps1
- scripts/test/release.py
- scripts/test/windows.py
push:
tags: ['v*-cuda-only']
workflow_dispatch:

permissions:
contents: read

jobs:
linux-cuda:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- name: Build release image
run: docker build -t xchplot2-release -f ci/release/Containerfile ci/release
- name: Build and package
env:
RELEASE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
run: |
docker run --rm -e RELEASE_TAG -v "$PWD:/src" xchplot2-release \
bash scripts/build-release.sh
- name: Check extracted archive on the oldest supported runtime
run: |
docker run --rm -v "$PWD:/src:ro" -w /src ubuntu:22.04 bash -euc '
apt-get update
apt-get install -y --no-install-recommends python3 libstdc++6
python3 scripts/test/release.py build/release/dist/*.tar.gz
'
- uses: actions/upload-artifact@v7
with:
name: linux-x86_64-cuda
path: |
build/release/dist/*.tar.gz
build/release/dist/*.sha256
if-no-files-found: error

windows-cuda:
runs-on: windows-2022
timeout-minutes: 60
defaults:
run:
shell: pwsh
steps:
- name: Preserve source line endings
run: git config --global core.autocrlf false
- uses: actions/checkout@v7
- name: Install CUDA 12.9.1 compiler and runtime headers
run: |
$installer = Join-Path $env:RUNNER_TEMP 'cuda.exe'
Invoke-WebRequest 'https://developer.download.nvidia.com/compute/cuda/12.9.1/network_installers/cuda_12.9.1_windows_network.exe' -OutFile $installer
$install = Start-Process $installer -ArgumentList '-s', '-n', 'nvcc_12.9', 'cudart_12.9', 'thrust_12.9' -Wait -PassThru
if ($install.ExitCode -ne 0) { throw "CUDA installer failed: $($install.ExitCode)" }
"CUDA_PATH=$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v12.9" >> $env:GITHUB_ENV
- name: Install release Rust tooling
run: |
$PSNativeCommandUseErrorActionPreference = $true
rustup toolchain install 1.98.1 --profile minimal
rustup default 1.98.1
cargo install --locked --features cli cargo-about --version 0.9.2
- name: Build and package
env:
RELEASE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
run: ./scripts/build-release.ps1
- name: Check extracted archive without toolkit libraries on PATH
run: |
$python = (Get-Command python.exe).Source
$env:PATH = "$env:SystemRoot\System32;$env:SystemRoot"
$archive = (Get-ChildItem build/release-windows/dist/*.zip).FullName
& $python scripts/test/release.py $archive
- uses: actions/upload-artifact@v7
with:
name: windows-x86_64-cuda
path: |
build/release-windows/dist/*.zip
build/release-windows/dist/*.sha256
if-no-files-found: error

draft:
if: startsWith(github.ref, 'refs/tags/')
needs: [linux-cuda, windows-cuda]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
pattern: '*-x86_64-cuda'
merge-multiple: true
path: dist
- name: Attach archives to a draft release
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
gh release create "$RELEASE_TAG" dist/* \
--verify-tag --draft --title "$RELEASE_TAG" --generate-notes
78 changes: 72 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ if(_xchplot2_nvcc)
set(_min_arch 9999)
foreach(_a IN LISTS _arches)
string(REGEX REPLACE "^(sm_|compute_)" "" _a "${_a}")
string(REGEX REPLACE "-(real|virtual)$" "" _a "${_a}")
if(_a MATCHES "^[0-9]+$" AND _a LESS _min_arch)
set(_min_arch ${_a})
endif()
Expand Down Expand Up @@ -160,6 +161,14 @@ unset(_xchplot2_nvcc CACHE)

project(pos2-gpu VERSION 0.11.0 LANGUAGES C CXX CUDA)

if(MSVC)
# Match the release Rust staticlib's CRT in every CMake configuration.
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS)
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:/utf-8>"
"$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/utf-8>")
endif()

# Default to Release: a plain `cmake -B build -S .` otherwise builds
# with EMPTY optimization flags — host C++ (FSE compression, writer,
# host-side merges) at -O0 silently runs several times slower while
Expand Down Expand Up @@ -268,6 +277,11 @@ message(STATUS "pos2-chip: ${POS2_CHIP_DIR}")
# pos2-chip vendors FSE under lib/fse with its own CMakeLists.txt.
# Bring it in so we can link against the same static lib pos2-chip uses.
add_subdirectory("${POS2_CHIP_DIR}/lib/fse" "${CMAKE_BINARY_DIR}/fse" EXCLUDE_FROM_ALL)
if(MSVC)
# Upstream's MSVC list has argumentless /wd, /we, and /D options.
# CMake already supplies the optimization and debug flags per configuration.
set_property(TARGET fse PROPERTY COMPILE_OPTIONS /W4)
endif()

# Header-only pos2-chip include surface
# Keep the upstream checkout intact. Its solver treats a statistical candidate
Expand All @@ -278,6 +292,33 @@ foreach(_header Solver.hpp ParallelRadixSort.hpp ProofSolverTimings.hpp)
"${_pos2_solver_dir}/solve/${_header}" COPYONLY)
endforeach()
find_package(Git REQUIRED)
# CCCL 2.x uses long2 for 64-bit PTX operands; Windows long is only 32 bits.
# Backport NVIDIA's fix to a build-local header, as with the solver below.
if(WIN32)
set(_cccl_header_name "cuda/__ptx/instructions/generated/clusterlaunchcontrol.h")
find_file(_cccl_header "${_cccl_header_name}"
PATHS ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} NO_DEFAULT_PATH NO_CACHE)
if(_cccl_header)
file(READ "${_cccl_header}" _cccl_text)
if(_cccl_text MATCHES "reinterpret_cast<long2")
message(STATUS "Applying CCCL Windows PTX operand fix")
set(_cccl_dir "${CMAKE_CURRENT_BINARY_DIR}/cccl-windows")
configure_file("${_cccl_header}" "${_cccl_dir}/${_cccl_header_name}" COPYONLY)
execute_process(
COMMAND "${GIT_EXECUTABLE}" apply --ignore-space-change
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/cccl-windows-ptx.patch"
WORKING_DIRECTORY "${_cccl_dir}"
RESULT_VARIABLE _cccl_patch_result ERROR_VARIABLE _cccl_patch_error)
if(NOT _cccl_patch_result EQUAL 0)
message(FATAL_ERROR "CCCL Windows PTX patch failed: ${_cccl_patch_error}")
endif()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/cccl-windows-ptx.patch")
include_directories(BEFORE "${_cccl_dir}")
set(_cccl_patch_applied TRUE)
endif()
endif()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" apply --ignore-space-change "${CMAKE_CURRENT_SOURCE_DIR}/contrib/pos2-solver-candidates.patch"
WORKING_DIRECTORY "${_pos2_solver_dir}"
Expand All @@ -295,7 +336,7 @@ target_include_directories(pos2_chip_headers INTERFACE
)
target_link_libraries(pos2_chip_headers INTERFACE fse)
# Match pos2-chip's CPU AES build flags so its AesHash compiles in CPU TUs.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
if(NOT MSVC AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
target_compile_options(pos2_chip_headers INTERFACE -maes -msse4.1 -mssse3 -msse2)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
target_compile_options(pos2_chip_headers INTERFACE -march=armv8-a+crypto)
Expand Down Expand Up @@ -392,7 +433,11 @@ target_link_libraries(pos2_gpu_host PUBLIC pos2_chip_headers pos2_gpu)
# ----------------------------------------------------------------------------
set(POS2_KEYGEN_CRATE_DIR "${CMAKE_SOURCE_DIR}/keygen-rs")
set(POS2_KEYGEN_TARGET_DIR "${CMAKE_BINARY_DIR}/keygen-rs-target")
set(POS2_KEYGEN_STATIC_LIB "${POS2_KEYGEN_TARGET_DIR}/release/libpos2_keygen.a")
set(POS2_KEYGEN_STATIC_LIB "${POS2_KEYGEN_TARGET_DIR}/release/${CMAKE_STATIC_LIBRARY_PREFIX}pos2_keygen${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(_pos2_keygen_env "CARGO_TARGET_DIR=${POS2_KEYGEN_TARGET_DIR}")
if(MSVC)
list(APPEND _pos2_keygen_env "RUSTFLAGS=$ENV{RUSTFLAGS} -C target-feature=+crt-static")
endif()

# Collect the sources so CMake knows when to rebuild.
file(GLOB_RECURSE POS2_KEYGEN_SRCS
Expand All @@ -404,7 +449,7 @@ file(GLOB_RECURSE POS2_KEYGEN_SRCS
add_custom_command(
OUTPUT "${POS2_KEYGEN_STATIC_LIB}"
COMMAND ${CMAKE_COMMAND} -E env
CARGO_TARGET_DIR=${POS2_KEYGEN_TARGET_DIR}
${_pos2_keygen_env}
cargo build --release --locked --manifest-path=${POS2_KEYGEN_CRATE_DIR}/Cargo.toml
DEPENDS ${POS2_KEYGEN_SRCS}
WORKING_DIRECTORY "${POS2_KEYGEN_CRATE_DIR}"
Expand All @@ -423,6 +468,8 @@ add_dependencies(pos2_keygen pos2_keygen_build)
# Rust staticlibs link in std, which needs these system libs at final link.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(pos2_keygen INTERFACE pthread dl m)
elseif(WIN32)
target_link_libraries(pos2_keygen INTERFACE ws2_32 userenv bcrypt ntdll advapi32)
endif()

# xchplot2_cli: the CLI dispatch logic as a static library, with the
Expand Down Expand Up @@ -469,8 +516,12 @@ add_executable(xchplot2 tools/xchplot2/main.cpp)
# the resolutions before it sees the unresolved references and bails.
# Cargo install already passes --start-group via build.rs; the cmake
# exe needs the same treatment.
target_link_libraries(xchplot2 PRIVATE
"$<LINK_GROUP:RESCAN,xchplot2_cli,pos2_gpu_host>")
if(MSVC)
target_link_libraries(xchplot2 PRIVATE xchplot2_cli pos2_gpu_host)
else()
target_link_libraries(xchplot2 PRIVATE
"$<LINK_GROUP:RESCAN,xchplot2_cli,pos2_gpu_host>")
endif()
# pos2-chip's soft_aesenc / soft_aesdec are defined (not just declared)
# in headers without `inline`, so any TU that includes the chain — both
# PlotFileWriterParallel.cpp and CpuPlotter.cpp do, transitively via
Expand All @@ -480,7 +531,11 @@ target_link_libraries(xchplot2 PRIVATE
# build.rs for an unrelated keygen-rs / libstd duplication; the cmake
# exe needs it too once CpuPlotter joined PlotFileWriterParallel as a
# pos2-chip-including TU.
target_link_options(xchplot2 PRIVATE LINKER:--allow-multiple-definition)
if(MSVC)
target_link_options(xchplot2 PRIVATE LINKER:/FORCE:MULTIPLE)
else()
target_link_options(xchplot2 PRIVATE LINKER:--allow-multiple-definition)
endif()

# Parity tests. Each test gets $<TARGET_OBJECTS:pos2_gpu_cuda_obj>
# explicitly: pos2_gpu (INTERFACE) doesn't carry the .o files, so
Expand Down Expand Up @@ -625,6 +680,11 @@ set_target_properties(gpu_ci_info PROPERTIES
include(CTest)
get_property(_xchplot2_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
foreach(_target IN LISTS _xchplot2_targets)
get_target_property(_type ${_target} TYPE)
if(WIN32 AND _type STREQUAL "EXECUTABLE")
target_sources(${_target} PRIVATE tools/xchplot2/windows.manifest)
target_link_libraries(${_target} PRIVATE advapi32 bcrypt)
endif()
if(_target MATCHES "(_parity|_test)$")
set_target_properties(${_target} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tools/parity")
Expand All @@ -633,3 +693,9 @@ foreach(_target IN LISTS _xchplot2_targets)
endif()
endif()
endforeach()

# Archive packaging is opt-in; ordinary builds need no release tooling.
option(XCHPLOT2_PACKAGE "Configure binary release packaging" OFF)
if(XCHPLOT2_PACKAGE)
include(cmake/Packaging.cmake)
endif()
55 changes: 55 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,61 @@ When moving sections, update incoming links and keep the useful README
entry headings. `docs/` is ignored local material; do not publish it as part
of a documentation move.

## Binary releases

The release workflow builds the standalone CMake executable in
`ci/release/Containerfile`: Ubuntu 22.04, CUDA 12.9.1, CMake 3.28.3, and
Rust 1.98.1. CUDA targets are explicit in `scripts/build-release.sh`; keep
the compatibility requirements in `INSTALL.md` and the archive README in
sync when changing them. `cargo-about` collects the Rust dependency licenses
and fails on unresolved licenses.

Build the same archive locally with Docker or Podman:

```bash
podman build -t xchplot2-release -f ci/release/Containerfile ci/release
podman run --rm -v "$PWD:/src" xchplot2-release bash scripts/build-release.sh
```

The Linux archive and its SHA-256 checksum are written to `build/release/dist/`.
For native Windows, install the [Windows build tools](INSTALL.md#windows)
and PowerShell 7.3+, then run:

```powershell
rustup toolchain install 1.98.1 --profile minimal
rustup default 1.98.1
cargo install --locked --features cli cargo-about --version 0.9.2
./scripts/build-release.ps1
python scripts/test/release.py build/release-windows/dist/xchplot2-0.11.0-windows-x86_64-cuda.zip
```

The PowerShell script loads the Visual Studio 2022 x64 environment when
needed, builds all targets with CUDA 12.9.1, runs the host CTest subset, and
writes a ZIP and checksum to `build/release-windows/dist/`. The extracted
Windows check also exercises Unicode paths, real key generation, Ctrl-Break,
resume, and publication failure. CI runs it with toolkit libraries removed
from `PATH`. Windows GPU plotting and spill behavior need qualification on
Windows hardware before the archive is advertised for those devices.
For affected CUDA 12.x headers, CMake applies NVIDIA's
[64-bit PTX operand fix](https://github.com/NVIDIA/cccl/commit/270f4100dceeb6345f74fd374695e78bb0a48082)
to a build-local copy; `BUILDINFO.txt` records the backport. The installed
toolkit stays intact.

PR and manual runs retain both platforms' archives as workflow artifacts. Pushing a
`vVERSION-cuda-only` tag creates a draft GitHub release; publish it after
qualifying the extracted archive on the supported GPUs. Do not rebuild
between qualification and publication.

The workflow runs host tests and tests the extracted archive on Ubuntu 22.04
without a GPU toolkit. Run `scripts/test/release.py ARCHIVE.tar.gz` to repeat
the archive, CPU plotting, and full-proof check. For GPU qualification, use
the packaged executable for k=22 and k=28 CPU byte comparisons, full proofs,
and the tier, spill, and recovery checks described above. Record qualification
in the release notes; keep generated plots and detailed logs out of the tree.
`gpu-ci.py --binary /path/to/extracted/bin/xchplot2` uses the package for
plotting and verification while retaining the build's parity and inventory
tools. Both must come from the same source revision and toolchain.

## Commit style

Short imperative subjects, lowercase scope prefix, no trailing period:
Expand Down
Loading
Loading