From 098da14f27d76a16f8cb79755ab1df005119d409 Mon Sep 17 00:00:00 2001 From: Donato Meoli Date: Mon, 19 Oct 2026 02:58:17 +0200 Subject: [PATCH] Install the library and a CMake package cmake --install now installs the headers, the shared and the static library and a package (ClarabelConfig.cmake and its version file) that defines the imported targets Clarabel::clarabel_c and Clarabel::clarabel_c_static, so that another project can use an installed Clarabel.cpp with find_package(Clarabel). The same names are aliases of the two interface targets when Clarabel.cpp is added with add_subdirectory. The cargo target is built by default, since the examples, which were the only targets depending on it, can now be left out with CLARABEL_BUILD_EXAMPLES=OFF. The compile definitions of the enabled features are passed on to the installed targets. The static library also needs the system libraries of the Rust standard library: on Linux both libclarabel_c_static and the installed static target now link them, while before any executable linked to libclarabel_c_static failed with undefined references to log, exp and the like. The shared library has no SONAME, so the installed target is marked IMPORTED_NO_SONAME, and executables record libclarabel_c.so rather than the absolute path of the library. --- CMakeLists.txt | 38 +++++++++++++++++- README.md | 17 ++++++++ cmake/ClarabelConfig.cmake.in | 74 +++++++++++++++++++++++++++++++++++ rust_wrapper/CMakeLists.txt | 27 ++++++++++++- 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 cmake/ClarabelConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ae42f5..9483f0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,10 @@ endif() add_subdirectory(rust_wrapper) # Add other subdirectories -add_subdirectory(examples) +option(CLARABEL_BUILD_EXAMPLES "Build the examples of Clarabel.cpp" true) +if(CLARABEL_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() # Add tests option(CLARABEL_BUILD_TESTS "Build the unit tests for Clarabel.cpp" false) @@ -64,3 +67,36 @@ if(CLARABEL_BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() + +#---------------------------------------------- +# Installation +#---------------------------------------------- +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +set(CLARABEL_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/Clarabel" + CACHE STRING "Installation directory of the CMake package files") + +install(DIRECTORY "${CLARABEL_ROOT_DIR}/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +if(WIN32) + install(FILES "${CLARABEL_C_OUTPUT_DIR}/clarabel_c.dll" + DESTINATION "${CMAKE_INSTALL_BINDIR}") +endif() +install(FILES "${LIBCLARABEL_C_SHARED_PATH}" "${LIBCLARABEL_C_STATIC_PATH}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}") + +configure_package_config_file( + "${CLARABEL_ROOT_DIR}/cmake/ClarabelConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ClarabelConfig.cmake" + INSTALL_DESTINATION "${CLARABEL_INSTALL_CMAKEDIR}" + PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_BINDIR) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/ClarabelConfigVersion.cmake" + VERSION ${CLARABEL_PROJECT_VERSION} + COMPATIBILITY SameMinorVersion) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/ClarabelConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/ClarabelConfigVersion.cmake" + DESTINATION "${CLARABEL_INSTALL_CMAKEDIR}") diff --git a/README.md b/README.md index efd49d0..4988aba 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,23 @@ where `VCPKG_TOOLCHAIN_PATH` is the path to the vcpkg toolchain file. - For 32-bit platforms, use `x86-windows` instead of `x64-windows`. +## Installing the solver + +```sh +cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= +cmake --build . +cmake --install . +``` + +installs the headers, the shared and the static library and a CMake package, which another project uses with + +```cmake +find_package(Clarabel CONFIG REQUIRED) +target_link_libraries(my_target PRIVATE Clarabel::clarabel_c) # or Clarabel::clarabel_c_static +``` + +The same two targets are available when Clarabel.cpp is added with `add_subdirectory`. The examples are not built with `-DCLARABEL_BUILD_EXAMPLES=OFF`. + ## Optional solver features Clarabel.rs supports a variety of build options for semidefinite program (SDP) support, JSON file read/write, 3rd party linear solvers etc. Feature options can be passed to cargo via CMake using `-DCLARABEL_CARGO_FEATURES = "feature1,feature2,..."`. diff --git a/cmake/ClarabelConfig.cmake.in b/cmake/ClarabelConfig.cmake.in new file mode 100644 index 0000000..b4549ad --- /dev/null +++ b/cmake/ClarabelConfig.cmake.in @@ -0,0 +1,74 @@ +# CMake package of Clarabel.cpp, which defines the imported targets +# +# Clarabel::clarabel_c the shared library +# Clarabel::clarabel_c_static the static library +# +# both with the C headers (clarabel.h) and the C++ ones (clarabel.hpp), the +# latter needing Eigen. + +@PACKAGE_INIT@ + +# before the dependencies, whose own package files redefine PACKAGE_PREFIX_DIR +set(_clarabel_includedir "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@") +set(_clarabel_libdir "@PACKAGE_CMAKE_INSTALL_LIBDIR@") +set(_clarabel_bindir "@PACKAGE_CMAKE_INSTALL_BINDIR@") +set(_clarabel_definitions "@CLARABEL_C_DEFINITIONS@") + +include(CMakeFindDependencyMacro) +find_dependency(Threads) +find_package(Eigen3 3.4 CONFIG QUIET) + +if(NOT TARGET Clarabel::clarabel_c) + add_library(Clarabel::clarabel_c SHARED IMPORTED) + if(WIN32) + set_target_properties(Clarabel::clarabel_c PROPERTIES + IMPORTED_LOCATION "${_clarabel_bindir}/clarabel_c.dll" + IMPORTED_IMPLIB "${_clarabel_libdir}/clarabel_c.dll.lib") + elseif(APPLE) + set_target_properties(Clarabel::clarabel_c PROPERTIES + IMPORTED_LOCATION "${_clarabel_libdir}/libclarabel_c.dylib") + else() + # the library has no SONAME, so that it is linked by name rather than + # by its path, which would otherwise be recorded in the executables + set_target_properties(Clarabel::clarabel_c PROPERTIES + IMPORTED_LOCATION "${_clarabel_libdir}/libclarabel_c.so" + IMPORTED_NO_SONAME TRUE) + endif() +endif() + +if(NOT TARGET Clarabel::clarabel_c_static) + add_library(Clarabel::clarabel_c_static STATIC IMPORTED) + if(WIN32) + set_target_properties(Clarabel::clarabel_c_static PROPERTIES + IMPORTED_LOCATION "${_clarabel_libdir}/clarabel_c.lib") + else() + set_target_properties(Clarabel::clarabel_c_static PROPERTIES + IMPORTED_LOCATION "${_clarabel_libdir}/libclarabel_c.a") + endif() + # the system libraries needed by the Rust standard library + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_property(TARGET Clarabel::clarabel_c_static APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Threads::Threads ${CMAKE_DL_LIBS} m rt util) + endif() +endif() + +foreach(_clarabel_target Clarabel::clarabel_c Clarabel::clarabel_c_static) + set_property(TARGET ${_clarabel_target} APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${_clarabel_includedir}") + if(_clarabel_definitions) + set_property(TARGET ${_clarabel_target} APPEND PROPERTY + INTERFACE_COMPILE_DEFINITIONS ${_clarabel_definitions}) + endif() + if(TARGET Eigen3::Eigen) + set_property(TARGET ${_clarabel_target} APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Eigen3::Eigen) + endif() +endforeach() + +unset(_clarabel_target) +unset(_clarabel_includedir) +unset(_clarabel_libdir) +unset(_clarabel_bindir) +unset(_clarabel_definitions) + +check_required_components(Clarabel) diff --git a/rust_wrapper/CMakeLists.txt b/rust_wrapper/CMakeLists.txt index 7cd7671..f1af01d 100644 --- a/rust_wrapper/CMakeLists.txt +++ b/rust_wrapper/CMakeLists.txt @@ -18,6 +18,10 @@ endif() set(CLARABEL_C_OUTPUT_DIR ${clarabel_c_output_directory} PARENT_SCOPE) +# The compile definitions of the enabled features, which are also given to +# the targets of the installed package +set(clarabel_c_definitions "") + if(NOT DEFINED CLARABEL_CARGO_FEATURES) set(CLARABEL_CARGO_FEATURES "") endif() @@ -111,35 +115,41 @@ if(CONFIG_SDP) # Define the FEATURE_SDP flag for all targets that link against clarabel_c target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_SDP) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_SDP) + list(APPEND clarabel_c_definitions FEATURE_SDP) endif() rust_feature_is_enabled("faer-sparse" CONFIG_FAER_SPARSE) if(CONFIG_FAER_SPARSE) target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_FAER_SPARSE) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_FAER_SPARSE) + list(APPEND clarabel_c_definitions FEATURE_FAER_SPARSE) endif() rust_feature_is_enabled("pardiso-mkl" CONFIG_PARDISO_MKL) if(CONFIG_PARDISO_MKL) target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_PARDISO_MKL) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_PARDISO_MKL) + list(APPEND clarabel_c_definitions FEATURE_PARDISO_MKL) endif() rust_feature_is_enabled("pardiso-panua" CONFIG_PARDISO_PANUA) if(CONFIG_PARDISO_PANUA) target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_PARDISO_PANUA) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_PARDISO_PANUA) + list(APPEND clarabel_c_definitions FEATURE_PARDISO_PANUA) endif() if(CONFIG_PARDISO_MKL OR CONFIG_PARDISO_PANUA) target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_PARDISO_ANY) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_PARDISO_ANY) + list(APPEND clarabel_c_definitions FEATURE_PARDISO_ANY) endif() rust_feature_is_enabled("serde" CONFIG_SERDE) if(CONFIG_SERDE) target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_SERDE) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_SERDE) + list(APPEND clarabel_c_definitions FEATURE_SERDE) endif() # replace each rust with clarabel/ so that they pass through @@ -178,10 +188,14 @@ elseif(WIN32) set(LIBCLARABEL_C_STATIC_PATH "${clarabel_c_output_directory}/clarabel_c.lib") endif() +set(LIBCLARABEL_C_SHARED_PATH "${LIBCLARABEL_C_SHARED_PATH}" PARENT_SCOPE) +set(LIBCLARABEL_C_STATIC_PATH "${LIBCLARABEL_C_STATIC_PATH}" PARENT_SCOPE) +set(CLARABEL_C_DEFINITIONS "${clarabel_c_definitions}" PARENT_SCOPE) + # Add the cargo project as a custom target add_custom_target( - libclarabel_c + libclarabel_c ALL WORKING_DIRECTORY ${CLARABEL_ROOT_DIR}/rust_wrapper # Commands for building the Rust library COMMAND cargo build ${clarabel_c_build_flags} @@ -202,8 +216,19 @@ add_custom_target( target_link_libraries(libclarabel_c_static INTERFACE ${LIBCLARABEL_C_STATIC_PATH}) target_include_directories(libclarabel_c_static INTERFACE ${CLARABEL_ROOT_DIR}/include) add_dependencies(libclarabel_c_static libclarabel_c) +# the system libraries needed by the Rust standard library +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_package(Threads REQUIRED) + target_link_libraries(libclarabel_c_static INTERFACE + Threads::Threads ${CMAKE_DL_LIBS} m rt util) +endif() # Shared library target_link_libraries(libclarabel_c_shared INTERFACE ${LIBCLARABEL_C_SHARED_PATH}) target_include_directories(libclarabel_c_shared INTERFACE ${CLARABEL_ROOT_DIR}/include) add_dependencies(libclarabel_c_shared libclarabel_c) + +# The names of the targets of the installed package, also when Clarabel.cpp +# is consumed via `add_subdirectory` +add_library(Clarabel::clarabel_c ALIAS libclarabel_c_shared) +add_library(Clarabel::clarabel_c_static ALIAS libclarabel_c_static)