Skip to content

Commit 768f4cb

Browse files
committed
python: 'sub-module' for binding sources and documentation meta information
1 parent b15bc19 commit 768f4cb

File tree

7 files changed

+117
-104
lines changed

7 files changed

+117
-104
lines changed

cmake/OpenCVModule.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ macro(ocv_add_dependencies full_modname)
104104
list(FIND OPENCV_MODULE_${full_modname}_WRAPPERS "python" __python_idx)
105105
if (NOT __python_idx EQUAL -1)
106106
list(REMOVE_ITEM OPENCV_MODULE_${full_modname}_WRAPPERS "python")
107-
list(APPEND OPENCV_MODULE_${full_modname}_WRAPPERS "python2" "python3")
107+
list(APPEND OPENCV_MODULE_${full_modname}_WRAPPERS "python_bindings_generator" "python2" "python3")
108108
endif()
109109
unset(__python_idx)
110110

doc/CMakeLists.txt

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ endif(HAVE_DOC_GENERATOR)
3333

3434
if(BUILD_DOCS AND DOXYGEN_FOUND)
3535
# not documented modules list
36-
list(APPEND blacklist "ts" "java" "python2" "python3" "js" "world")
36+
list(APPEND blacklist "ts" "java" "python_bindings_generator" "python2" "python3" "js" "world")
3737
unset(CMAKE_DOXYGEN_TUTORIAL_CONTRIB_ROOT)
3838
unset(CMAKE_DOXYGEN_TUTORIAL_JS_ROOT)
3939

@@ -104,7 +104,6 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
104104
list(APPEND deps ${bib_file})
105105
endif()
106106
# Reference entry
107-
# set(one_ref "@ref ${m} | ${m}\n")
108107
set(one_ref "\t- ${m}. @ref ${m}\n")
109108
list(FIND EXTRA_MODULES ${m} _pos)
110109
if(${_pos} EQUAL -1)
@@ -205,9 +204,8 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
205204
list(APPEND js_tutorials_assets_deps "${f}" "${opencv_tutorial_html_dir}/${fname}")
206205
endforeach()
207206

208-
set(doxygen_result "${CMAKE_CURRENT_BINARY_DIR}/doxygen/html/modules.html")
209-
210-
add_custom_target(doxygen_cpp
207+
add_custom_target(
208+
doxygen_cpp
211209
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
212210
DEPENDS ${doxyfile} ${rootfile} ${bibfile} ${deps} ${js_tutorials_assets_deps}
213211
COMMENT "Generate Doxygen documentation"
@@ -218,18 +216,27 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
218216
COMPONENT "docs" OPTIONAL
219217
)
220218

221-
if(PYTHON2_EXECUTABLE)
222-
add_custom_target(doxygen_python
223-
COMMAND ${PYTHON2_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tools/add_signatures.py" "${CMAKE_CURRENT_BINARY_DIR}/doxygen/html/" "${OPENCV_PYTHON2_SIGNATURES_FILE}" "python"
224-
DEPENDS "${doxygen_result}" gen_opencv_python2
225-
)
226-
add_custom_target(doxygen
227-
DEPENDS doxygen_cpp doxygen_python
228-
)
229-
elseif(PYTHON3_EXECUTABLE)
219+
if(NOT DEFINED HAVE_PYTHON_BS4 AND PYTHON_DEFAULT_EXECUTABLE)
220+
# Documentation post-processing tool requires BuautifulSoup Python package
221+
execute_process(COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" -c "import bs4; from bs4 import BeautifulSoup; print(bs4.__version__)"
222+
RESULT_VARIABLE _result
223+
OUTPUT_VARIABLE _bs4_version
224+
OUTPUT_STRIP_TRAILING_WHITESPACE)
225+
226+
if(NOT _result EQUAL 0)
227+
set(HAVE_PYTHON_BS4 0 CACHE INTERNAL "")
228+
else()
229+
message(STATUS "Python BeautifulSoup (bs4) version: ${_bs4_version}")
230+
set(HAVE_PYTHON_BS4 1 CACHE INTERNAL "")
231+
endif()
232+
endif()
233+
234+
if(PYTHON_DEFAULT_EXECUTABLE AND HAVE_PYTHON_BS4
235+
AND OPENCV_PYTHON_SIGNATURES_FILE AND TARGET gen_opencv_python_source)
230236
add_custom_target(doxygen_python
231-
COMMAND ${PYTHON3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tools/add_signatures.py" "${CMAKE_CURRENT_BINARY_DIR}/doxygen/html/" "${OPENCV_PYTHON3_SIGNATURES_FILE}" "python"
232-
DEPENDS "${doxygen_result}" gen_opencv_python3
237+
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tools/add_signatures.py" "${CMAKE_CURRENT_BINARY_DIR}/doxygen/html/" "${OPENCV_PYTHON_SIGNATURES_FILE}" "python"
238+
DEPENDS doxygen_cpp gen_opencv_python_source
239+
COMMENT "Inject Python signatures into documentation"
233240
)
234241
add_custom_target(doxygen
235242
DEPENDS doxygen_cpp doxygen_python

modules/python/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# CMake file for python support
33
# ----------------------------------------------------------------------------
44

5+
add_subdirectory(bindings)
6+
57
if(ANDROID OR APPLE_FRAMEWORK OR WINRT)
68
set(__disable_python2 ON)
79
set(__disable_python3 ON)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
set(MODULE_NAME "python_bindings_generator")
2+
ocv_add_module(${MODULE_NAME} INTERNAL)
3+
4+
set(OPENCV_PYTHON_SIGNATURES_FILE "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_signatures.json" CACHE INTERNAL "")
5+
set(OPENCV_PYTHON_BINDINGS_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "")
6+
7+
# This file is included from a subdirectory
8+
set(PYTHON_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../")
9+
10+
# get list of modules to wrap
11+
set(OPENCV_PYTHON_MODULES)
12+
foreach(m ${OPENCV_MODULES_BUILD})
13+
if (";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";${MODULE_NAME};" AND HAVE_${m})
14+
list(APPEND OPENCV_PYTHON_MODULES ${m})
15+
#message(STATUS "\t${m}")
16+
endif()
17+
endforeach()
18+
19+
set(opencv_hdrs "")
20+
set(opencv_userdef_hdrs "")
21+
foreach(m ${OPENCV_PYTHON_MODULES})
22+
list(APPEND opencv_hdrs ${OPENCV_MODULE_${m}_HEADERS})
23+
file(GLOB userdef_hdrs ${OPENCV_MODULE_${m}_LOCATION}/misc/python/pyopencv*.hpp)
24+
list(APPEND opencv_userdef_hdrs ${userdef_hdrs})
25+
endforeach(m)
26+
27+
# header blacklist
28+
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$")
29+
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
30+
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
31+
ocv_list_filterout(opencv_hdrs "modules/cudev")
32+
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
33+
ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*")
34+
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.inl\\\\.h*")
35+
ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*")
36+
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*")
37+
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker\\\\.hpp") # Conditional compilation
38+
39+
set(cv2_generated_hdrs
40+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
41+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.h"
42+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h"
43+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h"
44+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h"
45+
)
46+
47+
set(cv2_generated_files ${cv2_generated_hdrs}
48+
"${OPENCV_PYTHON_SIGNATURES_FILE}"
49+
)
50+
51+
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
52+
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
53+
add_custom_command(
54+
OUTPUT ${cv2_generated_files}
55+
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
56+
DEPENDS ${PYTHON_SOURCE_DIR}/src2/gen2.py
57+
DEPENDS ${PYTHON_SOURCE_DIR}/src2/hdr_parser.py
58+
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
59+
DEPENDS ${opencv_hdrs}
60+
COMMENT "Generate files for Python bindings and documentation"
61+
)
62+
63+
add_custom_target(gen_opencv_python_source DEPENDS ${cv2_generated_files})
64+
65+
set(cv2_custom_hdr "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_custom_headers.h")
66+
file(WRITE ${cv2_custom_hdr} "//user-defined headers\n")
67+
foreach(uh ${opencv_userdef_hdrs})
68+
file(APPEND ${cv2_custom_hdr} "#include \"${uh}\"\n")
69+
endforeach(uh)

modules/python/common.cmake

Lines changed: 15 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,26 @@
11
# This file is included from a subdirectory
22
set(PYTHON_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../")
33

4-
# try to use dynamic symbols linking with libpython.so
5-
set(OPENCV_FORCE_PYTHON_LIBS OFF CACHE BOOL "")
6-
string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}")
7-
if(NOT WIN32 AND NOT APPLE AND NOT OPENCV_PYTHON_SKIP_LINKER_EXCLUDE_LIBS)
8-
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--exclude-libs=ALL")
9-
endif()
10-
11-
ocv_add_module(${MODULE_NAME} BINDINGS)
4+
ocv_add_module(${MODULE_NAME} BINDINGS PRIVATE_REQUIRED opencv_python_bindings_generator)
125

136
ocv_module_include_directories(
147
"${${PYTHON}_INCLUDE_PATH}"
8+
)
9+
include_directories(
1510
${${PYTHON}_NUMPY_INCLUDE_DIRS}
1611
"${PYTHON_SOURCE_DIR}/src2"
17-
)
18-
19-
# get list of modules to wrap
20-
# message(STATUS "Wrapped in ${MODULE_NAME}:")
21-
set(OPENCV_PYTHON_MODULES)
22-
foreach(m ${OPENCV_MODULES_BUILD})
23-
if (";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";${MODULE_NAME};" AND HAVE_${m})
24-
list(APPEND OPENCV_PYTHON_MODULES ${m})
25-
# message(STATUS "\t${m}")
26-
endif()
27-
endforeach()
28-
29-
set(opencv_hdrs "")
30-
set(opencv_userdef_hdrs "")
31-
foreach(m ${OPENCV_PYTHON_MODULES})
32-
list(APPEND opencv_hdrs ${OPENCV_MODULE_${m}_HEADERS})
33-
file(GLOB userdef_hdrs ${OPENCV_MODULE_${m}_LOCATION}/misc/python/pyopencv*.hpp)
34-
list(APPEND opencv_userdef_hdrs ${userdef_hdrs})
35-
endforeach(m)
36-
37-
# header blacklist
38-
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$")
39-
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
40-
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
41-
ocv_list_filterout(opencv_hdrs "modules/cudev")
42-
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
43-
ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*")
44-
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.inl\\\\.h*")
45-
ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*")
46-
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*")
47-
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker\\\\.hpp") # Conditional compilation
48-
49-
set(cv2_generated_hdrs
50-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
51-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.h"
52-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h"
53-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h"
54-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h"
55-
)
56-
57-
set(OPENCV_${PYTHON}_SIGNATURES_FILE "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_signatures.json" CACHE INTERNAL "")
58-
59-
set(cv2_generated_files ${cv2_generated_hdrs}
60-
"${OPENCV_${PYTHON}_SIGNATURES_FILE}"
61-
)
62-
63-
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
64-
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
65-
add_custom_command(
66-
OUTPUT ${cv2_generated_files}
67-
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${PYTHON}"
68-
DEPENDS ${PYTHON_SOURCE_DIR}/src2/gen2.py
69-
DEPENDS ${PYTHON_SOURCE_DIR}/src2/hdr_parser.py
70-
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
71-
DEPENDS ${opencv_hdrs}
72-
COMMENT "Generate files for ${the_module}"
12+
"${OPENCV_PYTHON_BINDINGS_DIR}"
7313
)
7414

75-
add_custom_target(gen_${the_module} DEPENDS ${cv2_generated_files})
76-
77-
set(cv2_custom_hdr "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_custom_headers.h")
78-
file(WRITE ${cv2_custom_hdr} "//user-defined headers\n")
79-
foreach(uh ${opencv_userdef_hdrs})
80-
file(APPEND ${cv2_custom_hdr} "#include \"${uh}\"\n")
81-
endforeach(uh)
15+
# try to use dynamic symbols linking with libpython.so
16+
set(OPENCV_FORCE_PYTHON_LIBS OFF CACHE BOOL "")
17+
string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}")
18+
if(NOT WIN32 AND NOT APPLE AND NOT OPENCV_PYTHON_SKIP_LINKER_EXCLUDE_LIBS)
19+
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--exclude-libs=ALL")
20+
endif()
8221

8322
ocv_add_library(${the_module} MODULE ${PYTHON_SOURCE_DIR}/src2/cv2.cpp ${cv2_generated_hdrs} ${opencv_userdef_hdrs} ${cv2_custom_hdr})
84-
add_dependencies(${the_module} gen_${the_module})
23+
add_dependencies(${the_module} gen_opencv_python_source)
8524

8625
if(APPLE)
8726
set_target_properties(${the_module} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
@@ -92,7 +31,10 @@ elseif(WIN32 OR OPENCV_FORCE_PYTHON_LIBS)
9231
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${${PYTHON}_LIBRARIES})
9332
endif()
9433
endif()
95-
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${OPENCV_MODULE_${the_module}_DEPS})
34+
35+
set(deps ${OPENCV_MODULE_${the_module}_DEPS})
36+
list(REMOVE_ITEM deps opencv_python_bindings_generator) # don't add dummy module to target_link_libraries list
37+
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${deps})
9638

9739
if(DEFINED ${PYTHON}_CVPY_SUFFIX)
9840
set(CVPY_SUFFIX "${${PYTHON}_CVPY_SUFFIX}")

modules/python/src2/cv2.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
1010
#include <numpy/ndarrayobject.h>
1111

12+
#if PY_MAJOR_VERSION >= 3
13+
# define CV_PYTHON_TYPE_HEAD_INIT() PyVarObject_HEAD_INIT(&PyType_Type, 0)
14+
#else
15+
# define CV_PYTHON_TYPE_HEAD_INIT() PyObject_HEAD_INIT(&PyType_Type) 0,
16+
#endif
17+
1218
#include "pyopencv_generated_include.h"
1319
#include "opencv2/core/types_c.h"
1420

modules/python/src2/gen2.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,7 @@
4646
}
4747
""")
4848

49-
py_major_version = sys.version_info[0]
50-
if __name__ == "__main__":
51-
if len(sys.argv) > 3:
52-
if sys.argv[3] == 'PYTHON3':
53-
py_major_version = 3
54-
elif sys.argv[3] == 'PYTHON2':
55-
py_major_version = 2
56-
else:
57-
raise Exception('Incorrect argument: expected PYTHON2 or PYTHON3, received: ' + sys.argv[3])
58-
if py_major_version >= 3:
59-
head_init_str = "PyVarObject_HEAD_INIT(&PyType_Type, 0)"
60-
else:
61-
head_init_str = """PyObject_HEAD_INIT(&PyType_Type)
62-
0,"""
49+
head_init_str = "CV_PYTHON_TYPE_HEAD_INIT()"
6350

6451
gen_template_simple_type_decl = Template("""
6552
struct pyopencv_${name}_t

0 commit comments

Comments
 (0)