CMakeLists.txt 14 KB

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