CMakeLists.txt 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. # ----------------------------------------------------------------------------
  2. # CMake file for Matlab/Octave support
  3. #
  4. # Matlab code generation and compilation is broken down into two distinct
  5. # stages: configure time and build time. The idea is that we want to give
  6. # the user reasonable guarantees that once they type 'make', wrapper
  7. # generation is unlikely to fail. Therefore we run a series of tests at
  8. # configure time to check the working status of the core components.
  9. #
  10. # Configure Time
  11. # During configure time, the script attempts to ascertain whether the
  12. # generator and mex compiler are working for a given architecture.
  13. # Currently this involves:
  14. # 1) Generating a simple CV_EXPORTS_W symbol and checking whether a file
  15. # of the symbol name is generated
  16. # 2) Compiling a simple mex gateway to check that Bridge.hpp and mex.h
  17. # can be found, and that a file with the mexext is produced
  18. #
  19. # Build Time
  20. # If the configure time tests pass, then we assume Matlab wrapper generation
  21. # will not fail during build time. We simply glob all of the symbols in
  22. # the OpenCV module headers, generate intermediate .cpp files, then compile
  23. # them with mex.
  24. # ----------------------------------------------------------------------------
  25. # ----------------------------------------------------------------------------
  26. # Architecture checks
  27. # ----------------------------------------------------------------------------
  28. # make sure we're on a supported architecture with Matlab and Python (with jinja2) installed
  29. if(APPLE_FRAMEWORK OR ANDROID OR NOT MATLAB_FOUND)
  30. ocv_module_disable(matlab)
  31. elseif(NOT PYTHON_DEFAULT_AVAILABLE)
  32. message(WARNING "A required dependency of the matlab module (Python) was not found. Disabling Matlab bindings...")
  33. ocv_module_disable(matlab)
  34. endif()
  35. if(NOT DEFINED HAVE_PYTHON_JINJA2)
  36. # Bindings generator requires Jinja2 python package
  37. execute_process(COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" -c "import jinja2; print(jinja2.__version__)"
  38. RESULT_VARIABLE _result
  39. OUTPUT_VARIABLE _jinja2_version
  40. OUTPUT_STRIP_TRAILING_WHITESPACE)
  41. if(NOT _result EQUAL 0)
  42. set(HAVE_PYTHON_JINJA2 0 CACHE INTERNAL "")
  43. else()
  44. message(STATUS "Python Jinja version: ${_jinja2_version}")
  45. set(HAVE_PYTHON_JINJA2 1 CACHE INTERNAL "")
  46. endif()
  47. endif()
  48. if(NOT HAVE_PYTHON_JINJA2)
  49. message(WARNING "A required dependency of the matlab module (Python Jinja2 package) was not found (installation command: \"pip install jinja2\"). Disabling Matlab bindings...")
  50. ocv_module_disable(matlab)
  51. endif()
  52. # PREPEND
  53. # Given a list of strings IN and a TOKEN, prepend the token to each string
  54. # and append to OUT. This is used for passing command line "-I", "-L" and "-l"
  55. # arguments to mex. e.g.
  56. # prepend("-I" OUT /path/to/include/dir) --> -I/path/to/include/dir
  57. macro(PREPEND TOKEN OUT IN)
  58. foreach(VAR ${IN} ${ARGN})
  59. list(APPEND ${OUT} "${TOKEN}${VAR}")
  60. endforeach()
  61. endmacro()
  62. # WARN_MIXED_PRECISION
  63. # Formats a warning message if the compiler and Matlab bitness is different
  64. macro(WARN_MIXED_PRECISION COMPILER_BITNESS MATLAB_BITNESS)
  65. set(MSG "Your compiler is ${COMPILER_BITNESS}-bit")
  66. set(MSG "${MSG} but your version of Matlab is ${MATLAB_BITNESS}-bit.")
  67. set(MSG "${MSG} To build Matlab bindings, please switch to a ${MATLAB_BITNESS}-bit compiler.")
  68. message(WARNING ${MSG})
  69. endmacro()
  70. ocv_assert(DEFINED MATLAB_ARCH)
  71. ocv_assert(DEFINED MATLAB_MEX_SCRIPT)
  72. ocv_assert(DEFINED MATLAB_MEXEXT)
  73. # If the user built OpenCV as X-bit, but they have a Y-bit version of Matlab,
  74. # attempting to link to OpenCV during binding generation will fail, since
  75. # mixed precision pointers are not allowed. Disable the bindings.
  76. math(EXPR ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
  77. if (${ARCH} EQUAL 32 AND ${MATLAB_ARCH} MATCHES "64")
  78. warn_mixed_precision("32" "64")
  79. ocv_module_disable(matlab)
  80. return()
  81. elseif (${ARCH} EQUAL 64 AND NOT ${MATLAB_ARCH} MATCHES "64")
  82. warn_mixed_precision("64" "32")
  83. ocv_module_disable(matlab)
  84. return()
  85. endif()
  86. # If it's MSVC, warn the user that bindings will only be built in Release mode.
  87. # Debug mode seems to cause issues...
  88. if (MSVC)
  89. message(STATUS "Warning: Matlab bindings will only be built in Release configurations")
  90. endif()
  91. # ----------------------------------------------------------------------------
  92. # Configure time components
  93. # ----------------------------------------------------------------------------
  94. set(the_description "The Matlab/Octave bindings")
  95. ocv_add_module(matlab BINDINGS
  96. OPTIONAL opencv_core
  97. opencv_imgproc opencv_ml
  98. opencv_imgcodecs opencv_videoio opencv_highgui
  99. opencv_objdetect opencv_flann opencv_features2d
  100. opencv_photo opencv_video opencv_videostab
  101. opencv_calib opencv_calib3d
  102. opencv_stitching opencv_superres
  103. opencv_xfeatures2d
  104. )
  105. # get the commit information
  106. execute_process(COMMAND git log -1 --pretty=%H OUTPUT_VARIABLE GIT_COMMIT ERROR_QUIET)
  107. string(REGEX REPLACE "(\r?\n)+$" "" GIT_COMMIT "${GIT_COMMIT}")
  108. # set the path to the C++ header and doc parser, and template engine
  109. set(HDR_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/python/src2)
  110. # set mex compiler options
  111. prepend("-I" MEX_INCLUDE_DIRS ${CMAKE_BINARY_DIR})
  112. prepend("-I" MEX_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include)
  113. if (MSVC)
  114. prepend("-L" MEX_LIB_DIR ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR})
  115. else()
  116. prepend("-L" MEX_LIB_DIR ${LIBRARY_OUTPUT_PATH})
  117. endif()
  118. set(MEX_OPTS "-largeArrayDims")
  119. if (BUILD_TESTS)
  120. add_subdirectory(test)
  121. endif()
  122. include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
  123. # intersection of available modules and optional dependencies
  124. # 1. populate the command-line include directories (-I/path/to/module/header, ...)
  125. # 2. populate the command-line link libraries (-lopencv_core, ...) for Debug and Release
  126. set(MATLAB_DEPS ${OPENCV_MODULE_${the_module}_REQ_DEPS} ${OPENCV_MODULE_${the_module}_OPT_DEPS})
  127. foreach(opencv_module ${MATLAB_DEPS})
  128. if (HAVE_${opencv_module})
  129. string(REPLACE "opencv_" "" module ${opencv_module})
  130. list(APPEND opencv_modules ${module})
  131. list(APPEND ${the_module}_ACTUAL_DEPS ${opencv_module})
  132. prepend("-I" MEX_INCLUDE_DIRS "${OPENCV_MODULE_${opencv_module}_LOCATION}/include")
  133. prepend("-l" MEX_LIBS ${opencv_module}${OPENCV_DLLVERSION})
  134. prepend("-l" MEX_DEBUG_LIBS ${opencv_module}${OPENCV_DLLVERSION}${OPENCV_DEBUG_POSTFIX})
  135. endif()
  136. endforeach()
  137. # add extra headers by hand
  138. list(APPEND opencv_extra_hdrs "core=${OPENCV_MODULE_opencv_core_LOCATION}/include/opencv2/core/base.hpp")
  139. list(APPEND opencv_extra_hdrs "video=${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/tracking.hpp")
  140. # pass the OPENCV_CXX_EXTRA_FLAGS through to the mex compiler
  141. # remove the visibility modifiers, so the mex gateway is visible
  142. # TODO: get mex working without warnings
  143. string(REGEX REPLACE "[^\ ]*visibility[^\ ]*" "" MEX_CXXFLAGS "${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_CXX_FLAGS}")
  144. # Configure checks
  145. # Check to see whether the generator and the mex compiler are working.
  146. # The checks currently test:
  147. # - whether the python generator can be found
  148. # - whether the python generator correctly outputs a file for a definition
  149. # - whether the mex compiler can find the required headers
  150. # - whether the mex compiler can compile a trivial definition
  151. if (NOT MEX_WORKS)
  152. # attempt to generate a gateway for a function
  153. message(STATUS "Trying to generate Matlab code")
  154. execute_process(
  155. COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
  156. ${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
  157. --hdrparser ${HDR_PARSER_PATH}
  158. --extra "test=${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp"
  159. --outdir ${CMAKE_BINARY_DIR}/junk
  160. ERROR_VARIABLE GEN_ERROR
  161. OUTPUT_QUIET
  162. )
  163. if (GEN_ERROR)
  164. message(${GEN_ERROR})
  165. message(STATUS "Error generating Matlab code. Disabling Matlab bindings...")
  166. ocv_module_disable(matlab)
  167. return()
  168. else()
  169. message(STATUS "Trying to generate Matlab code - OK")
  170. endif()
  171. # attempt to compile a gateway using mex
  172. message(STATUS "Trying to compile mex file")
  173. execute_process(
  174. COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} "CXXFLAGS=\$CXXFLAGS ${MEX_CXX_FLAGS}"
  175. ${MEX_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_compiler.cpp
  176. WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/junk
  177. ERROR_VARIABLE MEX_ERROR
  178. OUTPUT_QUIET
  179. )
  180. if (MEX_ERROR)
  181. message(${MEX_ERROR})
  182. message(STATUS "Error compiling mex file. Disabling Matlab bindings...")
  183. ocv_module_disable(matlab)
  184. return()
  185. else()
  186. message(STATUS "Trying to compile mex file - OK")
  187. endif()
  188. endif()
  189. # if we make it here, mex works!
  190. set(MEX_WORKS True CACHE BOOL ADVANCED)
  191. # ----------------------------------------------------------------------------
  192. # Build time components
  193. # ----------------------------------------------------------------------------
  194. # proxies
  195. # these proxies are used to trigger the add_custom_commands
  196. # (which do the real work) only when they're outdated
  197. set(GENERATE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/generate.proxy)
  198. set(COMPILE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/compile.proxy)
  199. # TODO: Remove following line before merging with master
  200. file(REMOVE ${GENERATE_PROXY} ${COMPILE_PROXY})
  201. # generate
  202. # call the python executable to generate the Matlab gateways
  203. add_custom_command(
  204. OUTPUT ${GENERATE_PROXY}
  205. COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
  206. ${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
  207. --hdrparser ${HDR_PARSER_PATH}
  208. --moduleroot ${CMAKE_SOURCE_DIR}/modules ${OPENCV_EXTRA_MODULES_PATH}
  209. --modules ${opencv_modules}
  210. --extra ${opencv_extra_hdrs}
  211. --outdir ${CMAKE_CURRENT_BINARY_DIR}
  212. COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
  213. ${CMAKE_CURRENT_SOURCE_DIR}/generator/build_info.py
  214. --os ${CMAKE_SYSTEM}
  215. --arch ${ARCH} ${CMAKE_SYSTEM_PROCESSOR}
  216. --compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
  217. --mex_arch ${MATLAB_ARCH}
  218. --mex_script ${MATLAB_MEX_SCRIPT}
  219. --cxx_flags ${MEX_CXXFLAGS}
  220. --opencv_version ${OPENCV_VERSION}
  221. --commit ${GIT_COMMIT}
  222. --modules ${opencv_modules}
  223. --configuration $<CONFIGURATION>
  224. --outdir ${CMAKE_CURRENT_BINARY_DIR}
  225. COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
  226. ${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
  227. --opts="${MEX_OPTS}"
  228. --include_dirs="${MEX_INCLUDE_DIRS}"
  229. --lib_dir="${MEX_LIB_DIR}"
  230. --libs="${MEX_LIBS}"
  231. --flags ${MEX_CXXFLAGS}
  232. --outdir ${CMAKE_CURRENT_BINARY_DIR}
  233. COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test/help.m ${CMAKE_CURRENT_BINARY_DIR}/+cv
  234. COMMAND ${CMAKE_COMMAND} -E touch ${GENERATE_PROXY}
  235. COMMENT "Generating Matlab source files"
  236. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/build_info.py"
  237. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/cvmex.py"
  238. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/filters.py"
  239. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/gen_matlab.py"
  240. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/parse_tree.py"
  241. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/templates/functional.cpp"
  242. DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generator/templates/template_function_base.cpp"
  243. )
  244. # compile
  245. # call the mex compiler to compile the gateways
  246. # because we don't know the source files at configure-time, this
  247. # has to be executed in a separate script in cmake's script processing mode
  248. add_custom_command(
  249. OUTPUT ${COMPILE_PROXY}
  250. COMMAND ${CMAKE_COMMAND} -DMATLAB_MEX_SCRIPT=${MATLAB_MEX_SCRIPT}
  251. -DMATLAB_MEXEXT=${MATLAB_MEXEXT}
  252. -DMEX_OPTS=${MEX_OPTS}
  253. -DMEX_CXXFLAGS=${MEX_CXX_FLAGS}
  254. -DMEX_INCLUDE_DIRS="${MEX_INCLUDE_DIRS}"
  255. -DMEX_LIB_DIR="${MEX_LIB_DIR}"
  256. -DCONFIGURATION="$<CONFIGURATION>"
  257. -DMEX_LIBS="${MEX_LIBS}"
  258. -DMEX_DEBUG_LIBS="${MEX_DEBUG_LIBS}"
  259. -P ${CMAKE_CURRENT_SOURCE_DIR}/compile.cmake
  260. COMMAND ${CMAKE_COMMAND} -E touch ${COMPILE_PROXY}
  261. COMMENT "Compiling Matlab source files. This could take a while..."
  262. )
  263. # targets
  264. # opencv_matlab_sources --> opencv_matlab
  265. add_custom_target(${the_module}_sources ALL DEPENDS ${GENERATE_PROXY})
  266. add_custom_target(${the_module} ALL DEPENDS ${COMPILE_PROXY})
  267. add_dependencies(${the_module} ${the_module}_sources ${${the_module}_ACTUAL_DEPS})
  268. if (ENABLE_SOLUTION_FOLDERS)
  269. set_target_properties(${the_module} PROPERTIES FOLDER "modules")
  270. endif()
  271. # ----------------------------------------------------------------------------
  272. # Install time components
  273. # ----------------------------------------------------------------------------
  274. # NOTE: Trailing slashes on the DIRECTORY paths are important!
  275. # TODO: What needs to be done with rpath????
  276. # install the +cv directory verbatim
  277. install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${OPENCV_INCLUDE_INSTALL_PATH})
  278. install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/+cv/ DESTINATION matlab/+cv)
  279. install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cv.m DESTINATION matlab)
  280. # update the custom mex compiler to point to the install locations
  281. string(REPLACE ";" "\\ " MEX_OPTS "${MEX_OPTS}")
  282. string(REPLACE ";" "\\ " MEX_LIBS "${MEX_LIBS}")
  283. string(REPLACE " " "\\ " MEX_CXXFLAGS ${MEX_CXXFLAGS})
  284. string(REPLACE ";" "\\ " MEX_INCLUDE_DIRS "${MEX_INCLUDE_DIRS}")
  285. install(CODE
  286. "execute_process(
  287. COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
  288. ${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
  289. --opts=${MEX_OPTS}
  290. --include_dirs=-I${CMAKE_INSTALL_PREFIX}/${OPENCV_INCLUDE_INSTALL_PATH}
  291. --lib_dir=-L${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}
  292. --libs=${MEX_LIBS}
  293. --flags=${MEX_CXXFLAGS}
  294. --outdir ${CMAKE_INSTALL_PREFIX}/matlab
  295. )"
  296. )