Selaa lähdekoodia

PythonQt module can now be initialized as regular Python module

For example:
 * In addition to "PythonQt_init_org_commontk_CTKCore", the function
"initCTKCorePythonQt" will also be exposed.

 * If the file generated by either the light or full wrapping are
compiled into a shared library. The function "initCTKCorePythonQt" will
be automatically called if the module CTKCorePythonQt is imported.
Jean-Christophe Fillion-Robin 14 vuotta sitten
vanhempi
commit
38bcbbf69a

+ 19 - 4
CMake/ctkMacroWrapPythonQt.cmake

@@ -260,12 +260,22 @@ MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W
   
   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})
-  
+
+  set(wrapper_module_init_cpp_filename ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_module_init.cpp)
+  set(wrapper_module_init_cpp_file ${CMAKE_CURRENT_BINARY_DIR}/${wrap_int_dir}${wrapper_module_init_cpp_filename})
+
   # Custom command allow to generate ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp and 
   # associated wrappers ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}{0-N}.cpp
   ADD_CUSTOM_COMMAND(
-    OUTPUT ${wrap_int_dir}${wrapper_init_cpp_filename} ${extra_files}
-    DEPENDS ${pythonqtgenerator_executable_depends} ${SOURCES_TO_WRAP} ${CTK_CMAKE_DIR}/ctkScriptWrapPythonQt_${wrap_type}.cmake
+    OUTPUT
+      ${wrap_int_dir}${wrapper_init_cpp_filename}
+      ${wrap_int_dir}${wrapper_module_init_cpp_filename}
+      ${extra_files}
+    DEPENDS
+      ${pythonqtgenerator_executable_depends}
+      ${SOURCES_TO_WRAP}
+      ${CTK_CMAKE_DIR}/ctkScriptWrapPythonQt_${wrap_type}.cmake
+      ${CTK_CMAKE_DIR}/ctkMacroWrapPythonQtModuleInit.cpp.in
     COMMAND ${CMAKE_COMMAND}
       -DPYTHONQTGENERATOR_EXECUTABLE:FILEPATH=${PYTHONQTGENERATOR_EXECUTABLE}
       -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}
@@ -311,7 +321,10 @@ MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W
   # Custom command allowing to call moc to process the wrapper headers
   ADD_CUSTOM_COMMAND(
     OUTPUT ${wrap_int_dir}${wrapper_master_moc_filename}
-    DEPENDS ${wrap_int_dir}${wrapper_init_cpp_filename} ${extra_files} ${CTK_CMAKE_DIR}/ctkScriptMocPythonQtWrapper.cmake
+    DEPENDS
+      ${wrap_int_dir}${wrapper_init_cpp_filename}
+      ${wrap_int_dir}${wrapper_module_init_cpp_filename}
+      ${extra_files} ${CTK_CMAKE_DIR}/ctkScriptMocPythonQtWrapper.cmake
     COMMAND ${CMAKE_COMMAND}
       -DWRAPPING_NAMESPACE:STRING=${WRAPPING_NAMESPACE}
       -DTARGET:STRING=${TARGET}
@@ -328,6 +341,7 @@ MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W
   #The following files are generated
   SET_SOURCE_FILES_PROPERTIES(
     ${wrap_int_dir}${wrapper_init_cpp_filename}
+    ${wrap_int_dir}${wrapper_module_init_cpp_filename}
     ${wrap_int_dir}${wrapper_master_moc_filename}
     PROPERTIES GENERATED TRUE)
     
@@ -335,6 +349,7 @@ MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_W
   SET(${SRCS_LIST_NAME} 
     ${${SRCS_LIST_NAME}}
     ${wrap_int_dir}${wrapper_init_cpp_filename}
+    ${wrap_int_dir}${wrapper_module_init_cpp_filename}
     ${wrap_int_dir}${wrapper_master_moc_filename})
   
   #

+ 63 - 0
CMake/ctkMacroWrapPythonQtModuleInit.cpp.in

@@ -0,0 +1,63 @@
+// Configured by cmake macro @CMAKE_CURRENT_LIST_FILENAME@
+
+#include <PythonQt.h>
+#include <Python.h>
+
+#ifdef __GNUC__
+// Disable warnings related to Py_DECREF() macro
+// See http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
+// Note: Ideally the incriminated functions and macros should be fixed upstream ...
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+//-----------------------------------------------------------------------------
+static PyMethodDef Py@TARGET@PythonQt_ClassMethods[] = {
+{NULL, NULL, 0, NULL}};
+
+extern  "C" { void init@TARGET@PythonQt(); }
+
+//-----------------------------------------------------------------------------
+void copyAttributes(PyObject* orig_module, PyObject* dest_module)
+{
+  PyObject* keys = PyObject_Dir(orig_module);
+  if (keys)
+    {
+    PyObject* key;
+    PyObject* value;
+    int nKeys = PyList_Size(keys);
+    for (int i = 0; i < nKeys; ++i)
+      {
+      key = PyList_GetItem(keys, i);
+      value = PyObject_GetAttr(orig_module, key);
+      if (!value)
+        {
+        continue;
+        }
+      //printf("%s\n", PyString_AsString(key));
+      if (!PyObject_HasAttr(dest_module, key))
+        {
+        PyObject_SetAttr(dest_module, key, value);
+        }
+      Py_DECREF((void*)value);
+      }
+    Py_DECREF(keys);
+    }
+}
+
+//-----------------------------------------------------------------------------
+extern  "C" {void PythonQt_init_@WRAPPING_NAMESPACE_UNDERSCORE@_@TARGET@(PyObject*); }
+
+//-----------------------------------------------------------------------------
+void init@TARGET@PythonQt()
+{
+  static const char @TARGET@[] = "@TARGET@PythonQt";
+  PyObject *m;
+
+  m = Py_InitModule((char*)@TARGET@, Py@TARGET@PythonQt_ClassMethods);
+  PythonQt_init_@WRAPPING_NAMESPACE_UNDERSCORE@_@TARGET@(m);
+  
+  // Since invoking 'PythonQt_init_@WRAPPING_NAMESPACE_UNDERSCORE@_@TARGET@', will create 
+  // the module "PythonQt.@TARGET@". Let's copy its content into the current module.
+  PythonQtObjectPtr currentModule = PyImport_ImportModule((char*)"PythonQt.@TARGET@");
+  copyAttributes(currentModule, m);
+}

+ 14 - 1
CMake/ctkScriptWrapPythonQt_Full.cmake

@@ -39,6 +39,13 @@
 #          -P ctkScriptWrapPythonQt_Full.cmake
 #
 
+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 SOURCES TARGET INCLUDE_DIRS WRAP_INT_DIR WRAPPING_NAMESPACE)
   IF(NOT DEFINED ${var})
@@ -130,10 +137,16 @@ IF(result)
   MESSAGE(FATAL_ERROR "Failed to generate ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp\n${error}")
 ENDIF()
 
+# Configure 'ctkMacroWrapPythonQtModuleInit.cpp.in' replacing TARGET 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 PythonQtGenerator or 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
     ${OUTPUT_DIR}/${WRAP_INT_DIR}ctkPythonQt_${TARGET}_masterinclude.h
   )
-

+ 14 - 1
CMake/ctkScriptWrapPythonQt_Light.cmake

@@ -96,6 +96,12 @@ else: print \"TRUE\"
   
 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 INCLUDE_DIRS WRAP_INT_DIR)
@@ -211,7 +217,7 @@ public slots:
   # Generate code allowing to register the class metaobject and its associated "light" wrapper
   SET(registerclasses "${registerclasses}
   PythonQt::self()->registerClass(
-    &${className}::staticMetaObject, \"${TARGET}\",   
+    &${className}::staticMetaObject, \"${TARGET}\",
     PythonQtCreateObject<PythonQtWrapper_${className}>);\n")
 
 ENDFOREACH()
@@ -245,6 +251,13 @@ void PythonQt_init_${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}(PyObject* module)
 }
 ")
 
+# Configure 'ctkMacroWrapPythonQtModuleInit.cpp.in' replacing TARGET 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