Skip to content
Closed
263 changes: 97 additions & 166 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ 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)

# Set default build type to Release if not specified
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")
Expand All @@ -34,23 +35,30 @@ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
set(CMAKE_CUDA_ARCHITECTURES 60 70 75 80 86 89 90)
endif()

# Global Compile flags (corresponding to CFLAGS/NVCCFLAGS)
# -----------------------------------------------------------------------------
# [ELEGANT DESIGN] Target-based Compile Flags
# -----------------------------------------------------------------------------
add_library(cupdlpx_compile_flags INTERFACE)

if(MSVC)
add_compile_options(/O2 /W4 /Zi)
target_compile_options(cupdlpx_compile_flags INTERFACE
$<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:/O2 /W4 /Zi>
$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler "/O2 /W4 /Zi">
)
target_compile_definitions(cupdlpx_compile_flags INTERFACE
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE
strtok_r=strtok_s
strdup=_strdup
)
else()
add_compile_options(-O3 -Wall -Wextra -g)
endif()

if (NOT WIN32)
add_compile_options(-fPIC)
endif()

# Windows compatibility
if (WIN32)
add_definitions(-Dstrtok_r=strtok_s)
target_compile_options(cupdlpx_compile_flags INTERFACE -O3 -Wall -Wextra -g)
if(NOT WIN32)
target_compile_options(cupdlpx_compile_flags INTERFACE -fPIC)
endif()
endif()

# CUDA standards and RDC (Relocatable Device Code)
# CUDA standards and RDC
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)

Expand All @@ -62,130 +70,114 @@ include(CMakeDependentOption)
option(CUPDLPX_BUILD_STATIC_LIB "Build the cuPDLPx static library" ON)
option(CUPDLPX_BUILD_SHARED_LIB "Build the cuPDLPx shared library" ON)

# format: cmake_dependent_option(OPTION "docstring" DEFAULT_VALUE "DEPENDENCY_VARIABLE" FORCE_OFF_VALUE)
cmake_dependent_option(CUPDLPX_BUILD_PYTHON "Build the cuPDLPx Python bindings" OFF
"CUPDLPX_BUILD_STATIC_LIB" OFF)

cmake_dependent_option(CUPDLPX_BUILD_CLI "Build the cuPDLPx command-line executable" ON
"CUPDLPX_BUILD_STATIC_LIB" OFF)

cmake_dependent_option(CUPDLPX_BUILD_TESTS "Build the cuPDLPx test suite" OFF
"CUPDLPX_BUILD_STATIC_LIB" OFF)
cmake_dependent_option(CUPDLPX_BUILD_PYTHON "Build the cuPDLPx Python bindings" OFF "CUPDLPX_BUILD_STATIC_LIB" OFF)
cmake_dependent_option(CUPDLPX_BUILD_CLI "Build the cuPDLPx command-line executable" ON "CUPDLPX_BUILD_STATIC_LIB" OFF)
cmake_dependent_option(CUPDLPX_BUILD_TESTS "Build the cuPDLPx test suite" OFF "CUPDLPX_BUILD_STATIC_LIB" OFF)

# -----------------------------------------------------------------------------
# FIND DEPENDENCIES
# -----------------------------------------------------------------------------
# Core dependencies (required for Julia/Yggdrasil and Python)
find_package(CUDAToolkit REQUIRED)

include(FetchContent)
# 1. Try to find ZLIB in the system first (Standard for Linux/Mac)
find_package(ZLIB QUIET)

if(ZLIB_FOUND)
message(STATUS "Found System ZLIB: ${ZLIB_LIBRARIES}")
else()
# 2. If not found (Common on Windows), fetch from source
message(STATUS "ZLIB not found in system. Fetching from source...")
# 1. ZLIB Configuration

set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
find_package(ZLIB QUIET)
if(NOT ZLIB_FOUND)
FetchContent_Declare(
zlib
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG v1.3
)
FetchContent_MakeAvailable(zlib)

# 3. Create alias ZLIB::ZLIB to match your CORE_LINK_LIBS usage
if(NOT TARGET ZLIB::ZLIB)
if(TARGET zlibstatic)
# Prefer zlibstatic to ensure static linking (avoids DLL issues on Windows)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
# Expose include directories so zlib.h can be found
target_include_directories(zlibstatic INTERFACE ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR})
else()
# Fallback if the target is simply named 'zlib'
add_library(ZLIB::ZLIB ALIAS zlib)
target_include_directories(zlib INTERFACE ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR})
endif()

FetchContent_GetProperties(zlib)
if(NOT zlib_POPULATED)
FetchContent_Populate(zlib)

file(WRITE "${zlib_SOURCE_DIR}/zlib.pc.cmakein" "")
add_subdirectory(${zlib_SOURCE_DIR} ${zlib_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
endif()

if (CUPDLPX_BUILD_PYTHON)
# Dependencies required only for Python bindings
find_package(pybind11 CONFIG REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED) # For versioning script and pybind11
if(TARGET zlibstatic)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
target_include_directories(zlibstatic INTERFACE
$<BUILD_INTERFACE:${zlib_SOURCE_DIR}>
$<BUILD_INTERFACE:${zlib_BINARY_DIR}>
)
endif()
endif()

set(PSLP_VERSION_TAG "v0.0.4")

# 2. PSLP Configuration
set(PSLP_VERSION_TAG "v0.0.6")
FetchContent_Declare(
pslp
GIT_REPOSITORY https://github.com/dance858/PSLP.git
GIT_TAG ${PSLP_VERSION_TAG}
)

FetchContent_MakeAvailable(pslp)
include_directories(${pslp_SOURCE_DIR}/PSLP)
add_compile_definitions(PSLP_VERSION=\"${PSLP_VERSION_TAG}\")

# --- PSLP FIX BLOCK (Cross-Platform & Header fix) ---
if(TARGET PSLP)
# Fix Linux absolute path error
set_target_properties(PSLP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "")

# Expose PSLP's internal headers that cuPDLPx needs
target_include_directories(PSLP INTERFACE
$<BUILD_INTERFACE:${pslp_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${pslp_SOURCE_DIR}/include/PSLP>
)

# Defensive flag filtering for MSVC
if(MSVC)
get_target_property(PSLP_OPTS PSLP COMPILE_OPTIONS)
if(PSLP_OPTS)
list(REMOVE_ITEM PSLP_OPTS "-Wall" "-Wextra" "-Wpedantic" "-Werror")
set_target_properties(PSLP PROPERTIES COMPILE_OPTIONS "${PSLP_OPTS}")
endif()
endif()
endif()

target_compile_definitions(cupdlpx_compile_flags INTERFACE PSLP_VERSION="${PSLP_VERSION_TAG}")

# -----------------------------------------------------------------------------
# SOURCE DISCOVERY & TARGET DEFINITION
# TARGET DEFINITIONS
# -----------------------------------------------------------------------------
# Using file(GLOB) for convenience, but explicit lists are recommended for robust builds
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
file(GLOB C_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c")
file(GLOB CU_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu")
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
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/internal
)

# Set common link libraries
set(CORE_LINK_LIBS PUBLIC
CUDA::cudart
CUDA::cublas
CUDA::cusparse
ZLIB::ZLIB
PSLP
set(CORE_LINK_LIBS
PUBLIC cupdlpx_compile_flags
PUBLIC CUDA::cudart
PUBLIC CUDA::cublas
PUBLIC CUDA::cusparse
PUBLIC ZLIB::ZLIB
PUBLIC PSLP
)

# -----------------------------------------------------------------------------
# 1. Core STATIC Library (cupdlpx_core)
# -----------------------------------------------------------------------------
# 1. Core STATIC Library
if(CUPDLPX_BUILD_STATIC_LIB)
add_library(cupdlpx_core STATIC
${C_SOURCES}
${CU_SOURCES}
)
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})

set_target_properties(cupdlpx_core PROPERTIES
POSITION_INDEPENDENT_CODE ON
CUDA_SEPARABLE_COMPILATION ON
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)
endif()

# -----------------------------------------------------------------------------
# 2. Shared Library (libcupdlpx.so)
# -----------------------------------------------------------------------------
# 2. Shared Library
if(CUPDLPX_BUILD_SHARED_LIB)
add_library(cupdlpx_shared SHARED
${C_SOURCES}
${CU_SOURCES}
)
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})

# Shared library must resolve device symbols as it is a final link point
set_target_properties(cupdlpx_shared PROPERTIES
OUTPUT_NAME "cupdlpx"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
Expand All @@ -194,115 +186,54 @@ if(CUPDLPX_BUILD_SHARED_LIB)
)
endif()

# -----------------------------------------------------------------------------
# 3. CLI Executable (cupdlpx)
# -----------------------------------------------------------------------------
# 3. CLI Executable
if(CUPDLPX_BUILD_CLI)
if(NOT TARGET cupdlpx_core)
message(FATAL_ERROR "CUPDLPX_BUILD_CLI=ON requires CUPDLPX_BUILD_STATIC_LIB=ON.")
endif()

add_executable(cupdlpx_cli src/cli.c)

target_include_directories(cupdlpx_cli PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/internal
)

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

# CLI is a final executable, it must resolve device symbols
set_target_properties(cupdlpx_cli PROPERTIES
OUTPUT_NAME "cupdlpx"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)
endif()

# -----------------------------------------------------------------------------
# 4. Tests (CTest Integration)
# -----------------------------------------------------------------------------
# 4. Tests
if(CUPDLPX_BUILD_TESTS)
if(NOT TARGET cupdlpx_core)
message(FATAL_ERROR "CUPDLPX_BUILD_TESTS=ON requires CUPDLPX_BUILD_STATIC_LIB=ON.")
endif()

enable_testing()
file(GLOB TEST_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.cu"
)

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
)

# Tests are final executables, they must resolve device symbols
target_include_directories(${TEST_NAME} PRIVATE include internal)
set_target_properties(${TEST_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tests"
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)

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

endforeach()
endif()

# -----------------------------------------------------------------------------
# 5. Python Bindings (Conditional)
# -----------------------------------------------------------------------------
# 5. Python Bindings
if (CUPDLPX_BUILD_PYTHON)
if(NOT TARGET cupdlpx_core)
message(FATAL_ERROR "CUPDLPX_BUILD_PYTHON=ON requires CUPDLPX_BUILD_STATIC_LIB=ON.")
endif()

find_package(pybind11 CONFIG REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED)
add_subdirectory(python_bindings)
endif()

# -----------------------------------------------------------------------------
# 6. Install Targets
# -----------------------------------------------------------------------------

if (CUPDLPX_BUILD_PYTHON)
install(DIRECTORY include/
DESTINATION include/
FILES_MATCHING PATTERN "*.h"
)

install(DIRECTORY include/ DESTINATION include/ FILES_MATCHING PATTERN "*.h")
else()
if(TARGET cupdlpx_core)
install(TARGETS cupdlpx_core
ARCHIVE DESTINATION lib
)
install(TARGETS cupdlpx_core ARCHIVE DESTINATION lib)
endif()

if(TARGET cupdlpx_shared)
install(TARGETS cupdlpx_shared
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin # 'bin' for DLLs on Windows, 'lib' for .so on Linux
)
install(TARGETS cupdlpx_shared LIBRARY DESTINATION lib RUNTIME DESTINATION bin)
endif()

if(TARGET cupdlpx_cli)
install(TARGETS cupdlpx_cli
RUNTIME DESTINATION bin
)
install(TARGETS cupdlpx_cli RUNTIME DESTINATION bin)
endif()

install(DIRECTORY include/
DESTINATION include/
FILES_MATCHING PATTERN "*.h"
)
install(DIRECTORY include/ DESTINATION include/ FILES_MATCHING PATTERN "*.h")
endif()
1 change: 1 addition & 0 deletions internal/internal_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ limitations under the License.
#include <cublas_v2.h>
#include <cusparse.h>
#include <stdbool.h>
#include <time.h>

typedef struct
{
Expand Down
Loading
Loading