diff --git a/CMake/ctkMacroWrapPythonQt.cmake b/CMake/ctkMacroWrapPythonQt.cmake index 5239d1e743..8cd0269254 100644 --- a/CMake/ctkMacroWrapPythonQt.cmake +++ b/CMake/ctkMacroWrapPythonQt.cmake @@ -25,7 +25,7 @@ #! #! Depends on: #! PythonQt -#! PythonInterp (See function reSearchFile) +#! PythonInterp #! #! @@ -63,38 +63,6 @@ function(ctkMacroWrapPythonQt_log msg) file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/ctkMacroWrapPythonQt_log.txt" "${msg}\n") endfunction() -include(${CTK_CMAKE_DIR}/ctkMacroSetPaths.cmake) - -#! -#! Convenient function allowing to invoke re.search(regex, string) using the given interpreter. -#! Note that is_matching will be set to True if there is a match -#! -#! \ingroup CMakeUtilities -function(ctkMacroWrapPythonQt_reSearchFile python_exe python_library_path regex file is_matching) - - set(python_cmd "import re -f = open('${file}', 'r') -res = re.search('${regex}', f.read(), re.MULTILINE) -if res == None: print 'FALSE' -else: print 'TRUE' -") - #message("python_cmd: ${python_cmd}") - - ctkMacroSetPaths("${python_library_path}") - execute_process( - COMMAND ${python_exe} -c ${python_cmd} - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_VARIABLE error - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(result) - message(FATAL_ERROR "reSearchFile - Problem with regex: ${regex}\n${error}\nPython exe: ${python_exe}\nPython lib path: ${python_library_path}") - endif() - set(is_matching ${output} PARENT_SCOPE) -endfunction() - #! \ingroup CMakeUtilities macro(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_WRAP_FULL HAS_DECORATOR) @@ -158,50 +126,8 @@ macro(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W endif() endif() - # what is the filename without the extension - get_filename_component(TMP_FILENAME ${FILE} NAME_WE) - - # Extract classname - NOTE: We assume the filename matches the associated class - set(className ${TMP_FILENAME}) - - if(NOT skip_wrapping) - # Skip wrapping if file do NOT contain Q_OBJECT - file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} file_content) - if(NOT "${file_content}" MATCHES "Q_OBJECT") - set(skip_wrapping TRUE) - ctkMacroWrapPythonQt_log("${FILE}: skipping - No Q_OBJECT macro") - endif() - endif() - - if(NOT skip_wrapping) - # Skip wrapping if constructor doesn't match: - # my_class() - # my_class(QObject* newParent ...) - # my_class(QWidget* newParent ...) - # Constructor with either QWidget or QObject as first parameter - set(regex "[^~]${className}[\\s\\n]*\\([\\s\\n]*((QObject|QWidget)[\\s\\n]*\\*[\\s\\n]*\\w+[\\s\\n]*(\\=[\\s\\n]*(0|NULL)|,.*\\=.*\\)|\\)|\\)))") - ctkMacroWrapPythonQt_reSearchfile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH} - ${regex} ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} is_matching) - if(NOT is_matching) - set(skip_wrapping TRUE) - ctkMacroWrapPythonQt_log("${FILE}: skipping - Missing expected constructor signature") - endif() - endif() - - if(NOT skip_wrapping) - # Skip wrapping if object has a virtual pure method - # "x3b" is the unicode for semicolon - set(regex "virtual[\\w\\n\\s\\*\\(\\)]+\\=[\\s\\n]*(0|NULL)[\\s\\n]*\\x3b") - ctkMacroWrapPythonQt_reSearchfile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH} - ${regex} ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} is_matching) - if(is_matching) - set(skip_wrapping TRUE) - ctkMacroWrapPythonQt_log("${FILE}: skipping - Contains a virtual pure method") - endif() - endif() - # if we should wrap it - IF (NOT skip_wrapping) + if(NOT skip_wrapping) # compute the input filename if(IS_ABSOLUTE FILE) @@ -225,9 +151,6 @@ macro(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W set(wrap_int_dir generated_cpp/${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}/) #message("wrap_int_dir:${wrap_int_dir}") - # Create intermediate output directory - execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${wrap_int_dir}) - set(wrapper_init_cpp_filename ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp) set(wrapper_init_cpp_file ${CMAKE_CURRENT_BINARY_DIR}/${wrap_int_dir}${wrapper_init_cpp_filename}) @@ -245,15 +168,13 @@ macro(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W ${CTK_CMAKE_DIR}/ctkScriptWrapPythonQt_Light.cmake ${CTK_CMAKE_DIR}/ctkMacroWrapPythonQtModuleInit.cpp.in COMMAND ${CMAKE_COMMAND} - -DPYTHONQTGENERATOR_EXECUTABLE:FILEPATH=${PYTHONQTGENERATOR_EXECUTABLE} -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_LIBRARY_PATH:PATH=${PYTHON_LIBRARY_PATH} + -DWRAPPING_SCRIPT:FILEPATH=${CTK_CMAKE_DIR}/ctkWrapPythonQt.py -DWRAPPING_NAMESPACE:STRING=${WRAPPING_NAMESPACE} -DTARGET:STRING=${TARGET} -DSOURCES:STRING=${SOURCES_TO_WRAP_ARG} - -DOUTPUT_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR} - -DWRAP_INT_DIR:STRING=${wrap_int_dir} - -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} + -DOUTPUT_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/${wrap_int_dir} -DHAS_DECORATOR:BOOL=${HAS_DECORATOR} -P ${CTK_CMAKE_DIR}/ctkScriptWrapPythonQt_Light.cmake COMMENT "PythonQt Wrapping - Generating ${wrapper_init_cpp_filename}" diff --git a/CMake/ctkMacroWrapPythonQtModuleInit.cpp.in b/CMake/ctkMacroWrapPythonQtModuleInit.cpp.in index d90195142e..7990bf2e38 100644 --- a/CMake/ctkMacroWrapPythonQtModuleInit.cpp.in +++ b/CMake/ctkMacroWrapPythonQtModuleInit.cpp.in @@ -1,4 +1,4 @@ -// Configured by cmake macro @CMAKE_CURRENT_LIST_FILENAME@ +// Configured by cmake macro @CMAKE_CURRENT_LIST_FILE@ #include #include diff --git a/CMake/ctkScriptWrapPythonQt_Light.cmake b/CMake/ctkScriptWrapPythonQt_Light.cmake index 723e06892e..39ab0e1fb4 100644 --- a/CMake/ctkScriptWrapPythonQt_Light.cmake +++ b/CMake/ctkScriptWrapPythonQt_Light.cmake @@ -22,19 +22,14 @@ # ctkScriptWrapPythonQt_Light # -# -# Depends on: -# CTK/CMake/ctkMacroWrapPythonQt.cmake -# - # # This script should be invoked either as a CUSTOM_COMMAND # or from the command line using the following syntax: # -# cmake -DWRAPPING_NAMESPACE:STRING=org.commontk -DTARGET:STRING=MyLib +# cmake -DWRAPPING_SCRIPT:FILEPATH=/path/to/ctkWrapPythonQt.py +# -DWRAPPING_NAMESPACE:STRING=org.commontk -DTARGET:STRING=MyLib # -DSOURCES:STRING="file1^^file2" -# -DWRAP_INT_DIR:STRING=subir/subir/ -# -DOUTPUT_DIR:PATH=/path -DQT_QMAKE_EXECUTABLE:PATH=/path/to/qt/qmake +# -DOUTPUT_DIR:PATH=/path # -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python # -DPYTHON_LIBRARY_PATH:PATH=/path/to/pythonlib # -DHAS_DECORATOR:BOOL=True @@ -47,221 +42,63 @@ # It will contain the list of class and the constructor signature that will be wrapped. # -set(verbose 0) - -# -# Convenient function allowing to log the reason why a given class hasn't been wrapped -# If verbose=1, it will also be displayed on the standard output -# -function(log msg) - if(verbose) - message(${msg}) - endif() - file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/ctkScriptWrapPythonQt_Light_log.txt" "${msg}\n") -endfunction() - -# -# Convenient function allowing to invoke re.search(regex, string) using the given interpreter. -# Note that is_matching will be set to True if there is a match -# -function(reSearchFile python_exe python_library_path regex file is_matching) - - set(python_cmd "import re\; f = open('${file}', 'r')\; -res = re.search\(\"${regex}\", f.read(), re.MULTILINE\)\; -if res == None: print \"FALSE\" -else: print \"TRUE\" -") - #message("python_cmd: ${python_cmd}") - - if(WIN32) - set(ENV{PATH} ${python_library_path};$ENV{PATH}) - elseif(APPLE) - set(ENV{DYLD_LIBRARY_PATH} ${python_library_path}:$ENV{DYLD_LIBRARY_PATH}) - else() - set(ENV{LD_LIBRARY_PATH} ${python_library_path}:$ENV{LD_LIBRARY_PATH}) - endif() - - execute_process( - COMMAND ${python_exe} -c ${python_cmd}; - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_VARIABLE error - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(result) - message(FATAL_ERROR "reSearchFile - Problem with regex: ${regex}\n${error}") - endif() - #message(${output}) - set(is_matching ${output} PARENT_SCOPE) - -endfunction() - -if(NOT DEFINED CMAKE_CURRENT_LIST_DIR) - get_filename_component(CMAKE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) -endif() -if(NOT DEFINED CMAKE_CURRENT_LIST_FILENAME) - get_filename_component(CMAKE_CURRENT_LIST_FILENAME ${CMAKE_CURRENT_LIST_FILE} NAME) -endif() - # Check for non-defined var -foreach(var WRAPPING_NAMESPACE TARGET SOURCES WRAP_INT_DIR HAS_DECORATOR) +foreach(var WRAPPING_NAMESPACE TARGET SOURCES HAS_DECORATOR) if(NOT DEFINED ${var}) message(FATAL_ERROR "${var} not specified when calling ctkScriptWrapPythonQt") endif() endforeach() # Check for non-existing ${var} -foreach(var QT_QMAKE_EXECUTABLE OUTPUT_DIR PYTHON_EXECUTABLE PYTHON_LIBRARY_PATH) +foreach(var WRAPPING_SCRIPT OUTPUT_DIR PYTHON_EXECUTABLE PYTHON_LIBRARY_PATH) if(NOT EXISTS ${${var}}) message(FATAL_ERROR "Failed to find ${var}=\"${${var}}\" when calling ctkScriptWrapPythonQt") endif() endforeach() -# Clear log file -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/ctkScriptWrapPythonQt_Light_log.txt" "") - -# Convert wrapping namespace to subdir -string(REPLACE "." "_" WRAPPING_NAMESPACE_UNDERSCORE ${WRAPPING_NAMESPACE}) - # Convert ^^ separated string to list string(REPLACE "^^" ";" SOURCES "${SOURCES}") -foreach(FILE ${SOURCES}) - - # what is the filename without the extension - get_filename_component(TMP_FILENAME ${FILE} NAME_WE) - - set(includes - "${includes}\n#include \"${TMP_FILENAME}.h\"") - - # Extract classname - NOTE: We assume the filename matches the associated class - set(className ${TMP_FILENAME}) - #message(STATUS "FILE:${FILE}, className:${className}") - - # Extract parent classname - set(parentClassName) - - if("${parentClassName}" STREQUAL "") - # Does constructor signature is of the form: myclass() - set(regex "[^~]${className}[\\s\\n]*\\([\\s\\n]*\\)") - reSearchfile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH} ${regex} ${FILE} is_matching) - if(is_matching) - set(parentClassName "No") - log("${TMP_FILENAME} - constructor of the form: ${className}\(\)") - endif() - endif() - - if("${parentClassName}" STREQUAL "") - # Does constructor signature is of the form: myclass(QObject * parent ...) - set(regex "${className}[\\s\\n]*\\([\\s\\n]*QObject[\\s\\n]*\\*[\\s\\n]*\\w+[\\s\\n]*(\\=[\\s\\n]*(0|NULL)|,.*\\=.*\\)|\\))") - reSearchfile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH} ${regex} ${FILE} is_matching) - if(is_matching) - set(parentClassName "QObject") - log("${TMP_FILENAME} - constructor of the form: ${className}\(QObject * parent ... \)") - endif() - endif() - - if("${parentClassName}" STREQUAL "") - # Does constructor signature is of the form: myclass(QWidget * parent ...) - set(regex "${className}[\\s\\n]*\\([\\s\\n]*QWidget[\\s\\n]*\\*[\\s\\n]*\\w+[\\s\\n]*(\\=[\\s\\n]*(0|NULL)|,.*\\=.*\\)|\\))") - reSearchfile(${PYTHON_EXECUTABLE} ${PYTHON_LIBRARY_PATH} ${regex} ${FILE} is_matching) - if(is_matching) - set(parentClassName "QWidget") - log("${TMP_FILENAME} - constructor of the form: ${className}\(QWidget * parent ... \)") - endif() - endif() - - # Generate PythonQtWrapper class - if("${parentClassName}" STREQUAL "QObject" OR "${parentClassName}" STREQUAL "QWidget") - - set(pythonqtWrappers - "${pythonqtWrappers} -//----------------------------------------------------------------------------- -class PythonQtWrapper_${className} : public QObject -{ -Q_OBJECT -public: -public Q_SLOTS: - ${className}* new_${className}(${parentClassName}* parent = 0) - { - return new ${className}(parent); - } - void delete_${className}(${className}* obj) { delete obj; } -}; -") - - elseif("${parentClassName}" STREQUAL "No") - - set(pythonqtWrappers - "${pythonqtWrappers} -//----------------------------------------------------------------------------- -class Q_DECL_EXPORT PythonQtWrapper_${className} : public QObject -{ -Q_OBJECT -public: -public Q_SLOTS: - ${className}* new_${className}() - { - return new ${className}(); - } - void delete_${className}(${className}* obj) { delete obj; } -}; -") +if(WIN32) + set(ENV{PATH} ${PYTHON_LIBRARY_PATH};$ENV{PATH}) +elseif(APPLE) + set(ENV{DYLD_LIBRARY_PATH} ${PYTHON_LIBRARY_PATH}:$ENV{DYLD_LIBRARY_PATH}) +else() + set(ENV{LD_LIBRARY_PATH} ${PYTHON_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH}) +endif() - else() # Case parentClassName is empty +set(verbose 0) - message(WARNING "ctkScriptWrapPythonQt_Light - Problem wrapping ${FILE}") +set(extra_args) +if(verbose) + set(extra_args --extra-verbose) +endif() +execute_process( + COMMAND ${PYTHON_EXECUTABLE} ${WRAPPING_SCRIPT} + --target=${TARGET} --namespace=${WRAPPING_NAMESPACE} --output-dir=${OUTPUT_DIR} ${extra_args} + ${SOURCES} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE error + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +if(NOT result EQUAL 0) + message(FATAL_ERROR "Failed to wrap target: ${TARGET}\n${output}\n${error}") +else() + if(verbose) + message(${output}) endif() +endif() - # Generate code allowing to register the class metaobject and its associated "light" wrapper - set(registerclasses "${registerclasses} - PythonQt::self()->registerClass( - &${className}::staticMetaObject, \"${TARGET}\", - PythonQtCreateObject);\n") - -endforeach() - -# Write master include file -file(WRITE ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0.h "// -// File auto-generated by cmake macro ctkScriptWrapPythonQt_Light -// - -#ifndef __${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0_h -#define __${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0_h - -#include -${includes} -${pythonqtWrappers} -#endif -") - -# Write wrapper header -file(WRITE ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp "// -// File auto-generated by cmake macro ctkScriptWrapPythonQt_Light -// - -#include -#include \"${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0.h\" - -void PythonQt_init_${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}(PyObject* module) -{ - Q_UNUSED(module); - ${registerclasses} -} -") +# Convert wrapping namespace to subdir +string(REPLACE "." "_" WRAPPING_NAMESPACE_UNDERSCORE ${WRAPPING_NAMESPACE}) -# Configure 'ctkMacroWrapPythonQtModuleInit.cpp.in' replacing TARGET and +# Configure 'ctkMacroWrapPythonQtModuleInit.cpp.in' using TARGET, HAS_DECORATOR and # WRAPPING_NAMESPACE_UNDERSCORE. configure_file( ${CMAKE_CURRENT_LIST_DIR}/ctkMacroWrapPythonQtModuleInit.cpp.in ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_module_init.cpp ) -# Since file(WRITE ) doesn't update the timestamp - Let's touch the files -execute_process( - COMMAND ${CMAKE_COMMAND} -E touch - ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp - ) diff --git a/CMake/ctkWrapPythonQt.py b/CMake/ctkWrapPythonQt.py new file mode 100644 index 0000000000..614182f526 --- /dev/null +++ b/CMake/ctkWrapPythonQt.py @@ -0,0 +1,228 @@ + +import errno +import os +import re +from string import Template + +PYTHONQT_WRAPPER_WITH_PARENT = Template(""" +//----------------------------------------------------------------------------- +class PythonQtWrapper_${className} : public QObject +{ +Q_OBJECT +public: +public Q_SLOTS: + ${className}* new_${className}(${parentClassName}* parent = 0) + { + return new ${className}(parent); + } + void delete_${className}(${className}* obj) { delete obj; } +}; +""") + +PYTHONQT_WRAPPER_WITHOUT_PARENT = Template(""" +//----------------------------------------------------------------------------- +class PythonQtWrapper_${className} : public QObject +{ +Q_OBJECT +public: +public Q_SLOTS: + ${className}* new_${className}() + { + return new ${className}(); + } + void delete_${className}(${className}* obj) { delete obj; } +}; +""") + +def _mkdir_p(path): + """See """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +def ctk_wrap_pythonqt(target, namespace, output_dir, input_files, extra_verbose): + if extra_verbose: + print("target: %s" % target) + print("namespace: %s" % namespace) + print("output_dir: %s" % output_dir) + print("input_files: %s" % input_files) + + _mkdir_p(output_dir) + + includes = [] + pythonqtWrappers = [] + registerclasses = [] + namespace = namespace.replace('.', '_') + + for input_file in input_files: + filename = os.path.basename(input_file) + if extra_verbose: + print("Wrapping %s" % filename) + + # what is the filename without the extension + filename_we = os.path.splitext(filename)[0] + + includes.append('#include "%s.h"' % filename_we) + + # Extract classname - NOTE: We assume the filename matches the associated class + className = filename_we + if extra_verbose: + print("\tclassName:%s" % className) + + # Extract parent classname + parentClassName = None + + # Read input files + with open(input_file) as f: + content = f.read() + + # Skip wrapping if file do NOT contain Q_OBJECT + if 'Q_OBJECT' not in content: + if extra_verbose: + print("\tskipping - No Q_OBJECT macro") + continue + + # Skip wrapping if constructor doesn't match: + # my_class() + # my_class(QObject* newParent ...) + # my_class(QWidget* newParent ...) + # Constructor with either QWidget or QObject as first parameter + regex = r"[^~]%s[\s\n]*\([\s\n]*((QObject|QWidget)[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\)|\)))" % className + res = re.search(regex, content, re.MULTILINE) + if res is None: + if extra_verbose: + print("\tskipping - Missing expected constructor signature") + continue + + # Skip wrapping if object has a virtual pure method + # "x3b" is the unicode for semicolon + regex = r"virtual[\w\n\s\*\(\)]+\=[\s\n]*(0|NULL)[\s\n]*\x3b" + res = re.search(regex, content, re.MULTILINE) + if res is not None: + if extra_verbose: + print("skipping - Contains a virtual pure method") + continue + + if parentClassName is None: + # Does constructor signature is of the form: myclass() + regex = r"[^~]%s[\s\n]*\([\s\n]*\)" % className + res = re.search(regex, content, re.MULTILINE) + + if res is not None: + parentClassName = "" + if extra_verbose: + print("\tconstructor of the form: %s()" % className) + + if parentClassName is None: + # Does constructor signature is of the form: myclass(QObject * parent ...) + regex = r"%s[\s\n]*\([\s\n]*QObject[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\))" % className + res = re.search(regex, content, re.MULTILINE) + if res is not None: + parentClassName = "QObject" + if extra_verbose: + print("\tconstructor of the form: %s(QObject * parent ... )" % className) + + if parentClassName is None: + # Does constructor signature is of the form: myclass(QWidget * parent ...) + regex = r"%s[\s\n]*\([\s\n]*QWidget[\s\n]*\*[\s\n]*\w+[\s\n]*(\=[\s\n]*(0|NULL)|,.*\=.*\)|\))" % className + res = re.search(regex, content, re.MULTILINE) + if res is not None: + parentClassName = "QWidget" + if extra_verbose: + print("\tconstructor of the form: %s(QWidget * parent ... )" % className) + + # Generate PythonQtWrapper class + if parentClassName == "QObject" or parentClassName == "QWidget": + pythonqtWrappers.append( + PYTHONQT_WRAPPER_WITH_PARENT.substitute(className = className, parentClassName = parentClassName)) + + elif parentClassName == "": + pythonqtWrappers.append(PYTHONQT_WRAPPER_WITHOUT_PARENT.substitute(className = className)) + + else: # Case parentClassName is None + raise Exception("Problem wrapping %s" % input_file) + + # Generate code allowing to register the class metaobject and its associated "light" wrapper + registerclasses.append( + Template(""" + PythonQt::self()->registerClass( + &${className}::staticMetaObject, "${target}", + PythonQtCreateObject); + """).substitute(className = className, target = target)) + + output_header = output_dir + "/" + namespace + "_" + target + "0.h" + if extra_verbose: + print("output_header: %s" % output_header) + # Write master include file + with open(output_header, "w") as f: + f.write(Template( +""" +// +// File auto-generated by ctkWrapPythonQt.py +// + +#ifndef __${namespace}_${target}0_h +#define __${namespace}_${target}0_h + +#include +${includes} +${pythonqtWrappers} +#endif +""").substitute(namespace = namespace, target = target, includes = '\n'.join(includes), pythonqtWrappers = '\n'.join(pythonqtWrappers))) + + output_cpp = output_dir + "/" + namespace + "_" + target + "_init.cpp" + if extra_verbose: + print("output_cpp: %s" % output_cpp) + with open(output_cpp , "w") as f: + # Write wrapper header + f.write(Template( +""" +// +// File auto-generated by ctkWrapPythonQt.py +// + +#include +#include "${namespace}_${target}0.h" + +void PythonQt_init_${namespace}_${target}(PyObject* module) +{ + Q_UNUSED(module); + ${registerclasses} +} +""").substitute(namespace = namespace, target = target, registerclasses = '\n'.join(registerclasses))) + +if __name__ == '__main__': + from optparse import OptionParser + usage = "usage: %prog [options] [ [...]]" + parser = OptionParser(usage=usage) + parser.add_option("-t", "--target", + dest="target", action="store", type="string", + help="Name of the associated library") + parser.add_option("-n", "--namespace", + dest="namespace", action="store", type="string", + help="Wrapping namespace") + parser.add_option("--output-dir", + dest="output_dir", action="store", type="string", + help="Output directory") + parser.add_option("-v", "--verbose", + dest="verbose", action="store_true", + help="Print verbose information") + parser.add_option("--extra-verbose", + dest="extra_verbose", action="store_true", + help="Print extra verbose information") + + (options, args) = parser.parse_args() + + #if len(args) < 2: + # parser.error("arguments '%s' are required !" % ' ') + + if options.extra_verbose: + options.verbose = True + + ctk_wrap_pythonqt(options.target, options.namespace, options.output_dir, args, options.extra_verbose) + + if options.verbose: + print("Wrapped %d files" % len(args))