Austin Schuh | 9049e20 | 2022-02-20 17:34:16 -0800 | [diff] [blame^] | 1 | # Minimum version required |
| 2 | cmake_minimum_required (VERSION 3.2) |
| 3 | |
| 4 | # Project name |
| 5 | project (osqp) |
| 6 | |
| 7 | set(OSQP_VERSION "0.0.0" CACHE STRING "The version number of OSQP") |
| 8 | if(NOT OSQP_VERSION STREQUAL "0.0.0") |
| 9 | configure_file ( |
| 10 | "${PROJECT_SOURCE_DIR}/configure/version.h.in" |
| 11 | "${PROJECT_SOURCE_DIR}/include/version.h" |
| 12 | ) |
| 13 | endif() |
| 14 | |
| 15 | # Export compile commands |
| 16 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) |
| 17 | |
| 18 | # Set the output folder where your program will be created |
| 19 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/out) |
| 20 | set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/out) |
| 21 | |
| 22 | # Some non-standard CMake modules |
| 23 | LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/configure/cmake) |
| 24 | INCLUDE(FindPythonModule) |
| 25 | INCLUDE(Utils) |
| 26 | # include(FindMKL) # Find MKL module |
| 27 | |
| 28 | |
| 29 | # Detect operating system |
| 30 | # ---------------------------------------------- |
| 31 | message(STATUS "We are on a ${CMAKE_SYSTEM_NAME} system") |
| 32 | if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 33 | set(IS_LINUX ON) |
| 34 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") |
| 35 | set(IS_MAC ON) |
| 36 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") |
| 37 | set(IS_WINDOWS ON) |
| 38 | endif() |
| 39 | |
| 40 | |
| 41 | |
| 42 | # Set options |
| 43 | # ---------------------------------------------- |
| 44 | |
| 45 | # Are unittests generated? |
| 46 | option (UNITTESTS "Enable unittests generation" OFF) |
| 47 | |
| 48 | # Is the code generated for embedded platforms? |
| 49 | # 1 : Yes. Matrix update not allowed. |
| 50 | # 2 : Yes. Matrix update allowed. |
| 51 | if (NOT DEFINED EMBEDDED) |
| 52 | message(STATUS "Embedded is OFF") |
| 53 | else() |
| 54 | message(STATUS "Embedded is ${EMBEDDED}") |
| 55 | endif() |
| 56 | |
| 57 | # Is printing enabled? |
| 58 | option (PRINTING "Enable solver printing" ON) |
| 59 | if (DEFINED EMBEDDED) |
| 60 | message(STATUS "Disabling printing for embedded") |
| 61 | set(PRINTING OFF) |
| 62 | endif() |
| 63 | message(STATUS "Printing is ${PRINTING}") |
| 64 | |
| 65 | |
| 66 | # Is profiling enabled? |
| 67 | option (PROFILING "Enable solver profiling (timing)" ON) |
| 68 | if (DEFINED EMBEDDED) |
| 69 | message(STATUS "Disabling profiling for embedded") |
| 70 | set(PROFILING OFF) |
| 71 | endif() |
| 72 | message(STATUS "Profiling is ${PROFILING}") |
| 73 | |
| 74 | # Is user interrupt enabled? |
| 75 | option (CTRLC "Enable user interrupt (Ctrl-C)" ON) |
| 76 | if (DEFINED EMBEDDED) |
| 77 | message(STATUS "Disabling user interrupt for embedded") |
| 78 | set(CTRLC OFF) |
| 79 | endif() |
| 80 | message(STATUS "User interrupt is ${CTRLC}") |
| 81 | |
| 82 | # Use floats instead of integers |
| 83 | option (DFLOAT "Use float numbers instead of doubles" OFF) |
| 84 | message(STATUS "Floats are ${DFLOAT}") |
| 85 | |
| 86 | # Use long integers for indexing |
| 87 | option (DLONG "Use long integers (64bit) for indexing" ON) |
| 88 | if (NOT (CMAKE_SIZEOF_VOID_P EQUAL 8)) |
| 89 | message(STATUS "Disabling long integers (64bit) on 32bit machine") |
| 90 | set(DLONG OFF) |
| 91 | endif() |
| 92 | message(STATUS "Long integers (64bit) are ${DLONG}") |
| 93 | |
| 94 | |
| 95 | option (DEBUG "Debug mode" OFF) |
| 96 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
| 97 | set (DEBUG ON) |
| 98 | message(STATUS "Debug mode is ${DEBUG}") |
| 99 | endif() |
| 100 | |
| 101 | # Add code coverage |
| 102 | option (COVERAGE "Perform code coverage" OFF) |
| 103 | message(STATUS "Code coverage is ${COVERAGE}") |
| 104 | |
| 105 | |
| 106 | # Memory allocators |
| 107 | # ---------------------------------------------- |
| 108 | |
| 109 | #Report on custom user header options. This is intended to allow |
| 110 | #users to provide definitions of their own memory functions |
| 111 | # The header should define the functions as follows |
| 112 | # |
| 113 | # define c_malloc mymalloc |
| 114 | # define c_calloc mycalloc |
| 115 | # define c_realloc myrealloc |
| 116 | # define c_free myfree |
| 117 | |
| 118 | if(OSQP_CUSTOM_MEMORY) |
| 119 | message(STATUS "User custom memory management header: ${OSQP_CUSTOM_MEMORY}") |
| 120 | endif() |
| 121 | |
| 122 | |
| 123 | |
| 124 | # Linear solvers dependencies |
| 125 | # --------------------------------------------- |
| 126 | option (ENABLE_MKL_PARDISO "Enable MKL Pardiso solver" ON) |
| 127 | if (DFLOAT) |
| 128 | message(STATUS "Disabling MKL Pardiso Solver with floats") |
| 129 | set(ENABLE_MKL_PARDISO OFF) |
| 130 | elseif(DEFINED EMBEDDED) |
| 131 | message(STATUS "Disabling MKL Pardiso Solver for embedded") |
| 132 | set(ENABLE_MKL_PARDISO OFF) |
| 133 | endif() |
| 134 | message(STATUS "MKL Pardiso: ${ENABLE_MKL_PARDISO}") |
| 135 | |
| 136 | |
| 137 | # Generate header file with the global options |
| 138 | # --------------------------------------------- |
| 139 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure/osqp_configure.h.in |
| 140 | ${CMAKE_CURRENT_SOURCE_DIR}/include/osqp_configure.h |
| 141 | NEWLINE_STYLE LF) |
| 142 | |
| 143 | # Set Compiler flags |
| 144 | # ---------------------------------------------- |
| 145 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) # -fPIC |
| 146 | |
| 147 | |
| 148 | if (NOT MSVC) |
| 149 | |
| 150 | if (COVERAGE) |
| 151 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") |
| 152 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") |
| 153 | if(FORTRAN) |
| 154 | set(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS} --coverage") |
| 155 | endif(FORTRAN) |
| 156 | endif() |
| 157 | |
| 158 | if (DEBUG) |
| 159 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g") |
| 160 | else() |
| 161 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") |
| 162 | endif() |
| 163 | |
| 164 | set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lm") # Include math |
| 165 | # Include real time library in linux |
| 166 | if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 167 | set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lrt -ldl") |
| 168 | endif() |
| 169 | endif (NOT MSVC) |
| 170 | |
| 171 | # Set sources and includes |
| 172 | # ---------------------------------------------- |
| 173 | add_subdirectory (src) |
| 174 | add_subdirectory (include) |
| 175 | |
| 176 | |
| 177 | # if we are building the Python interface, let's look for Python |
| 178 | # and set some options |
| 179 | # ----------------------------------------------------------------- |
| 180 | if (PYTHON) |
| 181 | |
| 182 | # Python include directories need to be passed by the python compilation process |
| 183 | if (NOT PYTHON_INCLUDE_DIRS) |
| 184 | message( FATAL_ERROR "You need Python include directories to build the Python interface" ) |
| 185 | endif (NOT PYTHON_INCLUDE_DIRS) |
| 186 | |
| 187 | # Include directories for Python headers |
| 188 | include_directories(${PYTHON_INCLUDE_DIRS}) |
| 189 | |
| 190 | # Pass PYTHON flag to C compiler |
| 191 | add_definitions(-DPYTHON) |
| 192 | |
| 193 | if (UNITTESTS) |
| 194 | # Disable unittests |
| 195 | message(STATUS "Disabling UNITTESTS because we are building Python interface") |
| 196 | set(UNITTESTS OFF) |
| 197 | endif (UNITTESTS) |
| 198 | |
| 199 | endif (PYTHON) |
| 200 | |
| 201 | |
| 202 | # if we are building the Matlab interface, let's look for Matlab |
| 203 | # and set some options |
| 204 | # ----------------------------------------------------------------- |
| 205 | if (MATLAB) |
| 206 | |
| 207 | find_package(Matlab) |
| 208 | |
| 209 | if (NOT Matlab_FOUND) |
| 210 | message( FATAL_ERROR "You need Matlab libraries to build the Matlab interface" ) |
| 211 | endif (NOT Matlab_FOUND) |
| 212 | |
| 213 | # Include directories for Matlab headers |
| 214 | include_directories(${Matlab_INCLUDE_DIRS}) |
| 215 | |
| 216 | message(STATUS "Matlab root is " ${Matlab_ROOT_DIR}) |
| 217 | |
| 218 | # Pass MATLAB flag to C compiler |
| 219 | add_definitions(-DMATLAB) |
| 220 | |
| 221 | # Insist on the pre 2018 complex data API |
| 222 | # so that mxGetPr will work correctly |
| 223 | add_definitions(-DMATLAB_MEXSRC_RELEASE=R2017b) |
| 224 | |
| 225 | message(STATUS "Using Matlab pre-2018a API for mxGetPr compatibility") |
| 226 | |
| 227 | if (UNITTESTS) |
| 228 | # Disable unittests |
| 229 | message(STATUS "Disabling UNITTESTS because we are building Matlab interface") |
| 230 | set(UNITTESTS OFF) |
| 231 | endif (UNITTESTS) |
| 232 | |
| 233 | endif (MATLAB) |
| 234 | |
| 235 | # if we are building the R interface, let's look for R |
| 236 | # and set some options |
| 237 | # ----------------------------------------------------------------- |
| 238 | if (R_LANG) |
| 239 | |
| 240 | message(STATUS "We are building the R interface") |
| 241 | |
| 242 | # Look for R libraries |
| 243 | find_package(R) |
| 244 | |
| 245 | if (NOT R_FOUND) |
| 246 | message( FATAL_ERROR "You need R libraries to build the R interface" ) |
| 247 | endif (NOT R_FOUND) |
| 248 | |
| 249 | message(STATUS "R exec is: " ${R_EXEC}) |
| 250 | message(STATUS "R root dir is: " ${R_ROOT_DIR}) |
| 251 | message(STATUS "R includes are in: " ${R_INCLUDE_DIRS}) |
| 252 | |
| 253 | # Include directories for R headers |
| 254 | include_directories(${R_INCLUDE_DIRS}) |
| 255 | |
| 256 | # Pass R_LANG flag to C compiler |
| 257 | add_definitions(-DR_LANG) |
| 258 | |
| 259 | if (UNITTESTS) |
| 260 | # Disable unittests |
| 261 | message(STATUS "Disabling UNITTESTS because we are building the R interface") |
| 262 | set(UNITTESTS OFF) |
| 263 | endif (UNITTESTS) |
| 264 | |
| 265 | endif (R_LANG) |
| 266 | |
| 267 | |
| 268 | # Create Static Library |
| 269 | # ---------------------------------------------- |
| 270 | |
| 271 | # Add linear system solvers cumulative library |
| 272 | add_subdirectory(lin_sys) |
| 273 | |
| 274 | # Static library |
| 275 | add_library (osqpstatic STATIC ${osqp_src} ${osqp_headers} ${linsys_solvers}) |
| 276 | # Give same name to static library output |
| 277 | set_target_properties(osqpstatic PROPERTIES OUTPUT_NAME osqp) |
| 278 | |
| 279 | # Include directories for linear system solvers |
| 280 | target_include_directories(osqpstatic PRIVATE ${linsys_solvers_includes}) |
| 281 | |
| 282 | # Declare include directories for the cmake exported target |
| 283 | target_include_directories(osqpstatic |
| 284 | PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" |
| 285 | "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}/osqp>") |
| 286 | |
| 287 | # Install Static Library |
| 288 | # ---------------------------------------------- |
| 289 | |
| 290 | include(GNUInstallDirs) |
| 291 | |
| 292 | install(TARGETS osqpstatic |
| 293 | EXPORT ${PROJECT_NAME} |
| 294 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" |
| 295 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" |
| 296 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") |
| 297 | |
| 298 | |
| 299 | # Install Headers |
| 300 | # ---------------------------------------------- |
| 301 | |
| 302 | install(FILES ${osqp_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/osqp") |
| 303 | |
| 304 | |
| 305 | |
| 306 | if (MATLAB) |
| 307 | target_link_libraries (osqpstatic ${Matlab_LIBRARIES}) |
| 308 | endif (MATLAB) |
| 309 | |
| 310 | # If we are building Python/Matlab/R interface: |
| 311 | # - do not build shared library |
| 312 | # - do not build demo |
| 313 | if (NOT PYTHON AND NOT MATLAB AND NOT R_LANG AND NOT EMBEDDED) |
| 314 | # Create osqp shared library |
| 315 | # NB: Add all the linear system solvers here |
| 316 | add_library (osqp SHARED ${osqp_src} ${osqp_headers} ${linsys_solvers}) |
| 317 | |
| 318 | # Include directories for linear system solvers |
| 319 | target_include_directories(osqp PRIVATE ${linsys_solvers_includes}) |
| 320 | |
| 321 | # Declare include directories for the cmake exported target |
| 322 | target_include_directories(osqp |
| 323 | PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" |
| 324 | "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}/osqp>") |
| 325 | |
| 326 | # Install osqp shared library |
| 327 | install(TARGETS osqp |
| 328 | EXPORT ${PROJECT_NAME} |
| 329 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" |
| 330 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" |
| 331 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") |
| 332 | |
| 333 | # Create demo executable (linked to static library) |
| 334 | add_executable (osqp_demo ${PROJECT_SOURCE_DIR}/examples/osqp_demo.c) |
| 335 | target_link_libraries (osqp_demo osqpstatic) |
| 336 | |
| 337 | endif (NOT PYTHON AND NOT MATLAB AND NOT R_LANG AND NOT EMBEDDED) |
| 338 | |
| 339 | # Create CMake packages for the build directory |
| 340 | # ---------------------------------------------- |
| 341 | include(CMakePackageConfigHelpers) |
| 342 | |
| 343 | export(EXPORT ${PROJECT_NAME} |
| 344 | FILE "${CMAKE_CURRENT_BINARY_DIR}/osqp-targets.cmake" |
| 345 | NAMESPACE osqp::) |
| 346 | |
| 347 | if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/osqp-config.cmake) |
| 348 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/osqp-config.cmake "include(\"\${CMAKE_CURRENT_LIST_DIR}/osqp-targets.cmake\")\n") |
| 349 | endif() |
| 350 | |
| 351 | |
| 352 | # Create CMake packages for the install directory |
| 353 | # ---------------------------------------------- |
| 354 | |
| 355 | set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/osqp) |
| 356 | |
| 357 | install(EXPORT ${PROJECT_NAME} |
| 358 | FILE osqp-targets.cmake |
| 359 | NAMESPACE osqp:: |
| 360 | DESTINATION ${ConfigPackageLocation}) |
| 361 | |
| 362 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/osqp-config.cmake |
| 363 | DESTINATION ${ConfigPackageLocation}) |
| 364 | |
| 365 | |
| 366 | |
| 367 | # Add uninstall command |
| 368 | # ---------------------------------------------- |
| 369 | if(NOT TARGET uninstall) |
| 370 | configure_file( |
| 371 | "${CMAKE_CURRENT_SOURCE_DIR}/configure/cmake/cmake_uninstall.cmake.in" |
| 372 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" |
| 373 | IMMEDIATE @ONLY) |
| 374 | |
| 375 | add_custom_target(uninstall |
| 376 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) |
| 377 | endif() |
| 378 | |
| 379 | |
| 380 | |
| 381 | # Add testing |
| 382 | # ---------------------------------------------- |
| 383 | # Add custom command to generate tests |
| 384 | if (UNITTESTS) |
| 385 | find_package(PythonInterp) |
| 386 | if(NOT PYTHONINTERP_FOUND) |
| 387 | message( FATAL_ERROR "You need python installed to generate unittests. If you do not want to compile the unittests pass -DUNITTESTS=OFF to cmake." ) |
| 388 | endif() |
| 389 | |
| 390 | INCLUDE(FindPythonModule) |
| 391 | find_python_module(numpy) |
| 392 | IF(NOT NUMPY_FOUND) |
| 393 | message( FATAL_ERROR "You need numpy python module installed to generate unittests. If you do not want to compile the unittests pass -DUNITTESTS=OFF to cmake." ) |
| 394 | ENDIF() |
| 395 | |
| 396 | find_python_module(scipy) |
| 397 | # Check scipy version for sparse.random functionalities |
| 398 | IF((NOT SCIPY_FOUND) OR (SCIPY_VERSION VERSION_LESS 0.17.0)) |
| 399 | message( FATAL_ERROR "You need scipy python module installed to generate unittests. If you do not want to compile the unittests pass -DUNITTESTS=OFF to cmake." ) |
| 400 | ENDIF() |
| 401 | |
| 402 | find_python_module(__future__) |
| 403 | IF(NOT __FUTURE___FOUND) |
| 404 | message( FATAL_ERROR "You need future python module installed to generate unittests. If you do not want to compile the unittests pass -DUNITTESTS=OFF to cmake." ) |
| 405 | ENDIF() |
| 406 | |
| 407 | # Add test_headers and codegen_test_headers |
| 408 | add_subdirectory(tests) |
| 409 | |
| 410 | # Generating tests.stamp so that the test data are not always generated |
| 411 | # set(data_timestamp ${PROJECT_SOURCE_DIR}/tests/tests_data.stamp) |
| 412 | add_custom_command( |
| 413 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests |
| 414 | COMMAND ${PYTHON_EXECUTABLE} generate_tests_data.py |
| 415 | DEPENDS ${PROJECT_SOURCE_DIR}/tests/generate_tests_data.py |
| 416 | OUTPUT ${codegen_test_headers} |
| 417 | COMMENT "Generating unittests data files using Python" |
| 418 | ) |
| 419 | |
| 420 | # Direct linear solver testing |
| 421 | include_directories(tests) |
| 422 | add_executable(osqp_tester |
| 423 | ${PROJECT_SOURCE_DIR}/tests/osqp_tester.cpp |
| 424 | ${PROJECT_SOURCE_DIR}/tests/osqp_tester.h |
| 425 | ${test_headers} |
| 426 | ${codegen_test_headers} |
| 427 | ) |
| 428 | set_target_properties(osqp_tester |
| 429 | PROPERTIES |
| 430 | CXX_STANDARD 11 |
| 431 | CXX_STANDARD_REQUIRED YES |
| 432 | CXX_EXTENSIONS NO |
| 433 | ) |
| 434 | target_link_libraries (osqp_tester osqpstatic ${CMAKE_DL_LIBS}) |
| 435 | |
| 436 | # Add custom memory target |
| 437 | add_executable(osqp_tester_custom_memory |
| 438 | EXCLUDE_FROM_ALL |
| 439 | ${PROJECT_SOURCE_DIR}/tests/osqp_tester.cpp |
| 440 | ${PROJECT_SOURCE_DIR}/tests/osqp_tester.h |
| 441 | ${test_headers} |
| 442 | ${codegen_test_headers} |
| 443 | ${PROJECT_SOURCE_DIR}/tests/custom_memory/custom_memory.c |
| 444 | ${PROJECT_SOURCE_DIR}/tests/custom_memory/custom_memory.h |
| 445 | ) |
| 446 | target_link_libraries (osqp_tester_custom_memory osqpstatic ${CMAKE_DL_LIBS}) |
| 447 | |
| 448 | # Add testing |
| 449 | include(CTest) |
| 450 | enable_testing() |
| 451 | add_test(NAME tester COMMAND $<TARGET_FILE:osqp_tester>) |
| 452 | endif() |