From c54f8e5c062f4a3a456a145ddd0599272d5bc54d Mon Sep 17 00:00:00 2001 From: Bo Tang Date: Mon, 26 Oct 2026 23:08:17 -0400 Subject: [PATCH 1/2] Fix: support Windows builds with MSVC --- .github/workflows/build.yml | 4 ++- CMakeLists.txt | 35 ++++++++++++++++++-------- README.md | 2 +- test/unit/cpu/test_error_handling.c | 4 +++ test/unit/gpu/test_active_set_masks.cu | 8 +++--- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2167c2f..aa916cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,8 @@ jobs: name: Linux / CUDA ${{ matrix.cuda }} runs-on: ubuntu-latest container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04 + env: + CMAKE_BUILD_PARALLEL_LEVEL: "2" strategy: fail-fast: false matrix: @@ -61,7 +63,7 @@ jobs: -DHPDLP_BUILD_TESTS=ON - name: Build - run: cmake --build build --parallel 2 + run: cmake --build build - name: Run CPU tests run: ctest --test-dir build -L cpu --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 523809a..b54362c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project(hpdlp VERSION 0.0.1 LANGUAGES C CXX CUDA) add_compile_definitions(HPDLP_VERSION="${PROJECT_VERSION}") # Language standards -set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -31,15 +31,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) "MinSizeRel" "RelWithDebInfo") endif() -# Global compile flags -add_compile_definitions(CUSPARSE_ENABLE_EXPERIMENTAL_API) -add_compile_options(-Wall -Wextra) - -# Windows compatibility -if(WIN32) - add_compile_definitions(strtok_r=strtok_s) -endif() - # ----------------------------------------------------------------------------- # CONTROL OPTIONS # ----------------------------------------------------------------------------- @@ -51,8 +42,9 @@ option(HPDLP_BUILD_SHARED_LIB "Build the H-PDLP shared library" ON) cmake_dependent_option(HPDLP_BUILD_PYTHON "Build the H-PDLP Python bindings" OFF "HPDLP_BUILD_STATIC_LIB" OFF) +# The CLI uses getopt.h, libgen.h and unistd.h, which MSVC does not provide. cmake_dependent_option(HPDLP_BUILD_CLI "Build the H-PDLP command-line executable" ON - "HPDLP_BUILD_STATIC_LIB" OFF) + "HPDLP_BUILD_STATIC_LIB;NOT MSVC" OFF) cmake_dependent_option(HPDLP_BUILD_TESTS "Build the H-PDLP test suite" OFF "HPDLP_BUILD_STATIC_LIB" OFF) @@ -112,6 +104,25 @@ FetchContent_Declare( FetchContent_MakeAvailable(pslp) +# Apply project flags after dependencies so they do not inherit our options. +add_compile_definitions(CUSPARSE_ENABLE_EXPERIMENTAL_API) +if(MSVC) + add_compile_options( + $<$:/W4> + $<$:-Xcompiler=/W4>) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS strtok_r=strtok_s) + if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA" + AND CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 13) + # CUDA 13 CCCL headers require the conforming MSVC preprocessor. + # Keep CUDA 12 in its default mode. + add_compile_options($<$:-Xcompiler=/Zc:preprocessor>) + endif() +else() + add_compile_options( + "$<$:-Wall;-Wextra>" + $<$:-Xcompiler=-Wall,-Wextra>) +endif() + # ----------------------------------------------------------------------------- # SOURCE DISCOVERY & TARGET DEFINITION # ----------------------------------------------------------------------------- @@ -187,6 +198,7 @@ if(HPDLP_BUILD_SHARED_LIB) set_target_properties( hpdlp_shared PROPERTIES OUTPUT_NAME "hpdlp" + WINDOWS_EXPORT_ALL_SYMBOLS ON RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" CUDA_SEPARABLE_COMPILATION ON CUDA_RESOLVE_DEVICE_SYMBOLS ON) @@ -245,6 +257,7 @@ if(NOT HPDLP_BUILD_PYTHON) install( TARGETS hpdlp_shared LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) # 'bin' for DLLs on Windows, 'lib' for .so on Linux endif() diff --git a/README.md b/README.md index 1a77bc0..dcbd4e7 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Maximization is supported through MPS `OBJSENSE` and the C/Python APIs. For MPS ## Installation -Linux and WSL2 are the primary build environments. Native Windows builds have not been validated. +Linux and WSL2 support all build targets. Native Windows builds with MSVC support the libraries and Python bindings; the CLI requires Linux or WSL2. - **GPU:** an NVIDIA GPU supported by the selected CUDA toolkit. - **CUDA Toolkit:** 12.4+ with NVCC, cuBLAS, cuSPARSE, and cuRAND. diff --git a/test/unit/cpu/test_error_handling.c b/test/unit/cpu/test_error_handling.c index b673cd1..da0a7f6 100644 --- a/test/unit/cpu/test_error_handling.c +++ b/test/unit/cpu/test_error_handling.c @@ -27,7 +27,11 @@ static lp_problem_t *create_small_problem(void) int main(void) { +#ifdef _WIN32 + _putenv_s("CUDA_VISIBLE_DEVICES", "-1"); +#else setenv("CUDA_VISIBLE_DEVICES", "", 1); +#endif lp_problem_t *problem = create_small_problem(); check("problem is created without a GPU", problem != NULL); diff --git a/test/unit/gpu/test_active_set_masks.cu b/test/unit/gpu/test_active_set_masks.cu index 8ed6586..d29089d 100644 --- a/test/unit/gpu/test_active_set_masks.cu +++ b/test/unit/gpu/test_active_set_masks.cu @@ -6,11 +6,11 @@ #include __global__ void update_binding_constraint_mask_kernel( - const double *, const double *, const double *, const double *, - int *, bool *, active_set_mask_changes_t *, double, int, int, int); + const double *__restrict__, const double *, const double *__restrict__, const double *__restrict__, + int *__restrict__, bool *__restrict__, active_set_mask_changes_t *, double, int, int, int); __global__ void update_free_variable_mask_kernel( - const double *, const double *, const double *, const double *, - const double *, int *, bool *, active_set_mask_changes_t *, double, + const double *__restrict__, const double *__restrict__, const double *, const double *__restrict__, + const double *__restrict__, int *__restrict__, bool *__restrict__, active_set_mask_changes_t *, double, int, int, int); enum { NUM_ROWS = 10, NUM_COLUMNS = 12, NUM_ZERO_SCALE_COLUMNS = 4, NUM_GAUGES = 2 }; From 3d05ffcd2a88834342de84346f13c8792f380c05 Mon Sep 17 00:00:00 2001 From: Bo Tang Date: Mon, 26 Oct 2026 23:19:46 -0400 Subject: [PATCH 2/2] CI: align Linux and Windows CUDA build coverage --- .github/workflows/build.yml | 61 +++++++++++++++++++++++++------------ README.md | 2 +- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa916cd..7f219d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,42 +16,50 @@ concurrency: jobs: build: - name: Linux / CUDA ${{ matrix.cuda }} - runs-on: ubuntu-latest - container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04 + name: ${{ matrix.os }} / CUDA ${{ matrix.cuda }} + runs-on: ${{ matrix.os }} env: CMAKE_BUILD_PARALLEL_LEVEL: "2" strategy: fail-fast: false matrix: - cuda: ["12.4.0", "13.3.0"] + os: [ubuntu-22.04, windows-2022] + cuda: ["12.4.0", "12.5.0", "12.6.0", "12.8.0", "12.9.0", "13.0.0", "13.1.0"] defaults: run: shell: bash steps: + - uses: actions/checkout@v5 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - uses: ilammy/msvc-dev-cmd@v1 + if: runner.os == 'Windows' + with: + arch: x64 + + - uses: Jimver/cuda-toolkit@v0.2.30 + with: + cuda: ${{ matrix.cuda }} + linux-local-args: '["--toolkit"]' + use-github-cache: 'false' + log-file-suffix: '${{ matrix.os }}-${{ matrix.cuda }}' + - name: Install system dependencies + if: runner.os == 'Linux' run: | - # CUDA is preinstalled in the image; these dependencies only need Ubuntu sources. - # Ignore extra repositories so NVIDIA index sync failures do not block this step. - test -s /etc/apt/sources.list - apt_options=( - -o Dir::Etc::sourcelist=/etc/apt/sources.list - -o Dir::Etc::sourceparts=- - ) - apt-get "${apt_options[@]}" update - apt-get "${apt_options[@]}" install -y --no-install-recommends \ - build-essential git ca-certificates python3-dev python3-venv zlib1g-dev - - - uses: actions/checkout@v5 + sudo apt-get update + sudo apt-get install -y --no-install-recommends zlib1g-dev - name: Install build tools run: | - python3 -m venv "$RUNNER_TEMP/build-env" - "$RUNNER_TEMP/build-env/bin/python" -m pip install --upgrade pip "cmake>=3.24" ninja - echo "$RUNNER_TEMP/build-env/bin" >> "$GITHUB_PATH" + python -m pip install --upgrade pip "cmake>=3.24" ninja - name: Configure + # Check every toolkit's build; run the test suites once per OS. run: | cmake -S . -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ @@ -60,18 +68,31 @@ jobs: -DHPDLP_BUILD_SHARED_LIB=ON \ -DHPDLP_BUILD_CLI=ON \ -DHPDLP_BUILD_PYTHON=OFF \ - -DHPDLP_BUILD_TESTS=ON + -DHPDLP_BUILD_TESTS=${{ matrix.cuda == '13.1.0' && 'ON' || 'OFF' }} - name: Build run: cmake --build build + - name: Add PSLP to the Windows DLL search path + if: runner.os == 'Windows' && matrix.cuda == '13.1.0' + shell: pwsh + run: | + "$env:GITHUB_WORKSPACE\build\_deps\pslp-build" >> $env:GITHUB_PATH + - name: Run CPU tests + if: matrix.cuda == '13.1.0' + env: + LD_LIBRARY_PATH: ${{ env.CUDA_PATH }}/lib64 run: ctest --test-dir build -L cpu --output-on-failure - name: Install Python package + if: matrix.cuda == '13.1.0' run: | python -m pip install ".[test]" \ --config-settings=cmake.define.CMAKE_CUDA_ARCHITECTURES=80 - name: Run Python tests + if: matrix.cuda == '13.1.0' + env: + LD_LIBRARY_PATH: ${{ env.CUDA_PATH }}/lib64 run: python -m pytest -m "not gpu" diff --git a/README.md b/README.md index dcbd4e7..c0b42f1 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ cmake --build build -j ctest --test-dir build --output-on-failure ``` -See the [test guide](test/README.md) for CPU/GPU subsets and [Python tests](python/README.md#tests) for pytest instructions. CI builds everything and runs the CPU-only C tests and the non-GPU Python tests. +See the [test guide](test/README.md) for CPU/GPU subsets and [Python tests](python/README.md#tests) for pytest instructions. CI builds on Linux and Windows across the supported CUDA versions. On CUDA 13.1, both platforms also run the CPU-only C tests and the non-GPU Python tests. ## Acknowledgements