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
175 changes: 141 additions & 34 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# -----------------------------------------------------------------------------
# ROOT CMakeLists.txt for cuPDLPx (Unified Build System)
# -----------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.20)

# Project config
Expand All @@ -8,43 +11,56 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Set default build type to Release if not specified (Optimized builds)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# Increase compatibility by compiling for all supported real and virtual architectures.
set(CMAKE_CUDA_ARCHITECTURES all)

# On Windows, map strtok_r to strtok_s for compatibility
# Global Compile flags (corresponding to CFLAGS/NVCCFLAGS)
add_compile_options(-fPIC -O3 -Wall -Wextra -g)

# Windows compatibility
if (WIN32)
add_definitions(-Dstrtok_r=strtok_s)
endif()

# Optional: be explicit about CUDA standard and separable compilation
# CUDA standards and RDC (Relocatable Device Code) for shared/static linking
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)

set(CMAKE_CUDA_ARCHITECTURES "all")

# -----------------------------------------------------------------------------
# FIND DEPENDENCIES
# -----------------------------------------------------------------------------
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
find_package(CUDAToolkit REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED) # For versioning script

# -----------------------------------------------------------------------------
# Version header generation
# VERSION HEADER GENERATION (Build/generated/version.h)
# -----------------------------------------------------------------------------
# Get python for versioning script
find_package(Python3 COMPONENTS Interpreter REQUIRED)

# Extract version from pyproject.toml
execute_process(
COMMAND ${Python3_EXECUTABLE} -c
[=[
import sys
# Use stdlib tomllib if available, otherwise fall back to tomli (both accept .load on a binary file)
try:
import tomllib as toml # Python 3.11+
import tomllib as toml
except ModuleNotFoundError:
import tomli as toml
import os

if not os.path.exists("pyproject.toml"):
sys.stderr.write("Error: pyproject.toml not found in the root directory.\n")
sys.exit(1)

with open("pyproject.toml", "rb") as f:
data = toml.load(f)

ver = data["project"]["version"]
print(ver)
]=]
Expand All @@ -53,56 +69,147 @@ print(ver)
OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Print the version to CMake output
message(STATUS "cuPDLPx version from pyproject.toml = ${CUPDLPX_VERSION}")

# Generate version.h from version.h.in
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cupdlpx/version.h.in
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/generated/version.h
@ONLY
)

# Make the generated files available for inclusion
include_directories(${CMAKE_CURRENT_BINARY_DIR}/generated)


# -----------------------------------------------------------------------------
# Build the core native library that the Python extension links against
# SOURCE DISCOVERY & TARGET DEFINITION
# -----------------------------------------------------------------------------
add_library(cupdlpx_core STATIC
cupdlpx/interface.c
cupdlpx/preconditioner.c
cupdlpx/solver.cu
cupdlpx/utils.cu
# Discover sources (Assuming src/ directory based on Makefile)
file(GLOB C_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
)
file(GLOB CU_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu"
)
# Exclude cli.c from library builds
list(REMOVE_ITEM C_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/cli.c")

# Set common include directories for the core libraries
set(CORE_INCLUDE_DIRS
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include # Public API headers
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/internal # Internal implementation headers
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated # Generated headers (version.h)
)

# Public headers for dependents (e.g., the pybind11 module)
target_include_directories(cupdlpx_core
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cupdlpx
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated
# Set common link libraries
set(CORE_LINK_LIBS PUBLIC
CUDA::cudart
CUDA::cublas
CUDA::cusparse
ZLIB::ZLIB
)

# Ensure position-independent code so it can be linked into a Python extension
set_target_properties(cupdlpx_core PROPERTIES
POSITION_INDEPENDENT_CODE ON
# -----------------------------------------------------------------------------
# 1. Core STATIC Library (cupdlpx_core)
# -----------------------------------------------------------------------------
add_library(cupdlpx_core STATIC
${C_SOURCES}
${CU_SOURCES}
)
target_include_directories(cupdlpx_core ${CORE_INCLUDE_DIRS})
target_link_libraries(cupdlpx_core ${CORE_LINK_LIBS})

# If you compile CUDA sources in this target, enable separable compilation
set_target_properties(cupdlpx_core PROPERTIES
POSITION_INDEPENDENT_CODE ON
CUDA_SEPARABLE_COMPILATION ON
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)

# Link against CUDA runtime and libraries you use
target_link_libraries(cupdlpx_core PUBLIC
CUDA::cudart
CUDA::cublas
CUDA::cusparse
ZLIB::ZLIB
# -----------------------------------------------------------------------------
# 2. Shared Library (libcupdlpx.so)
# -----------------------------------------------------------------------------
add_library(cupdlpx_shared SHARED
${C_SOURCES}
${CU_SOURCES}
)
target_include_directories(cupdlpx_shared ${CORE_INCLUDE_DIRS})
target_link_libraries(cupdlpx_shared ${CORE_LINK_LIBS})

set_target_properties(cupdlpx_shared PROPERTIES
OUTPUT_NAME "cupdlpx"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # Output to ./build/
CUDA_SEPARABLE_COMPILATION ON
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)

# -----------------------------------------------------------------------------
# 3. CLI Executable (cupdlpx)
# -----------------------------------------------------------------------------
add_executable(cupdlpx_cli src/cli.c)

target_include_directories(cupdlpx_cli PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include # For public headers
${CMAKE_CURRENT_SOURCE_DIR}/internal # For internal headers
${CMAKE_CURRENT_BINARY_DIR}/generated # For version.h
)

# Link CLI to the static core library
target_link_libraries(cupdlpx_cli PRIVATE cupdlpx_core)

set_target_properties(cupdlpx_cli PROPERTIES
OUTPUT_NAME "cupdlpx"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # Output to ./build/
)

# -----------------------------------------------------------------------------
# 4. Tests (CTest Integration)
# -----------------------------------------------------------------------------
enable_testing()
file(GLOB TEST_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.cu"
)

foreach(TEST_SRC ${TEST_SOURCES})
get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE)

add_executable(${TEST_NAME} ${TEST_SRC})

# Link tests to the core static library
target_link_libraries(${TEST_NAME} PRIVATE cupdlpx_core)

# Set up test includes
target_include_directories(${TEST_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/internal
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated
)

# Register with CTest
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})

# Output to ./build/tests/
set_target_properties(${TEST_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tests"
)
endforeach()

# -----------------------------------------------------------------------------
# Add the pybind11 module (lives in subdir)
# 5. Python Bindings
# -----------------------------------------------------------------------------
add_subdirectory(python_bindings)

# -----------------------------------------------------------------------------
# 6. Install Targets
# -----------------------------------------------------------------------------
install(TARGETS cupdlpx_core cupdlpx_shared
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)

# Install headers (only public headers)
install(DIRECTORY include/
DESTINATION include/
FILES_MATCHING PATTERN "*.h"
)
Loading