ctkScriptWrapPythonQt_Light.cmake 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. ###########################################################################
  2. #
  3. # Library: CTK
  4. #
  5. # Copyright (c) 2010 Kitware Inc.
  6. #
  7. # Licensed under the Apache License, Version 2.0 (the "License");
  8. # you may not use this file except in compliance with the License.
  9. # You may obtain a copy of the License at
  10. #
  11. # http://www.commontk.org/LICENSE
  12. #
  13. # Unless required by applicable law or agreed to in writing, software
  14. # distributed under the License is distributed on an "AS IS" BASIS,
  15. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. # See the License for the specific language governing permissions and
  17. # limitations under the License.
  18. #
  19. ###########################################################################
  20. #
  21. # ctkScriptWrapPythonQt_Light
  22. #
  23. #
  24. # Depends on:
  25. # CTK/CMake/ctkMacroWrapPythonQt.cmake
  26. #
  27. #
  28. # This script should be invoked either as a CUSTOM_COMMAND
  29. # or from the command line using the following syntax:
  30. #
  31. # cmake -DWRAPPING_NAMESPACE:STRING=org.commontk -DTARGET:STRING=MyLib
  32. # -DSOURCES:STRING="file1^^file2" -DINCLUDE_DIRS:STRING=/path1:/path2
  33. # -DWRAP_INT_DIR:STRING=subir/subir/
  34. # -DOUTPUT_DIR:PATH=/path -DQT_QMAKE_EXECUTABLE:PATH=/path/to/qt/qmake
  35. # -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python
  36. # -P ctkScriptWrapPythonQt_Light.cmake
  37. #
  38. #
  39. # LOG FILE:
  40. # File ctkScriptWrapPythonQt_Light_log.txt will be created in the current directory.
  41. # It will contain the list of class and the constructor signature that will be wrapped.
  42. #
  43. set(verbose 0)
  44. #
  45. # Convenient function allowing to log the reason why a given class hasn't been wrapped
  46. # If verbose=1, it will also be displayed on the standard output
  47. #
  48. FUNCTION(log msg)
  49. IF(verbose)
  50. MESSAGE(${msg})
  51. ENDIF()
  52. FILE(APPEND "${CMAKE_CURRENT_BINARY_DIR}/ctkScriptWrapPythonQt_Light_log.txt" "${msg}\n")
  53. ENDFUNCTION()
  54. #
  55. # Convenient function allowing to invoke re.search(regex, string) using the given interpreter.
  56. # Note that is_matching will be set to True if there is a match
  57. #
  58. FUNCTION(reSearchFile python_exe regex file is_matching)
  59. set(python_cmd "import re\; f = open('${file}', 'r')\;
  60. res = re.search\(\"${regex}\", f.read(), re.MULTILINE\)\;
  61. if res == None: print \"FALSE\"
  62. else: print \"TRUE\"
  63. ")
  64. #message("python_cmd: ${python_cmd}")
  65. EXECUTE_PROCESS(
  66. COMMAND ${python_exe} -c ${python_cmd};
  67. RESULT_VARIABLE result
  68. OUTPUT_VARIABLE output
  69. ERROR_VARIABLE error
  70. OUTPUT_STRIP_TRAILING_WHITESPACE
  71. )
  72. IF(result)
  73. MESSAGE(SEND_ERROR "reSearchFile - Problem with regex: ${regex}\n${error}")
  74. ENDIF()
  75. #message(${output})
  76. SET(is_matching ${output} PARENT_SCOPE)
  77. ENDFUNCTION()
  78. # Check for non-defined var
  79. FOREACH(var WRAPPING_NAMESPACE TARGET SOURCES INCLUDE_DIRS WRAP_INT_DIR)
  80. IF(NOT DEFINED ${var})
  81. MESSAGE(SEND_ERROR "${var} not specified when calling ctkScriptWrapPythonQt")
  82. ENDIF()
  83. ENDFOREACH()
  84. # Check for non-existing ${var}
  85. FOREACH(var QT_QMAKE_EXECUTABLE OUTPUT_DIR PYTHON_EXECUTABLE)
  86. IF(NOT EXISTS ${${var}})
  87. MESSAGE(SEND_ERROR "Failed to find ${var} when calling ctkScriptWrapPythonQt")
  88. ENDIF()
  89. ENDFOREACH()
  90. # Clear log file
  91. FILE(WRITE "${CMAKE_CURRENT_BINARY_DIR}/ctkScriptWrapPythonQt_Light_log.txt" "")
  92. # Convert wrapping namespace to subdir
  93. STRING(REPLACE "." "_" WRAPPING_NAMESPACE_UNDERSCORE ${WRAPPING_NAMESPACE})
  94. # Convert ^^ separated string to list
  95. STRING(REPLACE "^^" ";" SOURCES "${SOURCES}")
  96. FOREACH(FILE ${SOURCES})
  97. # what is the filename without the extension
  98. GET_FILENAME_COMPONENT(TMP_FILENAME ${FILE} NAME_WE)
  99. SET(includes
  100. "${includes}\n#include \"${TMP_FILENAME}.h\"")
  101. # Extract classname - NOTE: We assume the filename matches the associated class
  102. set(className ${TMP_FILENAME})
  103. #message(STATUS "FILE:${FILE}, className:${className}")
  104. # Extract parent classname
  105. SET(parentClassName)
  106. IF("${parentClassName}" STREQUAL "")
  107. # Does constructor signature is of the form: myclass()
  108. SET(regex "[^~]${className}[\\s\\n]*\\([\\s\\n]*\\)")
  109. reSearchFile(${PYTHON_EXECUTABLE} ${regex} ${FILE} is_matching)
  110. IF(is_matching)
  111. SET(parentClassName "No")
  112. log("${TMP_FILENAME} - constructor of the form: ${className}\(\)")
  113. ENDIF()
  114. ENDIF()
  115. IF("${parentClassName}" STREQUAL "")
  116. # Does constructor signature is of the form: myclass(QObject * parent ...)
  117. SET(regex "${className}[\\s\\n]*\\([\\s\\n]*QObject[\\s\\n]*\\*[\\s\\n]*\\w+[\\s\\n]*(\\=[\\s\\n]*(0|NULL)|,.*\\=.*\\)|\\))")
  118. reSearchFile(${PYTHON_EXECUTABLE} ${regex} ${FILE} is_matching)
  119. IF(is_matching)
  120. SET(parentClassName "QObject")
  121. log("${TMP_FILENAME} - constructor of the form: ${className}\(QObject * parent ... \)")
  122. ENDIF()
  123. ENDIF()
  124. IF("${parentClassName}" STREQUAL "")
  125. # Does constructor signature is of the form: myclass(QWidget * parent ...)
  126. SET(regex "${className}[\\s\\n]*\\([\\s\\n]*QWidget[\\s\\n]*\\*[\\s\\n]*\\w+[\\s\\n]*(\\=[\\s\\n]*(0|NULL)|,.*\\=.*\\)|\\))")
  127. reSearchFile(${PYTHON_EXECUTABLE} ${regex} ${FILE} is_matching)
  128. IF(is_matching)
  129. SET(parentClassName "QWidget")
  130. log("${TMP_FILENAME} - constructor of the form: ${className}\(QWidget * parent ... \)")
  131. ENDIF()
  132. ENDIF()
  133. # Generate PythonQtWrapper class
  134. IF("${parentClassName}" STREQUAL "QObject" OR "${parentClassName}" STREQUAL "QWidget")
  135. SET(pythonqtWrappers
  136. "${pythonqtWrappers}
  137. //-----------------------------------------------------------------------------
  138. class PythonQtWrapper_${className} : public QObject
  139. {
  140. Q_OBJECT
  141. public:
  142. public slots:
  143. ${className}* new_${className}(${parentClassName}* parent = 0)
  144. {
  145. return new ${className}(parent);
  146. }
  147. void delete_${className}(${className}* obj) { delete obj; }
  148. };
  149. ")
  150. ELSEIF("${parentClassName}" STREQUAL "No")
  151. SET(pythonqtWrappers
  152. "${pythonqtWrappers}
  153. //-----------------------------------------------------------------------------
  154. class PythonQtWrapper_${className} : public QObject
  155. {
  156. Q_OBJECT
  157. public:
  158. public slots:
  159. ${className}* new_${className}()
  160. {
  161. return new ${className}();
  162. }
  163. void delete_${className}(${className}* obj) { delete obj; }
  164. };
  165. ")
  166. ELSE() # Case parentClassName is empty
  167. MESSAGE(WARNING "ctkScriptWrapPythonQt_Light - Problem wrapping ${FILE}")
  168. ENDIF()
  169. # Generate code allowing to register the class metaobject and its associated "light" wrapper
  170. SET(registerclasses "${registerclasses}
  171. PythonQt::self()->registerClass(
  172. &${className}::staticMetaObject, \"${TARGET}\",
  173. PythonQtCreateObject<PythonQtWrapper_${className}>);\n")
  174. ENDFOREACH()
  175. # Write master include file
  176. FILE(WRITE ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0.h "//
  177. // File auto-generated by cmake macro ctkScriptWrapPythonQt_Light
  178. //
  179. #ifndef __${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0_h
  180. #define __${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0_h
  181. #include <QWidget>
  182. ${includes}
  183. ${pythonqtWrappers}
  184. #endif
  185. ")
  186. # Write wrapper header
  187. FILE(WRITE ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp "//
  188. // File auto-generated by cmake macro ctkScriptWrapPythonQt_Light
  189. //
  190. #include <PythonQt.h>
  191. #include \"${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}0.h\"
  192. void PythonQt_init_${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}(PyObject* module)
  193. {
  194. Q_UNUSED(module);
  195. ${registerclasses}
  196. }
  197. ")
  198. # Since FILE(WRITE ) doesn't update the timestamp - Let's touch the files
  199. EXECUTE_PROCESS(
  200. COMMAND ${CMAKE_COMMAND} -E touch
  201. ${OUTPUT_DIR}/${WRAP_INT_DIR}${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_init.cpp
  202. )