|
@@ -0,0 +1,305 @@
|
|
|
+###########################################################################
|
|
|
+#
|
|
|
+# Library: CTK
|
|
|
+#
|
|
|
+# Copyright (c) 2010 Kitware Inc.
|
|
|
+#
|
|
|
+# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+# you may not use this file except in compliance with the License.
|
|
|
+# You may obtain a copy of the License at
|
|
|
+#
|
|
|
+# http://www.commontk.org/LICENSE
|
|
|
+#
|
|
|
+# Unless required by applicable law or agreed to in writing, software
|
|
|
+# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+# See the License for the specific language governing permissions and
|
|
|
+# limitations under the License.
|
|
|
+#
|
|
|
+###########################################################################
|
|
|
+
|
|
|
+#
|
|
|
+# ctkMacroWrapPythonQt
|
|
|
+#
|
|
|
+
|
|
|
+#
|
|
|
+# Depends on:
|
|
|
+# PythonQt
|
|
|
+# PythonQtGenerator (Only if IS_WRAP_FULL is TRUE)
|
|
|
+# PythonInterp (See function reSearchFile)
|
|
|
+#
|
|
|
+
|
|
|
+#
|
|
|
+# The different parameters are:
|
|
|
+#
|
|
|
+# WRAPPING_NAMESPACE: Namespace that should contain the library. For example: org.commontk
|
|
|
+#
|
|
|
+# TARGET ...........: Name of the wrapped library. For example: CTKWidget
|
|
|
+#
|
|
|
+# SRCS_LIST_NAME ...: Name of the variable that should contain the generated wrapper source.
|
|
|
+# For example: KIT_PYTHONQT_SRCS
|
|
|
+#
|
|
|
+# SOURCES ..........: List of source files that should be wrapped.
|
|
|
+#
|
|
|
+# IS_WRAP_FULL .....: Indicate if a Full wrapping if desired.
|
|
|
+#
|
|
|
+
|
|
|
+#
|
|
|
+# LOG FILE:
|
|
|
+# File ctkMacroWrapPythonQt_log.txt will be created in the current directory.
|
|
|
+# It will contain the list of file and the reason why a given class hasn't been 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(ctkMacroWrapPythonQt_log msg)
|
|
|
+ IF(verbose)
|
|
|
+ MESSAGE(${msg})
|
|
|
+ ENDIF()
|
|
|
+ FILE(APPEND "${CMAKE_CURRENT_BINARY_DIR}/ctkMacroWrapPythonQt_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(ctkMacroWrapPythonQt_reSearchFile python_exe 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}")
|
|
|
+
|
|
|
+ EXECUTE_PROCESS(
|
|
|
+ COMMAND ${python_exe} -c ${python_cmd};
|
|
|
+ RESULT_VARIABLE result
|
|
|
+ OUTPUT_VARIABLE output
|
|
|
+ ERROR_VARIABLE error
|
|
|
+ OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
|
+ )
|
|
|
+
|
|
|
+ IF(result)
|
|
|
+ MESSAGE(SEND_ERROR "reSearchFile - Problem with regex: ${regex}\n${error}")
|
|
|
+ ENDIF()
|
|
|
+ SET(is_matching ${output} PARENT_SCOPE)
|
|
|
+ENDFUNCTION()
|
|
|
+
|
|
|
+MACRO(ctkMacroWrapPythonQt WRAPPING_NAMESPACE TARGET SRCS_LIST_NAME SOURCES IS_WRAP_FULL)
|
|
|
+
|
|
|
+ # Sanity check
|
|
|
+ IF(IS_WRAP_FULL AND NOT EXISTS "${PYTHONQTGENERATOR_EXECUTABLE}")
|
|
|
+ MESSAGE(SEND_ERROR "PYTHONQTGENERATOR_EXECUTABLE not specified or inexistent when calling ctkMacroWrapPythonQt")
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ find_package(PythonInterp)
|
|
|
+ IF(NOT EXISTS "${PYTHON_EXECUTABLE}")
|
|
|
+ MESSAGE(SEND_ERROR "PYTHON_EXECUTABLE not specified or inexistent when calling ctkMacroWrapPythonQt")
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ # Clear log file
|
|
|
+ FILE(WRITE "${CMAKE_CURRENT_BINARY_DIR}/ctkMacroWrapPythonQt_log.txt" "")
|
|
|
+
|
|
|
+ # Convert wrapping namespace to subdir
|
|
|
+ STRING(REPLACE "." "_" WRAPPING_NAMESPACE_UNDERSCORE ${WRAPPING_NAMESPACE})
|
|
|
+
|
|
|
+ SET(SOURCES_TO_WRAP)
|
|
|
+ # For each class
|
|
|
+ FOREACH(FILE ${SOURCES})
|
|
|
+
|
|
|
+ SET(skip_wrapping FALSE)
|
|
|
+
|
|
|
+ IF(NOT skip_wrapping)
|
|
|
+ # Skip wrapping if file is NOT regular header
|
|
|
+ IF(NOT ${FILE} MATCHES "^.*\\.[hH]$")
|
|
|
+ SET(skip_wrapping TRUE)
|
|
|
+ ctkMacroWrapPythonQt_log("${FILE}: skipping - Not a regular header")
|
|
|
+ ENDIF()
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ IF(NOT skip_wrapping)
|
|
|
+ # Skip wrapping if file is a pimpl header
|
|
|
+ IF(${FILE} MATCHES "^.*_[pP]\\.[hH]$")
|
|
|
+ SET(skip_wrapping TRUE)
|
|
|
+ ctkMacroWrapPythonQt_log("${FILE}: skipping - Pimpl header (*._p.h)")
|
|
|
+ ENDIF()
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ IF(NOT skip_wrapping)
|
|
|
+ # Skip wrapping if file should excluded
|
|
|
+ SET(skip_wrapping TRUE)
|
|
|
+ GET_SOURCE_FILE_PROPERTY(TMP_WRAP_EXCLUDE ${FILE} WRAP_EXCLUDE)
|
|
|
+ IF(NOT TMP_WRAP_EXCLUDE)
|
|
|
+ SET(skip_wrapping FALSE)
|
|
|
+ ENDIF()
|
|
|
+ IF(skip_wrapping)
|
|
|
+ ctkMacroWrapPythonQt_log("${FILE}: skipping - WRAP_EXCLUDE")
|
|
|
+ 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 IS_WRAP_FULL=FALSE and if file do NOT contain Q_OBJECT
|
|
|
+ IF(NOT IS_WRAP_FULL)
|
|
|
+ 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()
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ IF(NOT skip_wrapping)
|
|
|
+ # Skip wrapping if IS_WRAP_FULL=FALSE and if constructor doesn't match:
|
|
|
+ # my_class()
|
|
|
+ # my_class(QObject* newParent ...)
|
|
|
+ # my_class(QWidget* newParent ...)
|
|
|
+ IF(NOT IS_WRAP_FULL)
|
|
|
+ # 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} ${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()
|
|
|
+ ENDIF()
|
|
|
+
|
|
|
+ IF(NOT skip_wrapping)
|
|
|
+ # Skip wrapping if object has a virtual pure method
|
|
|
+ SET(regex "virtual[\\w\\n\\s\\(\\)]+\\=[\\s\\n]*(0|NULL)[\\s\\n]*\\x3b")
|
|
|
+ ctkMacroWrapPythonQt_reSearchFile(${PYTHON_EXECUTABLE} ${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)
|
|
|
+
|
|
|
+ # the input file might be full path so handle that
|
|
|
+ GET_FILENAME_COMPONENT(TMP_FILEPATH ${FILE} PATH)
|
|
|
+
|
|
|
+ # compute the input filename
|
|
|
+ IF (TMP_FILEPATH)
|
|
|
+ SET(TMP_INPUT ${TMP_FILEPATH}/${TMP_FILENAME}.h)
|
|
|
+ ELSE (TMP_FILEPATH)
|
|
|
+ SET(TMP_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/${TMP_FILENAME}.h)
|
|
|
+ ENDIF (TMP_FILEPATH)
|
|
|
+
|
|
|
+ LIST(APPEND SOURCES_TO_WRAP ${TMP_INPUT})
|
|
|
+
|
|
|
+ ENDIF()
|
|
|
+ ENDFOREACH()
|
|
|
+
|
|
|
+ # PythonQtGenerator expects a colon ':' separated list
|
|
|
+ SET(INCLUDE_DIRS_TO_WRAP)
|
|
|
+ FOREACH(include ${CTK_BASE_INCLUDE_DIRS})
|
|
|
+ SET(INCLUDE_DIRS_TO_WRAP "${INCLUDE_DIRS_TO_WRAP}:${include}")
|
|
|
+ ENDFOREACH()
|
|
|
+
|
|
|
+ # Prepare custom_command argument
|
|
|
+ SET(SOURCES_TO_WRAP_ARG)
|
|
|
+ FOREACH(source ${SOURCES_TO_WRAP})
|
|
|
+ SET(SOURCES_TO_WRAP_ARG "${SOURCES_TO_WRAP_ARG}^^${source}")
|
|
|
+ ENDFOREACH()
|
|
|
+
|
|
|
+ # Define wrap type and wrap intermediate directory
|
|
|
+ SET(wrap_type "Light")
|
|
|
+ SET(wrap_int_dir generated_cpp/${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}/)
|
|
|
+ SET(extra_files )
|
|
|
+ IF(${IS_WRAP_FULL})
|
|
|
+ SET(wrap_type "Full")
|
|
|
+ SET(extra_files ${wrap_int_dir}ctkPythonQt_${TARGET}_masterinclude.h)
|
|
|
+ ENDIF()
|
|
|
+ #message("wrap_type:${wrap_type} - 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})
|
|
|
+
|
|
|
+ # 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
|
|
|
+ COMMAND ${CMAKE_COMMAND}
|
|
|
+ -DPYTHONQTGENERATOR_EXECUTABLE:FILEPATH=${PYTHONQTGENERATOR_EXECUTABLE}
|
|
|
+ -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}
|
|
|
+ -DWRAPPING_NAMESPACE:STRING=${WRAPPING_NAMESPACE}
|
|
|
+ -DTARGET:STRING=${TARGET}
|
|
|
+ -DSOURCES:STRING=${SOURCES_TO_WRAP_ARG}
|
|
|
+ -DINCLUDE_DIRS:STRING=${INCLUDE_DIRS_TO_WRAP}
|
|
|
+ -DOUTPUT_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}
|
|
|
+ -DWRAP_INT_DIR:STRING=${wrap_int_dir}
|
|
|
+ -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
|
|
|
+ -P ${CTK_CMAKE_DIR}/ctkScriptWrapPythonQt_${wrap_type}.cmake
|
|
|
+ COMMENT "PythonQt ${wrap_type} Wrapping - Generating ${wrapper_init_cpp_filename}"
|
|
|
+ VERBATIM
|
|
|
+ )
|
|
|
+
|
|
|
+ # Prepare custom_command argument
|
|
|
+ SET(moc_flags_arg)
|
|
|
+ FOREACH(flag ${moc_flags})
|
|
|
+ SET(moc_flags_arg "${moc_flags_arg}^^${flag}")
|
|
|
+ ENDFOREACH()
|
|
|
+
|
|
|
+ # Use Moc to process the wrapper headers
|
|
|
+ QT4_GET_MOC_FLAGS(moc_flags)
|
|
|
+
|
|
|
+ SET(wrapper_master_moc_filename moc_${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET}_all.cpp)
|
|
|
+ SET(wrapper_master_moc_file ${CMAKE_CURRENT_BINARY_DIR}/${wrap_int_dir}${wrapper_master_moc_filename})
|
|
|
+
|
|
|
+ # 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
|
|
|
+ COMMAND ${CMAKE_COMMAND}
|
|
|
+ -DWRAPPING_NAMESPACE:STRING=${WRAPPING_NAMESPACE}
|
|
|
+ -DTARGET:STRING=${TARGET}
|
|
|
+ -DMOC_FLAGS:STRING=${moc_flags_arg}
|
|
|
+ -DWRAP_INT_DIR:STRING=${wrap_int_dir}
|
|
|
+ -DWRAPPER_MASTER_MOC_FILE:STRING=${wrapper_master_moc_file}
|
|
|
+ -DOUTPUT_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}
|
|
|
+ -DQT_MOC_EXECUTABLE:FILEPATH=${QT_MOC_EXECUTABLE}
|
|
|
+ -P ${CTK_CMAKE_DIR}/ctkScriptMocPythonQtWrapper.cmake
|
|
|
+ COMMENT "PythonQt ${wrap_type} Wrapping - Moc'ing ${WRAPPING_NAMESPACE_UNDERSCORE}_${TARGET} wrapper headers"
|
|
|
+ VERBATIM
|
|
|
+ )
|
|
|
+
|
|
|
+ #The following files are generated
|
|
|
+ SET_SOURCE_FILES_PROPERTIES(
|
|
|
+ ${wrap_int_dir}${wrapper_init_cpp_filename}
|
|
|
+ ${wrap_int_dir}${wrapper_master_moc_filename}
|
|
|
+ PROPERTIES GENERATED TRUE)
|
|
|
+
|
|
|
+ # Create the Init File
|
|
|
+ SET(${SRCS_LIST_NAME}
|
|
|
+ ${${SRCS_LIST_NAME}}
|
|
|
+ ${wrap_int_dir}${wrapper_init_cpp_filename}
|
|
|
+ ${wrap_int_dir}${wrapper_master_moc_filename})
|
|
|
+
|
|
|
+ #
|
|
|
+ # Let's include the headers associated with PythonQt
|
|
|
+ #
|
|
|
+ FIND_PACKAGE(PythonQt)
|
|
|
+ IF(NOT PYTHONQT_FOUND)
|
|
|
+ MESSAGE(FATAL_ERROR "error: PythonQt package is required to build ${TARGET}PythonQt")
|
|
|
+ ENDIF()
|
|
|
+ INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS} ${PYTHONQT_INCLUDE_DIR})
|
|
|
+
|
|
|
+ENDMACRO()
|
|
|
+
|