mirror of
https://github.com/opencv/opencv.git
synced 2025-06-29 08:00:57 +08:00
feat: add conditional inclusion support to header parser
This commit is contained in:
parent
1c421be489
commit
b3e17ea9d4
63
cmake/OpenCVBindingsPreprocessorDefinitions.cmake
Normal file
63
cmake/OpenCVBindingsPreprocessorDefinitions.cmake
Normal file
@ -0,0 +1,63 @@
|
||||
function(ocv_bindings_generator_populate_preprocessor_definitions
|
||||
opencv_modules
|
||||
output_variable)
|
||||
set(defs "\"CV_VERSION_MAJOR\": ${OPENCV_VERSION_MAJOR}")
|
||||
|
||||
macro(ocv_add_definition name value)
|
||||
set(defs "${defs},\n\"${name}\": ${value}")
|
||||
endmacro()
|
||||
|
||||
ocv_add_definition(CV_VERSION_MINOR ${OPENCV_VERSION_MINOR})
|
||||
ocv_add_definition(CV_VERSION_PATCH ${OPENCV_VERSION_PATCH})
|
||||
ocv_add_definition(OPENCV_ABI_COMPATIBILITY "${OPENCV_VERSION_MAJOR}00")
|
||||
|
||||
foreach(module IN LISTS ${opencv_modules})
|
||||
if(HAVE_${module})
|
||||
string(TOUPPER "${module}" module)
|
||||
ocv_add_definition("HAVE_${module}" 1)
|
||||
endif()
|
||||
endforeach()
|
||||
if(HAVE_EIGEN)
|
||||
ocv_add_definition(HAVE_EIGEN 1)
|
||||
ocv_add_definition(EIGEN_WORLD_VERSION ${EIGEN_WORLD_VERSION})
|
||||
ocv_add_definition(EIGEN_MAJOR_VERSION ${EIGEN_MAJOR_VERSION})
|
||||
ocv_add_definition(EIGEN_MINOR_VERSION ${EIGEN_MINOR_VERSION})
|
||||
else()
|
||||
# Some checks in parsed headers might not be protected with HAVE_EIGEN check
|
||||
ocv_add_definition(EIGEN_WORLD_VERSION 0)
|
||||
ocv_add_definition(EIGEN_MAJOR_VERSION 0)
|
||||
ocv_add_definition(EIGEN_MINOR_VERSION 0)
|
||||
endif()
|
||||
if(HAVE_LAPACK)
|
||||
ocv_add_definition(HAVE_LAPACK 1)
|
||||
endif()
|
||||
|
||||
if(OPENCV_DISABLE_FILESYSTEM_SUPPORT)
|
||||
ocv_add_definition(OPENCV_HAVE_FILESYSTEM_SUPPORT 0)
|
||||
else()
|
||||
ocv_add_definition(OPENCV_HAVE_FILESYSTEM_SUPPORT 1)
|
||||
endif()
|
||||
|
||||
ocv_add_definition(OPENCV_BINDINGS_PARSER 1)
|
||||
|
||||
# Implementation details definitions, having no impact on how bindings are
|
||||
# generated, so their real values can be safely ignored
|
||||
ocv_add_definition(CV_ENABLE_UNROLLED 0)
|
||||
ocv_add_definition(CV__EXCEPTION_PTR 0)
|
||||
ocv_add_definition(CV_NEON 0)
|
||||
ocv_add_definition(TBB_INTERFACE_VERSION 0)
|
||||
ocv_add_definition(CV_SSE2 0)
|
||||
ocv_add_definition(CV_VSX 0)
|
||||
ocv_add_definition(OPENCV_SUPPORTS_FP_DENORMALS_HINT 0)
|
||||
ocv_add_definition(CV_LOG_STRIP_LEVEL 0)
|
||||
ocv_add_definition(CV_LOG_LEVEL_SILENT 0)
|
||||
ocv_add_definition(CV_LOG_LEVEL_FATAL 1)
|
||||
ocv_add_definition(CV_LOG_LEVEL_ERROR 2)
|
||||
ocv_add_definition(CV_LOG_LEVEL_WARN 3)
|
||||
ocv_add_definition(CV_LOG_LEVEL_INFO 4)
|
||||
ocv_add_definition(CV_LOG_LEVEL_DEBUG 5)
|
||||
ocv_add_definition(CV_LOG_LEVEL_VERBOSE 6)
|
||||
ocv_add_definition(CERES_FOUND 0)
|
||||
|
||||
set(${output_variable} ${defs} PARENT_SCOPE)
|
||||
endfunction()
|
@ -56,6 +56,12 @@ foreach(m ${OPENCV_JAVA_MODULES})
|
||||
ocv_remap_files(misc_files)
|
||||
endforeach(m)
|
||||
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVBindingsPreprocessorDefinitions.cmake")
|
||||
ocv_bindings_generator_populate_preprocessor_definitions(
|
||||
OPENCV_MODULES_BUILD
|
||||
opencv_preprocessor_defs
|
||||
)
|
||||
|
||||
set(CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen_java.json")
|
||||
set(__config_str
|
||||
"{
|
||||
@ -63,6 +69,9 @@ set(__config_str
|
||||
\"modules\": [
|
||||
${__modules_config}
|
||||
],
|
||||
\"preprocessor_definitions\": {
|
||||
${opencv_preprocessor_defs}
|
||||
},
|
||||
\"files_remap\": [
|
||||
${__remap_config}
|
||||
]
|
||||
|
@ -591,12 +591,16 @@ class JavaWrapperGenerator(object):
|
||||
f.write(buf)
|
||||
updated_files += 1
|
||||
|
||||
def gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, common_headers):
|
||||
def gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, common_headers,
|
||||
preprocessor_definitions=None):
|
||||
self.clear()
|
||||
self.module = module
|
||||
self.Module = module.capitalize()
|
||||
# TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
|
||||
parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
|
||||
parser = hdr_parser.CppHeaderParser(
|
||||
generate_umat_decls=False,
|
||||
preprocessor_definitions=preprocessor_definitions
|
||||
)
|
||||
|
||||
self.add_class( ['class cv.' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ]
|
||||
|
||||
@ -1444,6 +1448,7 @@ if __name__ == "__main__":
|
||||
gen_dict_files = []
|
||||
|
||||
print("JAVA: Processing OpenCV modules: %d" % len(config['modules']))
|
||||
preprocessor_definitions = config.get('preprocessor_definitions', None)
|
||||
for e in config['modules']:
|
||||
(module, module_location) = (e['name'], os.path.join(ROOT_DIR, e['location']))
|
||||
logging.info("\n=== MODULE: %s (%s) ===\n" % (module, module_location))
|
||||
@ -1508,7 +1513,8 @@ if __name__ == "__main__":
|
||||
copy_java_files(java_test_files_dir, java_test_base_path, 'org/opencv/test/' + module)
|
||||
|
||||
if len(srcfiles) > 0:
|
||||
generator.gen(srcfiles, module, dstdir, jni_path, java_path, common_headers)
|
||||
generator.gen(srcfiles, module, dstdir, jni_path, java_path, common_headers,
|
||||
preprocessor_definitions)
|
||||
else:
|
||||
logging.info("No generated code for module: %s", module)
|
||||
generator.finalize(jni_path)
|
||||
|
@ -30,7 +30,14 @@ ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/utils/*.privat
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/utils/instrumentation.hpp")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/utils/trace*")
|
||||
|
||||
ocv_update_file("${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}")
|
||||
set(config_json_headers_list "")
|
||||
foreach(header IN LISTS opencv_hdrs)
|
||||
if(NOT config_json_headers_list STREQUAL "")
|
||||
set(config_json_headers_list "${config_json_headers_list},\n\"${header}\"")
|
||||
else()
|
||||
set(config_json_headers_list "\"${header}\"")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(bindings_cpp "${OPENCV_JS_BINDINGS_DIR}/gen/bindings.cpp")
|
||||
|
||||
@ -55,16 +62,42 @@ else()
|
||||
message(STATUS "Use autogenerated whitelist ${OPENCV_JS_WHITELIST_FILE}")
|
||||
endif()
|
||||
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVBindingsPreprocessorDefinitions.cmake")
|
||||
ocv_bindings_generator_populate_preprocessor_definitions(
|
||||
OPENCV_MODULES_BUILD
|
||||
opencv_preprocessor_defs
|
||||
)
|
||||
|
||||
set(__config_str
|
||||
"{
|
||||
\"headers\": [
|
||||
${config_json_headers_list}
|
||||
],
|
||||
\"preprocessor_definitions\": {
|
||||
${opencv_preprocessor_defs}
|
||||
},
|
||||
\"core_bindings_file_path\": \"${JS_SOURCE_DIR}/src/core_bindings.cpp\"
|
||||
}")
|
||||
set(JSON_CONFIG_FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/gen_js_config.json")
|
||||
if(EXISTS "${JSON_CONFIG_FILE_PATH}")
|
||||
file(READ "${JSON_CONFIG_FILE_PATH}" __content)
|
||||
else()
|
||||
set(__content "")
|
||||
endif()
|
||||
if(NOT "${__content}" STREQUAL "${__config_str}")
|
||||
file(WRITE "${JSON_CONFIG_FILE_PATH}" "${__config_str}")
|
||||
endif()
|
||||
unset(__config_str)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${bindings_cpp} "${OPENCV_DEPHELPER}/gen_opencv_js_source"
|
||||
COMMAND
|
||||
${PYTHON_DEFAULT_EXECUTABLE}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/embindgen.py"
|
||||
"${scripts_hdr_parser}"
|
||||
"${bindings_cpp}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
|
||||
"${JS_SOURCE_DIR}/src/core_bindings.cpp"
|
||||
"${OPENCV_JS_WHITELIST_FILE}"
|
||||
--parser "${scripts_hdr_parser}"
|
||||
--output_file "${bindings_cpp}"
|
||||
--config "${JSON_CONFIG_FILE_PATH}"
|
||||
--whitelist "${OPENCV_JS_WHITELIST_FILE}"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/gen_opencv_js_source"
|
||||
WORKING_DIRECTORY
|
||||
@ -73,6 +106,7 @@ add_custom_command(
|
||||
${JS_SOURCE_DIR}/src/core_bindings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/embindgen.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/templates.py
|
||||
${JSON_CONFIG_FILE_PATH}
|
||||
"${OPENCV_JS_WHITELIST_FILE}"
|
||||
${scripts_hdr_parser}
|
||||
#(not needed - generated by CMake) ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
|
||||
|
@ -319,7 +319,7 @@ class Namespace(object):
|
||||
|
||||
|
||||
class JSWrapperGenerator(object):
|
||||
def __init__(self):
|
||||
def __init__(self, preprocessor_definitions=None):
|
||||
|
||||
self.bindings = []
|
||||
self.wrapper_funcs = []
|
||||
@ -328,7 +328,9 @@ class JSWrapperGenerator(object):
|
||||
self.namespaces = {}
|
||||
self.enums = {} # FIXIT 'enums' should belong to 'namespaces'
|
||||
|
||||
self.parser = hdr_parser.CppHeaderParser()
|
||||
self.parser = hdr_parser.CppHeaderParser(
|
||||
preprocessor_definitions=preprocessor_definitions
|
||||
)
|
||||
self.class_idx = 0
|
||||
|
||||
def add_class(self, stype, name, decl):
|
||||
@ -962,41 +964,69 @@ class JSWrapperGenerator(object):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 5:
|
||||
print("Usage:\n", \
|
||||
os.path.basename(sys.argv[0]), \
|
||||
"<full path to hdr_parser.py> <bindings.cpp> <headers.txt> <core_bindings.cpp> <whitelist.json or opencv_js.config.py>")
|
||||
print("Current args are: ", ", ".join(["'"+a+"'" for a in sys.argv]))
|
||||
exit(1)
|
||||
import argparse
|
||||
|
||||
dstdir = "."
|
||||
hdr_parser_path = os.path.abspath(sys.argv[1])
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
description="OpenCV JavaScript bindings generator"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-p", "--parser",
|
||||
required=True,
|
||||
help="Full path to OpenCV header parser `hdr_parser.py`"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-o", "--output_file",
|
||||
dest="output_file_path",
|
||||
required=True,
|
||||
help="Path to output file containing js bindings"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-c", "--config",
|
||||
dest="config_json_path",
|
||||
required=True,
|
||||
help="Path to generator configuration file in .json format"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--whitelist",
|
||||
dest="whitelist_file_path",
|
||||
required=True,
|
||||
help="Path to whitelist.js or opencv_js.config.py"
|
||||
)
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
# import header parser
|
||||
hdr_parser_path = os.path.abspath(args.parser)
|
||||
if hdr_parser_path.endswith(".py"):
|
||||
hdr_parser_path = os.path.dirname(hdr_parser_path)
|
||||
sys.path.append(hdr_parser_path)
|
||||
import hdr_parser
|
||||
|
||||
bindingsCpp = sys.argv[2]
|
||||
headers = open(sys.argv[3], 'r').read().split(';')
|
||||
coreBindings = sys.argv[4]
|
||||
whiteListFile = sys.argv[5]
|
||||
with open(args.config_json_path, "r") as fh:
|
||||
config_json = json.load(fh)
|
||||
headers = config_json.get("headers", ())
|
||||
|
||||
if whiteListFile.endswith(".json") or whiteListFile.endswith(".JSON"):
|
||||
with open(whiteListFile) as f:
|
||||
bindings_cpp = args.output_file_path
|
||||
core_bindings_path = config_json["core_bindings_file_path"]
|
||||
whitelist_file_path = args.whitelist_file_path
|
||||
|
||||
if whitelist_file_path.endswith(".json") or whitelist_file_path.endswith(".JSON"):
|
||||
with open(whitelist_file_path) as f:
|
||||
gen_dict = json.load(f)
|
||||
f.close()
|
||||
white_list = makeWhiteListJson(gen_dict)
|
||||
namespace_prefix_override = makeNamespacePrefixOverride(gen_dict)
|
||||
elif whiteListFile.endswith(".py") or whiteListFile.endswith(".PY"):
|
||||
exec(open(whiteListFile).read())
|
||||
assert(white_list)
|
||||
elif whitelist_file_path.endswith(".py") or whitelist_file_path.endswith(".PY"):
|
||||
with open(whitelist_file_path) as fh:
|
||||
exec(fh.read())
|
||||
assert white_list
|
||||
namespace_prefix_override = {
|
||||
'dnn' : '',
|
||||
'aruco' : '',
|
||||
}
|
||||
else:
|
||||
print("Unexpected format of OpenCV config file", whiteListFile)
|
||||
print("Unexpected format of OpenCV config file", whitelist_file_path)
|
||||
exit(1)
|
||||
|
||||
generator = JSWrapperGenerator()
|
||||
generator.gen(bindingsCpp, headers, coreBindings)
|
||||
generator = JSWrapperGenerator(
|
||||
preprocessor_definitions=config_json.get("preprocessor_definitions", None)
|
||||
)
|
||||
generator.gen(bindings_cpp, headers, core_bindings_path)
|
||||
|
@ -38,6 +38,13 @@ if(HAVE_opencv_objc)
|
||||
set(__objc_build_dir "\"objc_build_dir\": \"${CMAKE_CURRENT_BINARY_DIR}/../objc\",")
|
||||
endif()
|
||||
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVBindingsPreprocessorDefinitions.cmake")
|
||||
|
||||
ocv_bindings_generator_populate_preprocessor_definitions(
|
||||
OPENCV_MODULES_BUILD
|
||||
opencv_preprocessor_defs
|
||||
)
|
||||
|
||||
set(CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen_objc.json")
|
||||
set(__config_str
|
||||
"{
|
||||
@ -45,7 +52,10 @@ set(__config_str
|
||||
${__objc_build_dir}
|
||||
\"modules\": [
|
||||
${__modules_config}
|
||||
]
|
||||
],
|
||||
\"preprocessor_definitions\": {
|
||||
${opencv_preprocessor_defs}
|
||||
}
|
||||
}
|
||||
")
|
||||
#TODO: ocv_update_file("${CONFIG_FILE}" "${__config_str}" ON_CHANGE_REMOVE "${OPENCV_DEPHELPER}/gen_opencv_objc_source")
|
||||
|
@ -894,7 +894,8 @@ class ObjectiveCWrapperGenerator(object):
|
||||
namespace = self.classes[cname].namespace if cname in self.classes else "cv"
|
||||
return namespace.replace(".", "::") + "::"
|
||||
|
||||
def gen(self, srcfiles, module, output_path, output_objc_path, common_headers, manual_classes):
|
||||
def gen(self, srcfiles, module, output_path, output_objc_path,
|
||||
common_headers, manual_classes, preprocessor_definitions=None):
|
||||
self.clear()
|
||||
self.module = module
|
||||
self.objcmodule = make_objcmodule(module)
|
||||
@ -903,7 +904,10 @@ class ObjectiveCWrapperGenerator(object):
|
||||
extension_signatures = []
|
||||
|
||||
# TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
|
||||
parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
|
||||
parser = hdr_parser.CppHeaderParser(
|
||||
generate_umat_decls=False,
|
||||
preprocessor_definitions=preprocessor_definitions
|
||||
)
|
||||
|
||||
module_ci = self.add_class( ['class ' + self.Module, '', [], []]) # [ 'class/struct cname', ':bases', [modlist] [props] ]
|
||||
module_ci.header_import = module + '.hpp'
|
||||
@ -1715,7 +1719,9 @@ if __name__ == "__main__":
|
||||
manual_classes = [x for x in [x[x.rfind('/')+1:-2] for x in [x for x in copied_files if x.endswith('.h')]] if x in type_dict]
|
||||
|
||||
if len(srcfiles) > 0:
|
||||
generator.gen(srcfiles, module, dstdir, objc_base_path, common_headers, manual_classes)
|
||||
generator.gen(srcfiles, module, dstdir, objc_base_path,
|
||||
common_headers, manual_classes,
|
||||
config.get("preprocessor_definitions"))
|
||||
else:
|
||||
logging.info("No generated code for module: %s", module)
|
||||
generator.finalize(args.target, objc_base_path, objc_build_dir)
|
||||
|
@ -74,12 +74,50 @@ set(cv2_generated_files
|
||||
"${OPENCV_PYTHON_SIGNATURES_FILE}"
|
||||
)
|
||||
|
||||
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
|
||||
|
||||
set(config_json_headers_list "")
|
||||
foreach(header IN LISTS opencv_hdrs)
|
||||
if(NOT config_json_headers_list STREQUAL "")
|
||||
set(config_json_headers_list "${config_json_headers_list},\n\"${header}\"")
|
||||
else()
|
||||
set(config_json_headers_list "\"${header}\"")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVBindingsPreprocessorDefinitions.cmake")
|
||||
|
||||
ocv_bindings_generator_populate_preprocessor_definitions(
|
||||
OPENCV_MODULES_BUILD
|
||||
opencv_preprocessor_defs
|
||||
)
|
||||
|
||||
set(__config_str
|
||||
"{
|
||||
\"headers\": [
|
||||
${config_json_headers_list}
|
||||
],
|
||||
\"preprocessor_definitions\": {
|
||||
${opencv_preprocessor_defs}
|
||||
}
|
||||
}")
|
||||
|
||||
set(JSON_CONFIG_FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/gen_python_config.json")
|
||||
if(EXISTS "${JSON_CONFIG_FILE_PATH}")
|
||||
file(READ "${JSON_CONFIG_FILE_PATH}" __content)
|
||||
else()
|
||||
set(__content "")
|
||||
endif()
|
||||
if(NOT "${__content}" STREQUAL "${__config_str}")
|
||||
file(WRITE "${JSON_CONFIG_FILE_PATH}" "${__config_str}")
|
||||
endif()
|
||||
unset(__config_str)
|
||||
|
||||
file(GLOB_RECURSE typing_stubs_generation_files "${PYTHON_SOURCE_DIR}/src2/typing_stubs_generation/*.py")
|
||||
add_custom_command(
|
||||
OUTPUT ${cv2_generated_files}
|
||||
COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" "${PYTHON_SOURCE_DIR}/src2/gen2.py" "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
|
||||
COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" "${PYTHON_SOURCE_DIR}/src2/gen2.py"
|
||||
"--config" "${JSON_CONFIG_FILE_PATH}"
|
||||
"--output_dir" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS "${PYTHON_SOURCE_DIR}/src2/gen2.py"
|
||||
"${PYTHON_SOURCE_DIR}/src2/hdr_parser.py"
|
||||
"${typing_stubs_generation_files}"
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import hdr_parser, sys, re
|
||||
import json
|
||||
from string import Template
|
||||
from collections import namedtuple
|
||||
from itertools import chain
|
||||
@ -1108,6 +1109,18 @@ class Namespace(object):
|
||||
|
||||
|
||||
class PythonWrapperGenerator(object):
|
||||
class Config:
|
||||
def __init__(self, headers, preprocessor_definitions = None):
|
||||
self.headers = headers
|
||||
if preprocessor_definitions is None:
|
||||
preprocessor_definitions = {}
|
||||
elif not isinstance(preprocessor_definitions, dict):
|
||||
raise TypeError(
|
||||
"preprocessor_definitions should rather dictionary or None. "
|
||||
"Got: {}".format(type(preprocessor_definitions).__name__)
|
||||
)
|
||||
self.preprocessor_definitions = preprocessor_definitions
|
||||
|
||||
def __init__(self):
|
||||
self.clear()
|
||||
|
||||
@ -1324,13 +1337,16 @@ class PythonWrapperGenerator(object):
|
||||
f.write(buf.getvalue())
|
||||
|
||||
def save_json(self, path, name, value):
|
||||
import json
|
||||
with open(path + "/" + name, "wt") as f:
|
||||
json.dump(value, f)
|
||||
|
||||
def gen(self, srcfiles, output_path):
|
||||
def gen(self, srcfiles, output_path, preprocessor_definitions = None):
|
||||
self.clear()
|
||||
self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
|
||||
self.parser = hdr_parser.CppHeaderParser(
|
||||
generate_umat_decls=True,
|
||||
generate_gpumat_decls=True,
|
||||
preprocessor_definitions=preprocessor_definitions
|
||||
)
|
||||
|
||||
|
||||
# step 1: scan the headers and build more descriptive maps of classes, consts, functions
|
||||
@ -1502,12 +1518,36 @@ class PythonWrapperGenerator(object):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
srcfiles = hdr_parser.opencv_hdr_list
|
||||
dstdir = "/Users/vp/tmp"
|
||||
if len(sys.argv) > 1:
|
||||
dstdir = sys.argv[1]
|
||||
if len(sys.argv) > 2:
|
||||
with open(sys.argv[2], 'r') as f:
|
||||
srcfiles = [l.strip() for l in f.readlines()]
|
||||
import argparse
|
||||
import tempfile
|
||||
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
description="OpenCV Python bindings generator"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-c", "--config",
|
||||
dest="config_json_path",
|
||||
required=False,
|
||||
help="Generator configuration file in .json format"
|
||||
"Refer to PythonWrapperGenerator.Config for available "
|
||||
"configuration keys"
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-o", "--output_dir",
|
||||
dest="output_dir",
|
||||
default=tempfile.gettempdir(),
|
||||
help="Generated bindings output directory"
|
||||
)
|
||||
args = arg_parser.parse_args()
|
||||
if args.config_json_path is not None:
|
||||
with open(args.config_json_path, "r") as fh:
|
||||
config_json = json.load(fh)
|
||||
config = PythonWrapperGenerator.Config(**config_json)
|
||||
else:
|
||||
config = PythonWrapperGenerator.Config(
|
||||
headers=hdr_parser.opencv_hdr_list
|
||||
)
|
||||
|
||||
generator = PythonWrapperGenerator()
|
||||
generator.gen(srcfiles, dstdir)
|
||||
|
||||
generator.gen(config.headers, args.output_dir, config.preprocessor_definitions)
|
||||
|
@ -31,11 +31,160 @@ where the list of modifiers is yet another nested list of strings
|
||||
original_return_type is None if the original_return_type is the same as return_value_type
|
||||
"""
|
||||
|
||||
def evaluate_conditional_inclusion_directive(directive, preprocessor_definitions):
|
||||
"""Evaluates C++ conditional inclusion directive.
|
||||
Reference: https://en.cppreference.com/w/cpp/preprocessor/conditional
|
||||
|
||||
Args:
|
||||
directive(str): input C++ conditional directive.
|
||||
preprocessor_definitions(dict[str, int]): defined preprocessor identifiers.
|
||||
|
||||
Returns:
|
||||
bool: True, if directive is evaluated to 1, False otherwise.
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#ifdef A", {"A": 0})
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#ifdef A", {"B": 0})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#ifndef A", {})
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#ifndef A", {"A": 1})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if 0", {})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if 1", {})
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if VAR", {"VAR": 0})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if VAR ", {"VAR": 1})
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if defined(VAR)", {"VAR": 0})
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if !defined(VAR)", {"VAR": 0})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive("#if defined(VAR_1)", {"VAR_2": 0})
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive(
|
||||
... "#if defined(VAR) && VAR", {"VAR": 0}
|
||||
... )
|
||||
False
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive(
|
||||
... "#if VAR_1 || VAR_2", {"VAR_1": 1, "VAR_2": 0}
|
||||
... )
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive(
|
||||
... "#if defined VAR && defined (VAR)", {"VAR": 1}
|
||||
... )
|
||||
True
|
||||
|
||||
>>> evaluate_conditional_inclusion_directive(
|
||||
... "#if strangedefinedvar", {}
|
||||
... )
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Failed to evaluate '#if strangedefinedvar' directive, stripped down to 'strangedefinedvar'
|
||||
"""
|
||||
OPERATORS = { "!": "not ", "&&": "and", "&": "and", "||": "or", "|": "or" }
|
||||
|
||||
input_directive = directive
|
||||
|
||||
# Ignore all directives if they contain __cplusplus check
|
||||
if "__cplusplus" in directive:
|
||||
return True
|
||||
|
||||
directive = directive.strip()
|
||||
if directive.startswith("#ifdef "):
|
||||
var = directive[len("#ifdef "):].strip()
|
||||
return var in preprocessor_definitions
|
||||
if directive.startswith("#ifndef "):
|
||||
var = directive[len("#ifndef "):].strip()
|
||||
return var not in preprocessor_definitions
|
||||
|
||||
if directive.startswith("#if "):
|
||||
directive = directive[len("#if "):].strip()
|
||||
elif directive.startswith("#elif "):
|
||||
directive = directive[len("#elif "):].strip()
|
||||
else:
|
||||
raise ValueError("{} is not known conditional directive".format(directive))
|
||||
|
||||
if directive.isdigit():
|
||||
return int(directive) != 0
|
||||
|
||||
if directive in preprocessor_definitions:
|
||||
return bool(preprocessor_definitions[directive])
|
||||
|
||||
# Converting all `defined` directives to their boolean representations
|
||||
# they have 2 forms: `defined identifier` and `defined(identifier)`
|
||||
directive = re.sub(
|
||||
r"\bdefined\s*(\w+|\(\w+\))",
|
||||
lambda m: "True" if m.group(1).strip("() ") in preprocessor_definitions else "False",
|
||||
directive
|
||||
)
|
||||
|
||||
for src_op, dst_op in OPERATORS.items():
|
||||
directive = directive.replace(src_op, dst_op)
|
||||
|
||||
try:
|
||||
if sys.version_info >= (3, 13):
|
||||
eval_directive = eval(directive,
|
||||
globals={"__builtins__": {}},
|
||||
locals=preprocessor_definitions)
|
||||
else:
|
||||
eval_directive = eval(directive,
|
||||
{"__builtins__": {}},
|
||||
preprocessor_definitions)
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
"Failed to evaluate '{}' directive, stripped down to '{}'".format(
|
||||
input_directive, directive
|
||||
)
|
||||
) from e
|
||||
|
||||
if not isinstance(eval_directive, (bool, int)):
|
||||
raise TypeError(
|
||||
"'{}' directive is evaluated to unexpected type: {}".format(
|
||||
input_directive, type(eval_directive).__name__
|
||||
)
|
||||
)
|
||||
if isinstance(eval_directive, bool):
|
||||
return eval_directive
|
||||
|
||||
return eval_directive != 0
|
||||
|
||||
|
||||
class CppHeaderParser(object):
|
||||
|
||||
def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
|
||||
def __init__(self, generate_umat_decls = False, generate_gpumat_decls = False,
|
||||
preprocessor_definitions = None):
|
||||
self._generate_umat_decls = generate_umat_decls
|
||||
self._generate_gpumat_decls = generate_gpumat_decls
|
||||
if preprocessor_definitions is None:
|
||||
preprocessor_definitions = {}
|
||||
elif not isinstance(preprocessor_definitions, dict):
|
||||
raise TypeError(
|
||||
"preprocessor_definitions should rather dictionary or None. "
|
||||
"Got: {}".format(type(preprocessor_definitions).__name__)
|
||||
)
|
||||
self.preprocessor_definitions = preprocessor_definitions
|
||||
if "__OPENCV_BUILD" not in self.preprocessor_definitions:
|
||||
self.preprocessor_definitions["__OPENCV_BUILD"] = 0
|
||||
if "OPENCV_BINDING_PARSER" not in self.preprocessor_definitions:
|
||||
self.preprocessor_definitions["OPENCV_BINDING_PARSER"] = 1
|
||||
if "OPENCV_BINDINGS_PARSER" not in self.preprocessor_definitions:
|
||||
self.preprocessor_definitions["OPENCV_BINDINGS_PARSER"] = 1
|
||||
|
||||
self.BLOCK_TYPE = 0
|
||||
self.BLOCK_NAME = 1
|
||||
@ -839,9 +988,8 @@ class CppHeaderParser(object):
|
||||
"""
|
||||
self.hname = hname
|
||||
decls = []
|
||||
f = io.open(hname, 'rt', encoding='utf-8')
|
||||
with io.open(hname, 'rt', encoding='utf-8') as f:
|
||||
linelist = list(f.readlines())
|
||||
f.close()
|
||||
|
||||
# states:
|
||||
SCAN = 0 # outside of a comment or preprocessor directive
|
||||
@ -859,7 +1007,6 @@ class CppHeaderParser(object):
|
||||
self.wrap_mode = wmode
|
||||
|
||||
depth_if_0 = 0
|
||||
|
||||
for l0 in linelist:
|
||||
self.lineno += 1
|
||||
#print(state, self.lineno, l0)
|
||||
@ -886,22 +1033,38 @@ class CppHeaderParser(object):
|
||||
continue
|
||||
state = SCAN
|
||||
l = re.sub(r'//(.+)?', '', l).strip() # drop // comment
|
||||
if l in [
|
||||
'#if 0',
|
||||
'#if defined(__OPENCV_BUILD)', '#ifdef __OPENCV_BUILD',
|
||||
'#if !defined(OPENCV_BINDING_PARSER)', '#ifndef OPENCV_BINDING_PARSER',
|
||||
]:
|
||||
if l.startswith("#if") or l.startswith("#elif"):
|
||||
if not evaluate_conditional_inclusion_directive(
|
||||
l, self.preprocessor_definitions
|
||||
):
|
||||
# Condition evaluated to false
|
||||
state = DIRECTIVE_IF_0
|
||||
depth_if_0 = 1
|
||||
elif l.startswith("#else"):
|
||||
# else in state == DIRECTIVE may occur only if previous
|
||||
# conditional inclusion directive was evaluated to True
|
||||
state = DIRECTIVE_IF_0
|
||||
depth_if_0 = 1
|
||||
continue
|
||||
|
||||
if state == DIRECTIVE_IF_0:
|
||||
if l.startswith('#'):
|
||||
l = l[1:].strip()
|
||||
if l.startswith("if"):
|
||||
if l.startswith("#"):
|
||||
if l.startswith("#if"):
|
||||
depth_if_0 += 1
|
||||
continue
|
||||
if l.startswith("endif"):
|
||||
elif l.startswith("#else") and depth_if_0 == 1:
|
||||
depth_if_0 = 0
|
||||
state = SCAN
|
||||
elif l.startswith("#elif") and depth_if_0 == 1:
|
||||
if evaluate_conditional_inclusion_directive(
|
||||
l, self.preprocessor_definitions
|
||||
):
|
||||
depth_if_0 = 0
|
||||
state = SCAN
|
||||
else:
|
||||
depth_if_0 += 1
|
||||
continue
|
||||
elif l.startswith("#endif"):
|
||||
depth_if_0 -= 1
|
||||
if depth_if_0 == 0:
|
||||
state = SCAN
|
||||
@ -1075,6 +1238,9 @@ class CppHeaderParser(object):
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
|
||||
decls = []
|
||||
for hname in opencv_hdr_list:
|
||||
|
Loading…
Reference in New Issue
Block a user