From 9b3d53bdcbbf4c03f468b7c1ffad2d9718cc8ae4 Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Thu, 23 Jul 2026 15:40:25 -0500 Subject: [PATCH 01/12] build(cmake): split libcuopt into cuopt_base / cuopt_routing / cuopt_lp + umbrella MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce three STATIC component libraries that logically partition the cuOpt sources by domain, then fold them into the existing libcuopt.so umbrella via --whole-archive (LINK_LIBRARY:WHOLE_ARCHIVE). Component libraries: - cuopt_base — utilities + linear algebra (logger, work scheduler) - cuopt_routing — VRP / routing engine; links cuopt_base - cuopt_lp — LP / MIP / numerical optimization; links cuopt_base Umbrella: - cuopt SHARED — re-exports all symbols from the three statics via --whole-archive; backward-compatible for GAMS (-lcuopt / libcuopt.so) CMake aliases exposed: cuopt::base, cuopt::routing, cuopt::lp, cuopt::cuopt No source files moved. External build output (libcuopt.so, headers, install layout) is unchanged. SKIP_ROUTING_BUILD=ON continues to work by omitting cuopt_routing from the build and umbrella link. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/CMakeLists.txt | 288 +++++++++++++++-------- cpp/src/CMakeLists.txt | 31 ++- cpp/src/barrier/CMakeLists.txt | 1 + cpp/src/branch_and_bound/CMakeLists.txt | 1 + cpp/src/cuts/CMakeLists.txt | 1 + cpp/src/dual_simplex/CMakeLists.txt | 1 + cpp/src/io/CMakeLists.txt | 3 +- cpp/src/linear_algebra/CMakeLists.txt | 1 + cpp/src/math_optimization/CMakeLists.txt | 1 + cpp/src/mip_heuristics/CMakeLists.txt | 1 + cpp/src/pdlp/CMakeLists.txt | 1 + cpp/src/routing/CMakeLists.txt | 1 + 12 files changed, 227 insertions(+), 104 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 61f6eb91d..699b72765 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -454,6 +454,9 @@ if (BUILD_TESTS) endif () set(CUOPT_SRC_FILES) +set(CUOPT_BASE_SRC_FILES) +set(CUOPT_ROUTING_SRC_FILES) +set(CUOPT_LP_SRC_FILES) set(MPS_FAST_SRC_FILES) add_subdirectory(src) @@ -464,7 +467,9 @@ set_source_files_properties( PROPERTIES COMPILE_OPTIONS "--split-compile=0") if (HOST_LINEINFO) - set_source_files_properties(${CUOPT_SRC_FILES} DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTIES COMPILE_OPTIONS "-g1") + set_source_files_properties( + ${CUOPT_BASE_SRC_FILES} ${CUOPT_ROUTING_SRC_FILES} ${CUOPT_LP_SRC_FILES} + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTIES COMPILE_OPTIONS "-g1") endif () # Needed for the fast MPS parser, available on all x86-64-v3 compliant x86 CPUs (essentially since Haswell ~2013) @@ -477,16 +482,17 @@ endif () # TODO: figure out a set of flags for ARM that fits the range of CPUs we wish to support (neoverse?) # NEON should be universal on aarch64 and enough for our purposes (parsing) though -# Apply -UNDEBUG only to solver source files (not gRPC infrastructure). -# Must happen before gRPC files are appended to CUOPT_SRC_FILES. +# Apply -UNDEBUG to solver source files (not gRPC infrastructure). # Uses APPEND to preserve any existing per-file options (e.g. -g1 from HOST_LINEINFO). if (DEFINE_ASSERT) - set_property(SOURCE ${CUOPT_SRC_FILES} DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + set_property( + SOURCE ${CUOPT_BASE_SRC_FILES} ${CUOPT_ROUTING_SRC_FILES} ${CUOPT_LP_SRC_FILES} + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND PROPERTY COMPILE_OPTIONS "-UNDEBUG") endif () if (NOT SKIP_GRPC_BUILD) - # Add gRPC mapper files and generated protobuf sources + # gRPC integration layer: maps proto <-> C++ LP API; lives in the umbrella, not in cuopt_lp set(GRPC_INFRA_FILES ${DATA_PROTO_SRCS} ${PROTO_SRCS} @@ -501,7 +507,6 @@ if (NOT SKIP_GRPC_BUILD) src/grpc/client/cython_grpc_client.cpp src/grpc/client/solve_remote.cpp ) - list(APPEND CUOPT_SRC_FILES ${GRPC_INFRA_FILES}) # Always keep NDEBUG defined for gRPC infrastructure files so that abseil # headers inline Mutex::Dtor() instead of emitting an external call. @@ -512,67 +517,166 @@ if (NOT SKIP_GRPC_BUILD) APPEND PROPERTY COMPILE_OPTIONS "-DNDEBUG") endif (NOT SKIP_GRPC_BUILD) -add_library(cuopt SHARED - ${CUOPT_SRC_FILES} -) +# ################################################################################################## +# - cuopt component libraries (STATIC, position-independent for use in the umbrella SHARED) ------ -set_target_properties(cuopt - PROPERTIES BUILD_RPATH "\$ORIGIN" - INSTALL_RPATH "\$ORIGIN" - INTERFACE_POSITION_INDEPENDENT_CODE ON - CXX_SCAN_FOR_MODULES OFF -) +# Helper: apply compile options and common include paths to all cuOpt component libs +function(cuopt_configure_component target) + set_target_properties(${target} PROPERTIES + POSITION_INDEPENDENT_CODE ON + CXX_SCAN_FOR_MODULES OFF + ) + target_compile_options(${target} + PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" + "$<$:${CUOPT_CUDA_FLAGS}>" + ) + target_compile_definitions(${target} + PUBLIC "CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}" + ) + target_include_directories(${target} + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_BINARY_DIR}" + PUBLIC + "$" + "$" + INTERFACE + "$" + ) +endfunction() -target_compile_definitions(cuopt - PUBLIC "CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}" - PUBLIC CUSPARSE_ENABLE_EXPERIMENTAL_API +# Compute git hash and generate build_info.hpp before any component is defined +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE ) +message("-- Building with GIT_COMMIT_HASH = '${GIT_COMMIT_HASH}'") -target_compile_options(cuopt - PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" - "$<$:${CUOPT_CUDA_FLAGS}>" +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/utilities/build_info.hpp.in + ${CMAKE_CURRENT_BINARY_DIR}/include/utilities/build_info.hpp + @ONLY ) -if (WRITE_FATBIN) - file(WRITE "${CUOPT_BINARY_DIR}/fatbin.ld" - [=[ - SECTIONS - { - .nvFatBinSegment : { *(.nvFatBinSegment) } - .nv_fatbin : { *(.nv_fatbin) } - } - ]=]) - target_link_options(cuopt PRIVATE "${CUOPT_BINARY_DIR}/fatbin.ld") -endif () +list(JOIN CMAKE_CUDA_ARCHITECTURES "," JOINED_CUDA_ARCHITECTURES) -add_library(cuopt::cuopt ALIAS cuopt) -# ################################################################################################## -# - include paths --------------------------------------------------------------------------------- -message(STATUS "target include directories CUDSS_INCLUDES = ${CUDSS_INCLUDE}") +set(CUOPT_PRIVATE_CUDA_LIBS + CUDA::cublasLt + CUDA::curand + CUDA::cusolver + TBB::tbb + OpenMP::OpenMP_CXX) + +get_filename_component(CUDSS_MT_LIB_FILE_NAME "${CUDSS_MT_LIB_FILE}" NAME) +# cuopt_base: utilities + linear algebra (stateful shared infra — logger, work scheduler) +add_library(cuopt_base STATIC ${CUOPT_BASE_SRC_FILES}) +cuopt_configure_component(cuopt_base) +target_include_directories(cuopt_base PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") +target_compile_definitions(cuopt_base PUBLIC + CUOPT_CUDA_ARCHITECTURES="${JOINED_CUDA_ARCHITECTURES}" + CUOPT_CPU_ARCHITECTURE="${CMAKE_SYSTEM_PROCESSOR}" +) +target_link_libraries(cuopt_base + PUBLIC + rmm::rmm + rapids_logger::rapids_logger + CCCL::CCCL + raft::raft + CUDA::cublas + CUDA::cusparse + PRIVATE + OpenMP::OpenMP_CXX + OpenMP::OpenMP_CUDA +) +add_library(cuopt::base ALIAS cuopt_base) + +# cuopt_routing: VRP / routing engine (omitted when SKIP_ROUTING_BUILD=ON) +if(NOT SKIP_ROUTING_BUILD) + add_library(cuopt_routing STATIC ${CUOPT_ROUTING_SRC_FILES}) + cuopt_configure_component(cuopt_routing) + target_link_libraries(cuopt_routing + PUBLIC cuopt_base + PRIVATE simde::simde OpenMP::OpenMP_CXX + ) + add_library(cuopt::routing ALIAS cuopt_routing) +endif() + +# cuopt_lp: LP / MIP / numerical optimization engine +add_library(cuopt_lp STATIC ${CUOPT_LP_SRC_FILES}) +cuopt_configure_component(cuopt_lp) +target_include_directories(cuopt_lp PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io" + "${CUDSS_INCLUDE}" + $<$:${BZIP2_INCLUDE_DIRS}> + $<$:${ZLIB_INCLUDE_DIRS}> +) # Adding Papilo as a system include messes up clang's include resolution if papilo is already installed as a conda package -target_include_directories(cuopt PRIVATE +target_include_directories(cuopt_lp PRIVATE "${papilo_SOURCE_DIR}/src" "${papilo_BINARY_DIR}" ) - -target_include_directories(cuopt SYSTEM PRIVATE +target_include_directories(cuopt_lp SYSTEM PRIVATE "${pslp_SOURCE_DIR}/include" "${dejavu_SOURCE_DIR}" ) +target_compile_definitions(cuopt_lp + PUBLIC CUSPARSE_ENABLE_EXPERIMENTAL_API + PRIVATE CUDSS_MT_LIB_FILE_NAME="${CUDSS_MT_LIB_FILE_NAME}" +) +target_link_libraries(cuopt_lp + PUBLIC + cuopt_base + ${CUDSS_LIB_FILE} + PRIVATE + ${CUOPT_PRIVATE_CUDA_LIBS} + OpenMP::OpenMP_CUDA +) +target_link_libraries(cuopt_lp PRIVATE $) +add_dependencies(cuopt_lp PSLP) +add_library(cuopt::lp ALIAS cuopt_lp) + +# ################################################################################################## +# - cuopt: umbrella shared library ---------------------------------------------------------------- +# Re-exports all symbols from the three component libs via --whole-archive. +# Backward-compatible: GAMS and any consumer using -lcuopt / libcuopt.so is unaffected. +# gRPC integration layer (maps proto <-> C++ LP API) lives here, not in cuopt_lp. + +message(STATUS "target include directories CUDSS_INCLUDES = ${CUDSS_INCLUDE}") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp" "// cuopt umbrella\n") + +if(NOT SKIP_GRPC_BUILD) + set(CUOPT_UMBRELLA_EXTRA_SRCS ${GRPC_INFRA_FILES}) +endif() + +add_library(cuopt SHARED + "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp" + ${CUOPT_UMBRELLA_EXTRA_SRCS} +) + +set_target_properties(cuopt PROPERTIES + BUILD_RPATH "\$ORIGIN" + INSTALL_RPATH "\$ORIGIN" + INTERFACE_POSITION_INDEPENDENT_CODE ON + CXX_SCAN_FOR_MODULES OFF +) + +target_compile_options(cuopt + PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" + "$<$:${CUOPT_CUDA_FLAGS}>" +) target_include_directories(cuopt PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty" "${CMAKE_CURRENT_SOURCE_DIR}/src" - "${CMAKE_CURRENT_SOURCE_DIR}/src/io" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated" "${CMAKE_CURRENT_BINARY_DIR}" - "${CUDSS_INCLUDE}" - $<$:${BZIP2_INCLUDE_DIRS}> - $<$:${ZLIB_INCLUDE_DIRS}> PUBLIC "$" "$" @@ -580,67 +684,34 @@ target_include_directories(cuopt "$" ) -# Link PSLP by file to avoid export dependency tracking -target_link_libraries(cuopt PRIVATE $) -add_dependencies(cuopt PSLP) - -# ################################################################################################## -# - link libraries -------------------------------------------------------------------------------- - -set(CUOPT_PRIVATE_CUDA_LIBS - CUDA::curand - CUDA::cusolver - TBB::tbb - OpenMP::OpenMP_CXX) - -list(PREPEND CUOPT_PRIVATE_CUDA_LIBS CUDA::cublasLt) - -# Pass CUDSS_MT_LIB_FILE_NAME as a compile definition -get_filename_component(CUDSS_MT_LIB_FILE_NAME "${CUDSS_MT_LIB_FILE}" NAME) -target_compile_definitions(cuopt PRIVATE CUDSS_MT_LIB_FILE_NAME="${CUDSS_MT_LIB_FILE_NAME}") - -execute_process( - COMMAND git rev-parse --short HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE -) -message("-- Building with GIT_COMMIT_HASH = '${GIT_COMMIT_HASH}'") - -# Generate build_info.hpp from template -# configure_file() only updates the output if content changes, avoiding unnecessary rebuilds -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/src/utilities/build_info.hpp.in - ${CMAKE_CURRENT_BINARY_DIR}/include/utilities/build_info.hpp - @ONLY -) - -# Add the generated include directory -target_include_directories(cuopt PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) - -list(JOIN CMAKE_CUDA_ARCHITECTURES "," JOINED_CUDA_ARCHITECTURES) -target_compile_definitions(cuopt PUBLIC - CUOPT_CUDA_ARCHITECTURES="${JOINED_CUDA_ARCHITECTURES}" - CUOPT_CPU_ARCHITECTURE="${CMAKE_SYSTEM_PROCESSOR}") +if(NOT SKIP_ROUTING_BUILD) + target_link_libraries(cuopt PUBLIC + $) +else() + target_link_libraries(cuopt PUBLIC + $) +endif() target_link_libraries(cuopt - PUBLIC - CUDA::cublas - CUDA::cusparse - rmm::rmm - rapids_logger::rapids_logger - CCCL::CCCL - raft::raft - ${CUDSS_LIB_FILE} PRIVATE - ${CUOPT_PRIVATE_CUDA_LIBS} - simde::simde - OpenMP::OpenMP_CXX - OpenMP::OpenMP_CUDA $<$:protobuf::libprotobuf> $<$:gRPC::grpc++> ) +if (WRITE_FATBIN) + file(WRITE "${CUOPT_BINARY_DIR}/fatbin.ld" + [=[ + SECTIONS + { + .nvFatBinSegment : { *(.nvFatBinSegment) } + .nv_fatbin : { *(.nv_fatbin) } + } + ]=]) + target_link_options(cuopt PRIVATE "${CUOPT_BINARY_DIR}/fatbin.ld") +endif () + +add_library(cuopt::cuopt ALIAS cuopt) + # ################################################################################################## # - generate tests -------------------------------------------------------------------------------- if (BUILD_TESTS) @@ -669,14 +740,25 @@ else () set(_INCLUDE_DEST include/cuopt/) endif () -# adds the .so files to the runtime deb package +# Install component static libs (runtime: none — statics are build-time only; +# dev: headers are shared, statics go in the dev package for downstream cmake consumers) +set(CUOPT_COMPONENT_TARGETS cuopt_base cuopt_lp) +if(NOT SKIP_ROUTING_BUILD) + list(APPEND CUOPT_COMPONENT_TARGETS cuopt_routing) +endif() +install(TARGETS ${CUOPT_COMPONENT_TARGETS} + DESTINATION ${_LIB_DEST} + COMPONENT dev + EXPORT cuopt-exports +) + +# Install umbrella shared library (the primary runtime artifact) install(TARGETS cuopt DESTINATION ${_LIB_DEST} COMPONENT runtime EXPORT cuopt-exports ) -# adds the .so files to the development deb package install(TARGETS cuopt DESTINATION ${_LIB_DEST} COMPONENT dev @@ -700,12 +782,14 @@ set(doc_string Provide targets for cuOpt. cuOpt library is a collection of GPU accelerated combinatorial optimization algorithms. +Component targets: cuopt::base, cuopt::routing, cuopt::lp +Umbrella target: cuopt::cuopt (re-exports all symbols — backward-compatible with -lcuopt) ]=]) rapids_export(INSTALL cuopt EXPORT_SET cuopt-exports - GLOBAL_TARGETS cuopt + GLOBAL_TARGETS cuopt ${CUOPT_COMPONENT_TARGETS} NAMESPACE cuopt:: DOCUMENTATION doc_string ) @@ -714,7 +798,7 @@ rapids_export(INSTALL cuopt # - build export ------------------------------------------------------------------------------- rapids_export(BUILD cuopt EXPORT_SET cuopt-exports - GLOBAL_TARGETS cuopt + GLOBAL_TARGETS cuopt ${CUOPT_COMPONENT_TARGETS} NAMESPACE cuopt:: DOCUMENTATION doc_string ) diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index e8737cf6d..8af5cf4df 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -25,5 +25,34 @@ add_subdirectory(barrier) add_subdirectory(branch_and_bound) add_subdirectory(cuts) -set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${UTIL_SRC_FILES} PARENT_SCOPE) +# Aggregate per-domain source lists for the three component libraries +set(CUOPT_BASE_SRC_FILES + ${UTIL_SRC_FILES} + ${LINEAR_ALGEBRA_SRC_FILES} +) + +set(CUOPT_ROUTING_SRC_FILES + ${ROUTING_SRC_FILES} +) + +set(CUOPT_LP_SRC_FILES + ${LP_SRC_FILES} + ${MATH_OPT_SRC_FILES} + ${MIP_SRC_FILES} + ${PARSERS_SRC_FILES} + ${DUAL_SIMPLEX_SRC_FILES} + ${BARRIER_SRC_FILES} + ${BRANCH_AND_BOUND_SRC_FILES} + ${CUTS_SRC_FILES} +) + +set(CUOPT_BASE_SRC_FILES ${CUOPT_BASE_SRC_FILES} PARENT_SCOPE) +set(CUOPT_ROUTING_SRC_FILES ${CUOPT_ROUTING_SRC_FILES} PARENT_SCOPE) +set(CUOPT_LP_SRC_FILES ${CUOPT_LP_SRC_FILES} PARENT_SCOPE) +set(CUOPT_SRC_FILES + ${CUOPT_BASE_SRC_FILES} + ${CUOPT_ROUTING_SRC_FILES} + ${CUOPT_LP_SRC_FILES} + PARENT_SCOPE +) set(MPS_FAST_SRC_FILES ${MPS_FAST_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/barrier/CMakeLists.txt b/cpp/src/barrier/CMakeLists.txt index 650bc733e..83af7da10 100644 --- a/cpp/src/barrier/CMakeLists.txt +++ b/cpp/src/barrier/CMakeLists.txt @@ -10,5 +10,6 @@ set(BARRIER_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pinned_host_allocator.cu ) +set(BARRIER_SRC_FILES ${BARRIER_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${BARRIER_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/branch_and_bound/CMakeLists.txt b/cpp/src/branch_and_bound/CMakeLists.txt index 1e40c1bbf..c9f47c4d5 100644 --- a/cpp/src/branch_and_bound/CMakeLists.txt +++ b/cpp/src/branch_and_bound/CMakeLists.txt @@ -10,5 +10,6 @@ set(BRANCH_AND_BOUND_SRC_FILES ) +set(BRANCH_AND_BOUND_SRC_FILES ${BRANCH_AND_BOUND_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${BRANCH_AND_BOUND_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/cuts/CMakeLists.txt b/cpp/src/cuts/CMakeLists.txt index 813ac88a5..07d945135 100644 --- a/cpp/src/cuts/CMakeLists.txt +++ b/cpp/src/cuts/CMakeLists.txt @@ -8,5 +8,6 @@ set(CUTS_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/objective_step.cpp ) +set(CUTS_SRC_FILES ${CUTS_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${CUTS_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/dual_simplex/CMakeLists.txt b/cpp/src/dual_simplex/CMakeLists.txt index 228f2aedd..1f424c69a 100644 --- a/cpp/src/dual_simplex/CMakeLists.txt +++ b/cpp/src/dual_simplex/CMakeLists.txt @@ -25,5 +25,6 @@ set(DUAL_SIMPLEX_SRC_FILES # Uncomment to enable debug info #set_source_files_properties(${DUAL_SIMPLEX_SRC_FILES} DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTIES COMPILE_OPTIONS "-g1") +set(DUAL_SIMPLEX_SRC_FILES ${DUAL_SIMPLEX_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${DUAL_SIMPLEX_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/io/CMakeLists.txt b/cpp/src/io/CMakeLists.txt index cafcffb23..29bd8dc1e 100644 --- a/cpp/src/io/CMakeLists.txt +++ b/cpp/src/io/CMakeLists.txt @@ -23,5 +23,6 @@ set(PARSERS_SRC_FILES ${MPS_FAST_SRC_FILES} ) -set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${PARSERS_SRC_FILES} PARENT_SCOPE) +set(PARSERS_SRC_FILES ${PARSERS_SRC_FILES} PARENT_SCOPE) set(MPS_FAST_SRC_FILES ${MPS_FAST_SRC_FILES} PARENT_SCOPE) +set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${PARSERS_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/linear_algebra/CMakeLists.txt b/cpp/src/linear_algebra/CMakeLists.txt index 875a01654..7a8ad1fa0 100644 --- a/cpp/src/linear_algebra/CMakeLists.txt +++ b/cpp/src/linear_algebra/CMakeLists.txt @@ -9,5 +9,6 @@ set(LINEAR_ALGEBRA_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vector_math.cpp ) +set(LINEAR_ALGEBRA_SRC_FILES ${LINEAR_ALGEBRA_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${LINEAR_ALGEBRA_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/math_optimization/CMakeLists.txt b/cpp/src/math_optimization/CMakeLists.txt index efa1600c5..3a118cf16 100644 --- a/cpp/src/math_optimization/CMakeLists.txt +++ b/cpp/src/math_optimization/CMakeLists.txt @@ -11,5 +11,6 @@ list(PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/tic_toc.cpp ) +set(MATH_OPT_SRC_FILES ${MATH_OPT_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${MATH_OPT_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/mip_heuristics/CMakeLists.txt b/cpp/src/mip_heuristics/CMakeLists.txt index 770546551..4b8bcfd3a 100644 --- a/cpp/src/mip_heuristics/CMakeLists.txt +++ b/cpp/src/mip_heuristics/CMakeLists.txt @@ -53,5 +53,6 @@ else() set(MIP_SRC_FILES ${MIP_LP_NECESSARY_FILES} ${MIP_NON_LP_FILES}) endif() +set(MIP_SRC_FILES ${MIP_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${MIP_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/pdlp/CMakeLists.txt b/cpp/src/pdlp/CMakeLists.txt index f5f26837b..c90332355 100644 --- a/cpp/src/pdlp/CMakeLists.txt +++ b/cpp/src/pdlp/CMakeLists.txt @@ -44,4 +44,5 @@ else() set(LP_SRC_FILES ${LP_CORE_FILES} ${LP_ADAPTER_FILES}) endif() +set(LP_SRC_FILES ${LP_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${LP_SRC_FILES} PARENT_SCOPE) diff --git a/cpp/src/routing/CMakeLists.txt b/cpp/src/routing/CMakeLists.txt index 452c4806d..c92b4d0f3 100644 --- a/cpp/src/routing/CMakeLists.txt +++ b/cpp/src/routing/CMakeLists.txt @@ -50,4 +50,5 @@ set(ROUTING_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/utilities/check_input.cu ${CMAKE_CURRENT_SOURCE_DIR}/utilities/cython.cu) +set(ROUTING_SRC_FILES ${ROUTING_SRC_FILES} PARENT_SCOPE) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} ${ROUTING_SRC_FILES} PARENT_SCOPE) From 94755a05d690f1c61458d2caf81af4316f6cd63d Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Fri, 24 Jul 2026 09:52:31 -0500 Subject: [PATCH 02/12] build(cmake): fix component library linking and include propagation Four issues found while validating the library split locally: - cuopt_routing was missing OpenMP::OpenMP_CUDA, causing routing CUDA files to reject #pragma omp directives as unknown in CUDA compiler mode - cuopt_lp was missing simde::simde, required by the fast MPS parser (io/experimental_mps_fast/) which uses SIMD intrinsics via simde headers - The umbrella cuopt target was missing src/io in its private include dirs, causing gRPC mapper files (grpc_problem_mapper.cpp) that include mps_parser_internal.hpp to fail to compile - WHOLE_ARCHIVE linkage on the umbrella was PUBLIC, propagating the static sub-libs as link dependencies to all consumers (test binaries). This caused double-definition errors when tests linked both libcuopt.so and the statics. Changed to PRIVATE and re-exposed the statics' transitive PUBLIC deps (rmm, raft, CCCL, CUDA libs) directly on the umbrella so that consumers receive the correct source-fetched include dirs. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/CMakeLists.txt | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 699b72765..380dc294f 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -599,7 +599,7 @@ if(NOT SKIP_ROUTING_BUILD) cuopt_configure_component(cuopt_routing) target_link_libraries(cuopt_routing PUBLIC cuopt_base - PRIVATE simde::simde OpenMP::OpenMP_CXX + PRIVATE simde::simde OpenMP::OpenMP_CXX OpenMP::OpenMP_CUDA ) add_library(cuopt::routing ALIAS cuopt_routing) endif() @@ -634,6 +634,7 @@ target_link_libraries(cuopt_lp PRIVATE ${CUOPT_PRIVATE_CUDA_LIBS} OpenMP::OpenMP_CUDA + simde::simde ) target_link_libraries(cuopt_lp PRIVATE $) add_dependencies(cuopt_lp PSLP) @@ -673,6 +674,7 @@ target_compile_options(cuopt target_include_directories(cuopt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated" @@ -685,18 +687,34 @@ target_include_directories(cuopt ) if(NOT SKIP_ROUTING_BUILD) - target_link_libraries(cuopt PUBLIC + target_link_libraries(cuopt PRIVATE $) else() - target_link_libraries(cuopt PUBLIC + target_link_libraries(cuopt PRIVATE $) endif() +# Re-expose the component statics' PUBLIC deps so that consumers of cuopt::cuopt +# (tests, downstream cmake, GAMS) receive the correct include dirs and link targets. target_link_libraries(cuopt + PUBLIC + rmm::rmm + rapids_logger::rapids_logger + CCCL::CCCL + raft::raft + CUDA::cublas + CUDA::cusparse + ${CUDSS_LIB_FILE} PRIVATE $<$:protobuf::libprotobuf> $<$:gRPC::grpc++> ) +target_compile_definitions(cuopt PUBLIC + "CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}" + CUOPT_CUDA_ARCHITECTURES="${JOINED_CUDA_ARCHITECTURES}" + CUOPT_CPU_ARCHITECTURE="${CMAKE_SYSTEM_PROCESSOR}" + CUSPARSE_ENABLE_EXPERIMENTAL_API +) if (WRITE_FATBIN) file(WRITE "${CUOPT_BINARY_DIR}/fatbin.ld" From 0390d40edbdcced133ee4e8eac4ceb8e0387dfee Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Fri, 24 Jul 2026 13:48:52 -0500 Subject: [PATCH 03/12] build(conda): verify component static libs in libcuopt package_contents Add libcuopt_base.a, libcuopt_routing.a, and libcuopt_lp.a to the package_contents file check so CI fails fast if any of the three component static libraries are missing from the installed package. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- conda/recipes/libcuopt/recipe.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conda/recipes/libcuopt/recipe.yaml b/conda/recipes/libcuopt/recipe.yaml index 77c957ead..475fafba7 100644 --- a/conda/recipes/libcuopt/recipe.yaml +++ b/conda/recipes/libcuopt/recipe.yaml @@ -162,6 +162,9 @@ outputs: - package_contents: files: - lib/libcuopt.so + - lib/libcuopt_base.a + - lib/libcuopt_routing.a + - lib/libcuopt_lp.a - bin/cuopt_cli - bin/cuopt_grpc_server about: From efc5256c70cd4df058dca90962e2ab250918eafa Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Mon, 27 Jul 2026 10:08:35 -0500 Subject: [PATCH 04/12] build(cmake): switch component libs to SHARED and move gRPC bridge into cuopt_lp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Component libs (cuopt_base, cuopt_routing, cuopt_lp) are now SHARED instead of STATIC. The umbrella libcuopt.so becomes a thin stub (~15 KB) carrying only DT_NEEDED entries for the three component libs; no code or WHOLE_ARCHIVE baking. The gRPC bridge (mapper + Cython client) moves from the umbrella into cuopt_lp where it semantically belongs — LP/MIP remote solve is an LP concern. The umbrella drops all gRPC sources, include dirs, and protobuf/gRPC link deps. Both RPATH settings use $ORIGIN so component libs find each other when co-installed. Conda package_contents check updated from .a to .so. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- conda/recipes/libcuopt/recipe.yaml | 6 +-- cpp/CMakeLists.txt | 86 +++++++++--------------------- 2 files changed, 28 insertions(+), 64 deletions(-) diff --git a/conda/recipes/libcuopt/recipe.yaml b/conda/recipes/libcuopt/recipe.yaml index 475fafba7..f794204c7 100644 --- a/conda/recipes/libcuopt/recipe.yaml +++ b/conda/recipes/libcuopt/recipe.yaml @@ -162,9 +162,9 @@ outputs: - package_contents: files: - lib/libcuopt.so - - lib/libcuopt_base.a - - lib/libcuopt_routing.a - - lib/libcuopt_lp.a + - lib/libcuopt_base.so + - lib/libcuopt_routing.so + - lib/libcuopt_lp.so - bin/cuopt_cli - bin/cuopt_grpc_server about: diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 380dc294f..9ebc097d3 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -492,7 +492,7 @@ if (DEFINE_ASSERT) endif () if (NOT SKIP_GRPC_BUILD) - # gRPC integration layer: maps proto <-> C++ LP API; lives in the umbrella, not in cuopt_lp + # gRPC integration layer: maps proto <-> C++ LP API; compiled into cuopt_lp set(GRPC_INFRA_FILES ${DATA_PROTO_SRCS} ${PROTO_SRCS} @@ -523,8 +523,9 @@ endif (NOT SKIP_GRPC_BUILD) # Helper: apply compile options and common include paths to all cuOpt component libs function(cuopt_configure_component target) set_target_properties(${target} PROPERTIES - POSITION_INDEPENDENT_CODE ON CXX_SCAN_FOR_MODULES OFF + BUILD_RPATH_USE_ORIGIN TRUE + INSTALL_RPATH "\$ORIGIN" ) target_compile_options(${target} PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" @@ -572,7 +573,7 @@ set(CUOPT_PRIVATE_CUDA_LIBS get_filename_component(CUDSS_MT_LIB_FILE_NAME "${CUDSS_MT_LIB_FILE}" NAME) # cuopt_base: utilities + linear algebra (stateful shared infra — logger, work scheduler) -add_library(cuopt_base STATIC ${CUOPT_BASE_SRC_FILES}) +add_library(cuopt_base SHARED ${CUOPT_BASE_SRC_FILES}) cuopt_configure_component(cuopt_base) target_include_directories(cuopt_base PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") target_compile_definitions(cuopt_base PUBLIC @@ -595,7 +596,7 @@ add_library(cuopt::base ALIAS cuopt_base) # cuopt_routing: VRP / routing engine (omitted when SKIP_ROUTING_BUILD=ON) if(NOT SKIP_ROUTING_BUILD) - add_library(cuopt_routing STATIC ${CUOPT_ROUTING_SRC_FILES}) + add_library(cuopt_routing SHARED ${CUOPT_ROUTING_SRC_FILES}) cuopt_configure_component(cuopt_routing) target_link_libraries(cuopt_routing PUBLIC cuopt_base @@ -605,7 +606,7 @@ if(NOT SKIP_ROUTING_BUILD) endif() # cuopt_lp: LP / MIP / numerical optimization engine -add_library(cuopt_lp STATIC ${CUOPT_LP_SRC_FILES}) +add_library(cuopt_lp SHARED ${CUOPT_LP_SRC_FILES}) cuopt_configure_component(cuopt_lp) target_include_directories(cuopt_lp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty" @@ -638,47 +639,36 @@ target_link_libraries(cuopt_lp ) target_link_libraries(cuopt_lp PRIVATE $) add_dependencies(cuopt_lp PSLP) +if(NOT SKIP_GRPC_BUILD) + target_sources(cuopt_lp PRIVATE ${GRPC_INFRA_FILES}) + target_include_directories(cuopt_lp PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc" + "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client" + "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated" + ) + target_link_libraries(cuopt_lp PRIVATE protobuf::libprotobuf gRPC::grpc++) +endif() add_library(cuopt::lp ALIAS cuopt_lp) # ################################################################################################## -# - cuopt: umbrella shared library ---------------------------------------------------------------- -# Re-exports all symbols from the three component libs via --whole-archive. -# Backward-compatible: GAMS and any consumer using -lcuopt / libcuopt.so is unaffected. -# gRPC integration layer (maps proto <-> C++ LP API) lives here, not in cuopt_lp. +# - cuopt: thin umbrella shared library ----------------------------------------------------------- +# Links publicly against the three component shared libs so that -lcuopt keeps working for +# all existing consumers. No code of its own except the gRPC bridge (mapper + client) which +# sits here because it spans both the LP API and gRPC transport layers. message(STATUS "target include directories CUDSS_INCLUDES = ${CUDSS_INCLUDE}") -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp" "// cuopt umbrella\n") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp" "// thin umbrella\n") -if(NOT SKIP_GRPC_BUILD) - set(CUOPT_UMBRELLA_EXTRA_SRCS ${GRPC_INFRA_FILES}) -endif() - -add_library(cuopt SHARED - "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp" - ${CUOPT_UMBRELLA_EXTRA_SRCS} -) +add_library(cuopt SHARED "${CMAKE_CURRENT_BINARY_DIR}/cuopt_umbrella.cpp") set_target_properties(cuopt PROPERTIES - BUILD_RPATH "\$ORIGIN" + BUILD_RPATH_USE_ORIGIN TRUE INSTALL_RPATH "\$ORIGIN" - INTERFACE_POSITION_INDEPENDENT_CODE ON CXX_SCAN_FOR_MODULES OFF ) -target_compile_options(cuopt - PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" - "$<$:${CUOPT_CUDA_FLAGS}>" -) - target_include_directories(cuopt - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/src" - "${CMAKE_CURRENT_SOURCE_DIR}/src/io" - "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc" - "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client" - "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated" - "${CMAKE_CURRENT_BINARY_DIR}" PUBLIC "$" "$" @@ -687,35 +677,11 @@ target_include_directories(cuopt ) if(NOT SKIP_ROUTING_BUILD) - target_link_libraries(cuopt PRIVATE - $) + target_link_libraries(cuopt PUBLIC cuopt_base cuopt_routing cuopt_lp) else() - target_link_libraries(cuopt PRIVATE - $) + target_link_libraries(cuopt PUBLIC cuopt_base cuopt_lp) endif() -# Re-expose the component statics' PUBLIC deps so that consumers of cuopt::cuopt -# (tests, downstream cmake, GAMS) receive the correct include dirs and link targets. -target_link_libraries(cuopt - PUBLIC - rmm::rmm - rapids_logger::rapids_logger - CCCL::CCCL - raft::raft - CUDA::cublas - CUDA::cusparse - ${CUDSS_LIB_FILE} - PRIVATE - $<$:protobuf::libprotobuf> - $<$:gRPC::grpc++> -) -target_compile_definitions(cuopt PUBLIC - "CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}" - CUOPT_CUDA_ARCHITECTURES="${JOINED_CUDA_ARCHITECTURES}" - CUOPT_CPU_ARCHITECTURE="${CMAKE_SYSTEM_PROCESSOR}" - CUSPARSE_ENABLE_EXPERIMENTAL_API -) - if (WRITE_FATBIN) file(WRITE "${CUOPT_BINARY_DIR}/fatbin.ld" [=[ @@ -758,15 +724,13 @@ else () set(_INCLUDE_DEST include/cuopt/) endif () -# Install component static libs (runtime: none — statics are build-time only; -# dev: headers are shared, statics go in the dev package for downstream cmake consumers) set(CUOPT_COMPONENT_TARGETS cuopt_base cuopt_lp) if(NOT SKIP_ROUTING_BUILD) list(APPEND CUOPT_COMPONENT_TARGETS cuopt_routing) endif() install(TARGETS ${CUOPT_COMPONENT_TARGETS} DESTINATION ${_LIB_DEST} - COMPONENT dev + COMPONENT runtime EXPORT cuopt-exports ) From 08c8db47e01ba7e8f60e32af634fb34a3cf4e820 Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Mon, 27 Jul 2026 14:33:43 -0500 Subject: [PATCH 05/12] build(cmake): extract gRPC bridge into libcuopt_grpc.so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves all gRPC infrastructure (proto mappers, Cython client, solve_remote) from cuopt_lp into a new cuopt_grpc SHARED component. cuopt_grpc links cuopt_lp + cuopt_routing (when built), keeping both core solver libs free of any gRPC/protobuf dependency. The grpc_server binary now links cuopt_grpc directly. The umbrella links cuopt_grpc when gRPC is built so -lcuopt continues to expose remote-solve symbols to existing consumers. When PR #1597 (VRP gRPC) lands, routing gRPC sources go into cuopt_grpc alongside the LP ones — no cross-dependency between cuopt_lp and cuopt_routing is needed. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- conda/recipes/libcuopt/recipe.yaml | 1 + cpp/CMakeLists.txt | 33 ++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/conda/recipes/libcuopt/recipe.yaml b/conda/recipes/libcuopt/recipe.yaml index f794204c7..280f42573 100644 --- a/conda/recipes/libcuopt/recipe.yaml +++ b/conda/recipes/libcuopt/recipe.yaml @@ -165,6 +165,7 @@ outputs: - lib/libcuopt_base.so - lib/libcuopt_routing.so - lib/libcuopt_lp.so + - lib/libcuopt_grpc.so - bin/cuopt_cli - bin/cuopt_grpc_server about: diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 9ebc097d3..80c4c32ba 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -492,7 +492,7 @@ if (DEFINE_ASSERT) endif () if (NOT SKIP_GRPC_BUILD) - # gRPC integration layer: maps proto <-> C++ LP API; compiled into cuopt_lp + # gRPC integration layer: maps proto <-> C++ LP/routing APIs; compiled into cuopt_grpc set(GRPC_INFRA_FILES ${DATA_PROTO_SRCS} ${PROTO_SRCS} @@ -639,16 +639,27 @@ target_link_libraries(cuopt_lp ) target_link_libraries(cuopt_lp PRIVATE $) add_dependencies(cuopt_lp PSLP) +add_library(cuopt::lp ALIAS cuopt_lp) + +# cuopt_grpc: gRPC bridge — proto mappers + Cython client (LP and routing over gRPC) +# Depends on cuopt_lp and cuopt_routing so it can reference both APIs without forcing +# either component to take a gRPC dependency. if(NOT SKIP_GRPC_BUILD) - target_sources(cuopt_lp PRIVATE ${GRPC_INFRA_FILES}) - target_include_directories(cuopt_lp PRIVATE + add_library(cuopt_grpc SHARED ${GRPC_INFRA_FILES}) + cuopt_configure_component(cuopt_grpc) + target_include_directories(cuopt_grpc PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client" "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io" ) - target_link_libraries(cuopt_lp PRIVATE protobuf::libprotobuf gRPC::grpc++) + if(NOT SKIP_ROUTING_BUILD) + target_link_libraries(cuopt_grpc PUBLIC cuopt_lp cuopt_routing PRIVATE protobuf::libprotobuf gRPC::grpc++) + else() + target_link_libraries(cuopt_grpc PUBLIC cuopt_lp PRIVATE protobuf::libprotobuf gRPC::grpc++) + endif() + add_library(cuopt::grpc ALIAS cuopt_grpc) endif() -add_library(cuopt::lp ALIAS cuopt_lp) # ################################################################################################## # - cuopt: thin umbrella shared library ----------------------------------------------------------- @@ -681,6 +692,9 @@ if(NOT SKIP_ROUTING_BUILD) else() target_link_libraries(cuopt PUBLIC cuopt_base cuopt_lp) endif() +if(NOT SKIP_GRPC_BUILD) + target_link_libraries(cuopt PUBLIC cuopt_grpc) +endif() if (WRITE_FATBIN) file(WRITE "${CUOPT_BINARY_DIR}/fatbin.ld" @@ -728,6 +742,9 @@ set(CUOPT_COMPONENT_TARGETS cuopt_base cuopt_lp) if(NOT SKIP_ROUTING_BUILD) list(APPEND CUOPT_COMPONENT_TARGETS cuopt_routing) endif() +if(NOT SKIP_GRPC_BUILD) + list(APPEND CUOPT_COMPONENT_TARGETS cuopt_grpc) +endif() install(TARGETS ${CUOPT_COMPONENT_TARGETS} DESTINATION ${_LIB_DEST} COMPONENT runtime @@ -764,8 +781,8 @@ set(doc_string Provide targets for cuOpt. cuOpt library is a collection of GPU accelerated combinatorial optimization algorithms. -Component targets: cuopt::base, cuopt::routing, cuopt::lp -Umbrella target: cuopt::cuopt (re-exports all symbols — backward-compatible with -lcuopt) +Component targets: cuopt::base, cuopt::routing, cuopt::lp, cuopt::grpc (when gRPC is built) +Umbrella target: cuopt::cuopt (links all component libs — backward-compatible with -lcuopt) ]=]) @@ -967,7 +984,7 @@ if (NOT SKIP_GRPC_BUILD) target_link_libraries(cuopt_grpc_server PUBLIC - cuopt + cuopt_grpc OpenMP::OpenMP_CXX PRIVATE protobuf::libprotobuf From a54e62a5b5abc992bbc6ce1763f9b150df4ddfe4 Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Mon, 27 Jul 2026 15:36:57 -0500 Subject: [PATCH 06/12] chore: fix copyright year in routing CMakeLists.txt Co-Authored-By: Claude Sonnet 4.6 --- cpp/src/routing/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/routing/CMakeLists.txt b/cpp/src/routing/CMakeLists.txt index c92b4d0f3..fa9653076 100644 --- a/cpp/src/routing/CMakeLists.txt +++ b/cpp/src/routing/CMakeLists.txt @@ -1,5 +1,5 @@ # cmake-format: off -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # cmake-format: on From 6c24d1f6af468facaa91874754814a8777e0df7f Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Mon, 27 Jul 2026 16:23:25 -0500 Subject: [PATCH 07/12] fix(ci): exclude component libs from auditwheel repair in cuopt wheel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libcuopt.so is now a thin umbrella with DT_NEEDED on libcuopt_base.so, libcuopt_routing.so, libcuopt_lp.so, and libcuopt_grpc.so. auditwheel traverses DT_NEEDED transitively and failed when it couldn't locate the component libs. Exclude them the same way libcuopt.so is excluded — they ship with the libcuopt wheel and are available at runtime. Co-Authored-By: Claude Sonnet 4.6 --- ci/build_wheel_cuopt.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci/build_wheel_cuopt.sh b/ci/build_wheel_cuopt.sh index f624b2770..449bc1966 100755 --- a/ci/build_wheel_cuopt.sh +++ b/ci/build_wheel_cuopt.sh @@ -41,6 +41,10 @@ EXCLUDE_ARGS=( --exclude "libcusolver.so.*" --exclude "libcusparse.so.*" --exclude "libcuopt.so" + --exclude "libcuopt_base.so" + --exclude "libcuopt_routing.so" + --exclude "libcuopt_lp.so" + --exclude "libcuopt_grpc.so" --exclude "librapids_logger.so" --exclude "librmm.so" ) From 705167fa69e55fe7f64d15a55db026f0d336af71 Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Mon, 27 Jul 2026 16:32:29 -0500 Subject: [PATCH 08/12] fix(cmake): include gRPC sources in cuopt_objs for cuopt_static test builds main appends GRPC_INFRA_FILES to CUOPT_SRC_FILES before creating cuopt_objs so cuopt_static (used by NUMOPT_INTERNAL_TEST) gets solve_lp_remote / solve_mip_remote. We dropped that line when we moved those files into cuopt_grpc, causing undefined-reference link failures in tests. Co-Authored-By: Claude Sonnet 4.6 --- cpp/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 9d9d74198..cfb05e146 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -515,6 +515,9 @@ if (NOT SKIP_GRPC_BUILD) # at runtime with "undefined symbol: absl::…::Mutex::Dtor". set_property(SOURCE ${GRPC_INFRA_FILES} DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND PROPERTY COMPILE_OPTIONS "-DNDEBUG") + # Include gRPC sources in CUOPT_SRC_FILES so cuopt_objs (and cuopt_static for tests) + # have solve_lp_remote / solve_mip_remote defined when CUOPT_ENABLE_GRPC is set. + list(APPEND CUOPT_SRC_FILES ${GRPC_INFRA_FILES}) endif (NOT SKIP_GRPC_BUILD) # ################################################################################################## From a42419b499ce83fa8baa6aeb087a27ee97d757ac Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Tue, 28 Jul 2026 10:40:56 -0500 Subject: [PATCH 09/12] fix(cmake): link cuopt_cli against cuopt_grpc for runtime symbol resolution cuopt_lp.so calls solve_lp/mip_remote (under CUOPT_ENABLE_GRPC) which are defined in cuopt_grpc.so. With --as-needed the linker was dropping libcuopt_grpc.so from executables that never directly referenced a grpc symbol, leaving solve_lp_remote unresolved at runtime. Route remote solves in cuopt_cli directly through solve_lp/mip_remote so libcuopt_grpc.so is a genuine DT_NEEDED of the binary; --as-needed then keeps it in the link and the symbol is in scope when libcuopt_lp.so needs it. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/CMakeLists.txt | 1 + cpp/cuopt_cli.cpp | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index cfb05e146..5270c70ca 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -981,6 +981,7 @@ if (NOT BUILD_LP_ONLY) target_link_libraries(cuopt_cli PUBLIC cuopt + $<$:cuopt_grpc> OpenMP::OpenMP_CXX ${CUDSS_LIBRARIES} TBB::tbb diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index feb0e8cd7..992c7f455 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,22 @@ int run_single_file(const std::string& file_path, } try { - if (is_mip) { + if (memory_backend == cuopt::mathematical_optimization::memory_backend_t::CPU) { + // Remote execution: problem_interface holds a cpu_optimization_problem_t. + // Call solve_lp/mip_remote directly so libcuopt_grpc.so is a real DT_NEEDED + // dependency of this binary rather than an implicit runtime lookup. + auto* cpu_prob = static_cast*>(problem_interface.get()); + if (is_mip) { + auto& mip_settings = settings.get_mip_settings(); + auto solution = + cuopt::mathematical_optimization::solve_mip_remote(*cpu_prob, mip_settings); + } else { + auto& lp_settings = settings.get_pdlp_settings(); + auto solution = + cuopt::mathematical_optimization::solve_lp_remote(*cpu_prob, lp_settings); + } + } else if (is_mip) { auto& mip_settings = settings.get_mip_settings(); auto solution = cuopt::mathematical_optimization::solve_mip(problem_interface.get(), mip_settings); From 776bd3bae6e14fbeb290bd15765b996a259d49eb Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Tue, 28 Jul 2026 12:18:59 -0500 Subject: [PATCH 10/12] fix(cli): use is_remote_execution_enabled() not memory_backend==CPU memory_backend_t::CPU fires on any CPU-only host even when CUOPT_REMOTE_HOST is not set, incorrectly routing local solves through the gRPC client path. is_remote_execution_enabled() checks CUOPT_REMOTE_HOST + CUOPT_REMOTE_PORT and is the correct guard. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/cuopt_cli.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index 992c7f455..2374fe758 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -176,7 +176,7 @@ int run_single_file(const std::string& file_path, } try { - if (memory_backend == cuopt::mathematical_optimization::memory_backend_t::CPU) { + if (cuopt::mathematical_optimization::is_remote_execution_enabled()) { // Remote execution: problem_interface holds a cpu_optimization_problem_t. // Call solve_lp/mip_remote directly so libcuopt_grpc.so is a real DT_NEEDED // dependency of this binary rather than an implicit runtime lookup. From 8511bd039dba987c7fe40c8f4276055c30ed8ebf Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Tue, 28 Jul 2026 14:19:08 -0500 Subject: [PATCH 11/12] style: apply clang-format to cuopt_cli.cpp Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/cuopt_cli.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index 153ee5938..f2ee18980 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -200,16 +200,15 @@ int run_single_file(const std::string& file_path, // Remote execution: problem_interface holds a cpu_optimization_problem_t. // Call solve_lp/mip_remote directly so libcuopt_grpc.so is a real DT_NEEDED // dependency of this binary rather than an implicit runtime lookup. - auto* cpu_prob = static_cast*>(problem_interface.get()); + auto* cpu_prob = + static_cast*>( + problem_interface.get()); if (is_mip) { auto& mip_settings = settings.get_mip_settings(); - auto solution = - cuopt::mathematical_optimization::solve_mip_remote(*cpu_prob, mip_settings); + auto solution = cuopt::mathematical_optimization::solve_mip_remote(*cpu_prob, mip_settings); } else { auto& lp_settings = settings.get_pdlp_settings(); - auto solution = - cuopt::mathematical_optimization::solve_lp_remote(*cpu_prob, lp_settings); + auto solution = cuopt::mathematical_optimization::solve_lp_remote(*cpu_prob, lp_settings); } } else if (is_mip) { auto& mip_settings = settings.get_mip_settings(); From f2b22e7d8868f031cd8b0a44cad2d774942f117a Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Tue, 28 Jul 2026 15:00:58 -0500 Subject: [PATCH 12/12] fix(build): link nccl_external into cuopt_lp distributed_pdlp files (multi_gpu_engine.cu, distributed_algorithms.cu) use NCCL APIs and are compiled into cuopt_lp. After the library split, cuopt_lp must declare its own NCCL dependency rather than inheriting it from the monolithic cuopt_static target. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Ramakrishna Prabhu --- cpp/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 1ab920cce..fbd8646f3 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -677,6 +677,7 @@ target_link_libraries(cuopt_lp ${CUOPT_PRIVATE_CUDA_LIBS} OpenMP::OpenMP_CUDA simde::simde + nccl_external ) target_link_libraries(cuopt_lp PRIVATE $) add_dependencies(cuopt_lp PSLP)