CMakeLists.txt 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # ----------------------------------------------------------------------------
  2. # CMake file for js support
  3. # ----------------------------------------------------------------------------
  4. if(OPENCV_INITIAL_PASS)
  5. # generator for Objective-C source code and documentation signatures
  6. add_subdirectory(generator)
  7. endif()
  8. if(NOT BUILD_opencv_js) # should be enabled explicitly (by build_js.py script)
  9. return()
  10. endif()
  11. set(the_description "The JavaScript(JS) bindings")
  12. set(OPENCV_JS "opencv.js")
  13. set(JS_HELPER "${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.js")
  14. find_path(EMSCRIPTEN_INCLUDE_DIR
  15. emscripten/bind.h
  16. PATHS
  17. ENV EMSCRIPTEN_ROOT
  18. PATH_SUFFIXES system/include include
  19. DOC "Location of Emscripten SDK")
  20. if(NOT EMSCRIPTEN_INCLUDE_DIR OR NOT PYTHON_DEFAULT_AVAILABLE)
  21. set(DISABLE_MSG "Module 'js' disabled because the following dependencies are not found:")
  22. if(NOT EMSCRIPTEN_INCLUDE_DIR)
  23. set(DISABLE_MSG "${DISABLE_MSG} Emscripten")
  24. endif()
  25. if(NOT PYTHON_DEFAULT_AVAILABLE)
  26. set(DISABLE_MSG "${DISABLE_MSG} Python")
  27. endif()
  28. message(STATUS ${DISABLE_MSG})
  29. ocv_module_disable(js)
  30. endif()
  31. # Get Emscripten version from emscripten/version.h
  32. unset(EMSCRIPTEN_VERSION)
  33. unset(EMSCRIPTEN_VERSION_CONTENTS)
  34. unset(EMSCRIPTEN_VERSION_MAJOR)
  35. unset(EMSCRIPTEN_VERSION_MINOR)
  36. unset(EMSCRIPTEN_VERSION_TINY)
  37. set(EMSCRIPTEN_VERSION_PATH "${EMSCRIPTEN_INCLUDE_DIR}/emscripten/version.h")
  38. if(NOT EXISTS "${EMSCRIPTEN_VERSION_PATH}")
  39. message(STATUS "${EMSCRIPTEN_INCLUDE_DIR}/emscripten/version.h is missing")
  40. else()
  41. file(STRINGS "${EMSCRIPTEN_VERSION_PATH}" EMSCRIPTEN_VERSION_CONTENTS REGEX "^#define[ \t]+__EMSCRIPTEN_[a-z]+__[ \t][0-9]+")
  42. if(NOT EMSCRIPTEN_VERSION_CONTENTS)
  43. message(STATUS "${EMSCRIPTEN_INCLUDE_DIR}/emscripten/version.h is exists, but is not readable")
  44. else()
  45. if(EMSCRIPTEN_VERSION_CONTENTS MATCHES "__EMSCRIPTEN_major__[ \t]+([0-9]+)")
  46. set(EMSCRIPTEN_VERSION_MAJOR "${CMAKE_MATCH_1}")
  47. endif()
  48. if(EMSCRIPTEN_VERSION_CONTENTS MATCHES "__EMSCRIPTEN_minor__[ \t]+([0-9]+)")
  49. set(EMSCRIPTEN_VERSION_MINOR "${CMAKE_MATCH_1}")
  50. endif()
  51. if(EMSCRIPTEN_VERSION_CONTENTS MATCHES "__EMSCRIPTEN_tiny__[ \t]+([0-9]+)")
  52. set(EMSCRIPTEN_VERSION_TINY "${CMAKE_MATCH_1}")
  53. endif()
  54. # When version(major/minor/tiny) is 0, "if(version)" is failed.
  55. # "if(version GREATER_EQUAL 0)" can compare version as numeric.
  56. if( (EMSCRIPTEN_VERSION_MAJOR GREATER_EQUAL "0") AND
  57. (EMSCRIPTEN_VERSION_MINOR GREATER_EQUAL "0") AND
  58. (EMSCRIPTEN_VERSION_TINY GREATER_EQUAL "0")
  59. )
  60. set(EMSCRIPTEN_VERSION "${EMSCRIPTEN_VERSION_MAJOR}.${EMSCRIPTEN_VERSION_MINOR}.${EMSCRIPTEN_VERSION_TINY}")
  61. message(STATUS "js: Emscripten version = ${EMSCRIPTEN_VERSION}")
  62. else()
  63. message(STATUS "js: Emscripten version is not able to parsed")
  64. message(AUTHOR_WARNING "EMSCRIPTEN_VERSION_CONTENTS = ${EMSCRIPTEN_VERSION_CONTENTS}")
  65. endif()
  66. endif()
  67. endif()
  68. # Embind requires C++17 or newer from Emscripten 4.0.20.
  69. # See https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#4020---111825
  70. if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.20")
  71. if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD STREQUAL "98"
  72. OR CMAKE_CXX_STANDARD STREQUAL "11" OR CMAKE_CXX_STANDARD STREQUAL "14")
  73. message(FATAL_ERROR "[OpenCV.js Build Error] "
  74. "Emscripten ${EMSCRIPTEN_VERSION} requires C++17 or newer for Embind, "
  75. "but CMAKE_CXX_STANDARD is set to '${CMAKE_CXX_STANDARD}'.\n"
  76. "Please re-run emcmake with --cmake_option=\"-DCMAKE_CXX_STANDARD=17\"\n")
  77. endif()
  78. endif()
  79. ocv_add_module(js BINDINGS PRIVATE_REQUIRED opencv_js_bindings_generator)
  80. ocv_module_include_directories(${EMSCRIPTEN_INCLUDE_DIR})
  81. set(deps ${OPENCV_MODULE_${the_module}_DEPS})
  82. list(REMOVE_ITEM deps opencv_js_bindings_generator) # don't add dummy module
  83. link_libraries(${deps})
  84. set(bindings_cpp "${OPENCV_JS_BINDINGS_DIR}/gen/bindings.cpp")
  85. set_source_files_properties(${bindings_cpp} PROPERTIES GENERATED TRUE)
  86. OCV_OPTION(BUILD_WASM_INTRIN_TESTS "Build WASM intrin tests" OFF )
  87. if(BUILD_WASM_INTRIN_TESTS)
  88. add_definitions(-DTEST_WASM_INTRIN)
  89. ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../ts/include")
  90. ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../imgcodecs/include")
  91. ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../videoio/include")
  92. ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../highgui/include")
  93. ocv_add_executable(${the_module} ${bindings_cpp} "${CMAKE_CURRENT_SOURCE_DIR}/../ts/src/ts_gtest.cpp")
  94. else()
  95. ocv_add_executable(${the_module} ${bindings_cpp})
  96. endif()
  97. add_dependencies(${the_module} gen_opencv_js_source)
  98. set(COMPILE_FLAGS "")
  99. if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
  100. set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-missing-prototypes")
  101. endif()
  102. if(COMPILE_FLAGS)
  103. set_target_properties(${the_module} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS})
  104. endif()
  105. set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s TOTAL_MEMORY=128MB -s WASM_MEM_MAX=1GB -s ALLOW_MEMORY_GROWTH=1")
  106. set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1")
  107. set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s EXPORT_NAME=\"'cv'\"")
  108. # See https://github.com/opencv/opencv/issues/27513
  109. # DEMANGLE_SUPPRT is deprecated at Emscripten 3.1.54 and later.
  110. if(NOT EMSCRIPTEN_VERSION OR EMSCRIPTEN_VERSION VERSION_LESS "3.1.54")
  111. set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s DEMANGLE_SUPPORT=1")
  112. endif()
  113. set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s FORCE_FILESYSTEM=1 --use-preload-plugins --bind --post-js ${JS_HELPER} ${COMPILE_FLAGS}")
  114. set_target_properties(${the_module} PROPERTIES LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS}")
  115. # add UMD wrapper
  116. set(MODULE_JS_PATH "${OpenCV_BINARY_DIR}/bin/${the_module}.js")
  117. set(OCV_JS_PATH "${OpenCV_BINARY_DIR}/bin/${OPENCV_JS}")
  118. add_custom_command(
  119. OUTPUT ${OCV_JS_PATH}
  120. COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/src/make_umd.py" ${MODULE_JS_PATH} "${OCV_JS_PATH}"
  121. DEPENDS ${the_module}
  122. DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/make_umd.py")
  123. add_custom_target(${OPENCV_JS} ALL
  124. DEPENDS ${OCV_JS_PATH}
  125. DEPENDS ${the_module})
  126. # test
  127. set(opencv_test_js_bin_dir "${EXECUTABLE_OUTPUT_PATH}")
  128. set(test_dir ${CMAKE_CURRENT_SOURCE_DIR}/test)
  129. set(opencv_test_js_file_deps "")
  130. # message(STATUS "${opencv_test_js_bin_dir}")
  131. # make sure the build directory exists
  132. file(MAKE_DIRECTORY "${opencv_test_js_bin_dir}")
  133. # gather and copy specific files for js test
  134. file(GLOB_RECURSE test_files RELATIVE "${test_dir}" "${test_dir}/*")
  135. foreach(f ${test_files})
  136. # message(STATUS "copy ${test_dir}/${f} ${opencv_test_js_bin_dir}/${f}")
  137. add_custom_command(OUTPUT "${opencv_test_js_bin_dir}/${f}"
  138. COMMAND ${CMAKE_COMMAND} -E copy_if_different "${test_dir}/${f}" "${opencv_test_js_bin_dir}/${f}"
  139. DEPENDS "${test_dir}/${f}"
  140. COMMENT "Copying ${f}"
  141. )
  142. list(APPEND opencv_test_js_file_deps "${test_dir}/${f}" "${opencv_test_js_bin_dir}/${f}")
  143. endforeach()
  144. # copy test data
  145. set(test_data "haarcascade_frontalface_default.xml")
  146. set(test_data_path "${PROJECT_SOURCE_DIR}/../../data/haarcascades/${test_data}")
  147. add_custom_command(OUTPUT "${opencv_test_js_bin_dir}/${test_data}"
  148. COMMAND ${CMAKE_COMMAND} -E copy_if_different "${test_data_path}" "${opencv_test_js_bin_dir}/${test_data}"
  149. DEPENDS "${test_data_path}"
  150. COMMENT "Copying ${test_data}"
  151. )
  152. list(APPEND opencv_test_js_file_deps "${test_data_path}" "${opencv_test_js_bin_dir}/${test_data}")
  153. add_custom_target(${PROJECT_NAME}_test
  154. DEPENDS ${OCV_JS_PATH} ${opencv_test_js_file_deps})
  155. # perf
  156. set(opencv_perf_js_bin_dir "${EXECUTABLE_OUTPUT_PATH}/perf")
  157. set(perf_dir ${CMAKE_CURRENT_SOURCE_DIR}/perf)
  158. set(opencv_perf_js_file_deps "")
  159. # make sure the build directory exists
  160. file(MAKE_DIRECTORY "${opencv_perf_js_bin_dir}")
  161. # gather and copy specific files for js perf
  162. file(GLOB_RECURSE perf_files RELATIVE "${perf_dir}" "${perf_dir}/*")
  163. foreach(f ${perf_files})
  164. add_custom_command(OUTPUT "${opencv_perf_js_bin_dir}/${f}"
  165. COMMAND ${CMAKE_COMMAND} -E copy_if_different "${perf_dir}/${f}" "${opencv_perf_js_bin_dir}/${f}"
  166. DEPENDS "${perf_dir}/${f}"
  167. COMMENT "Copying ${f}"
  168. )
  169. list(APPEND opencv_perf_js_file_deps "${perf_dir}/${f}" "${opencv_perf_js_bin_dir}/${f}")
  170. endforeach()
  171. add_custom_target(${PROJECT_NAME}_perf
  172. DEPENDS ${OCV_JS_PATH} ${opencv_perf_js_file_deps})
  173. #loader
  174. set(opencv_loader_js_bin_dir "${EXECUTABLE_OUTPUT_PATH}")
  175. set(loader_dir ${CMAKE_CURRENT_SOURCE_DIR}/src)
  176. set(opencv_loader_js_file_deps "")
  177. # make sure the build directory exists
  178. file(MAKE_DIRECTORY "${opencv_loader_js_bin_dir}")
  179. add_custom_command(
  180. TARGET ${PROJECT_NAME} POST_BUILD
  181. COMMAND ${CMAKE_COMMAND} -E copy
  182. ${loader_dir}/loader.js
  183. ${opencv_loader_js_bin_dir}/loader.js)
  184. list(APPEND opencv_loader_js_file_deps "${loader_dir}/loader.js" "${opencv_loader_js_bin_dir}/loader.js")
  185. add_custom_target(${PROJECT_NAME}_loader ALL
  186. DEPENDS ${OCV_JS_PATH} ${opencv_loader_js_file_deps})
  187. add_custom_target(opencv_test_js ALL DEPENDS opencv_js_test opencv_js_perf opencv_js_loader)