Commit 71631f90 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Add cmake modules for finding python, sip and pyqt

parent 505fa128
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Find PyQt5
# ~~~~~~~~~~
# Copyright (c) 2014, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# PyQt5 website: http://www.riverbankcomputing.co.uk/pyqt/index.php
#
# Find the installed version of PyQt5. FindPyQt5 should only be called after
# Python has been found.
#
# This file defines the following variables:
#
# PYQT5_VERSION - The version of PyQt5 found expressed as a 6 digit hex number
# suitable for comparison as a string
#
# PYQT5_VERSION_STR - The version of PyQt5 as a human readable string.
#
# PYQT5_VERSION_TAG - The PyQt version tag using by PyQt's sip files.
#
# PYQT5_SIP_DIR - The directory holding the PyQt5 .sip files.
#
# PYQT5_SIP_FLAGS - The SIP flags used to build PyQt.
IF(EXISTS PYQT5_VERSION)
# Already in cache, be silent
SET(PYQT5_FOUND TRUE)
ELSE(EXISTS PYQT5_VERSION)
FIND_FILE(_find_pyqt5_py FindPyQt5.py PATHS ${CMAKE_MODULE_PATH})
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_pyqt5_py} OUTPUT_VARIABLE pyqt5_config)
IF(pyqt5_config)
STRING(REGEX REPLACE "^pyqt_version:([^\n]+).*$" "\\1" PYQT5_VERSION ${pyqt5_config})
STRING(REGEX REPLACE ".*\npyqt_version_str:([^\n]+).*$" "\\1" PYQT5_VERSION_STR ${pyqt5_config})
STRING(REGEX REPLACE ".*\npyqt_version_tag:([^\n]+).*$" "\\1" PYQT5_VERSION_TAG ${pyqt5_config})
STRING(REGEX REPLACE ".*\npyqt_sip_dir:([^\n]+).*$" "\\1" PYQT5_SIP_DIR ${pyqt5_config})
STRING(REGEX REPLACE ".*\npyqt_sip_flags:([^\n]+).*$" "\\1" PYQT5_SIP_FLAGS ${pyqt5_config})
SET(PYQT5_FOUND TRUE)
ENDIF(pyqt5_config)
IF(PYQT5_FOUND)
IF(NOT PYQT5_FIND_QUIETLY)
MESSAGE(STATUS "Found PyQt5 version: ${PYQT5_VERSION_STR}")
ENDIF(NOT PYQT5_FIND_QUIETLY)
ELSE(PYQT5_FOUND)
IF(PYQT5_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find PyQt5.")
ENDIF(PYQT5_FIND_REQUIRED)
ENDIF(PYQT5_FOUND)
ENDIF(EXISTS PYQT5_VERSION)
# Copyright (c) 2014, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
import PyQt5.Qt
import sys
import os.path
print("pyqt_version:%06.0x" % PyQt5.Qt.PYQT_VERSION)
print("pyqt_version_str:%s" % PyQt5.Qt.PYQT_VERSION_STR)
pyqt_version_tag = ""
in_t = False
for item in PyQt5.Qt.PYQT_CONFIGURATION["sip_flags"].split(' '):
if item=="-t":
in_t = True
elif in_t:
if item.startswith("Qt_5"):
pyqt_version_tag = item
else:
in_t = False
print("pyqt_version_tag:%s" % pyqt_version_tag)
# FIXME This next line is just a little bit too crude.
pyqt_sip_dir = os.path.join(sys.prefix, "share", "sip", "PyQt5")
print("pyqt_sip_dir:%s" % pyqt_sip_dir)
print("pyqt_sip_flags:%s" % PyQt5.Qt.PYQT_CONFIGURATION["sip_flags"])
# Find Python
# ~~~~~~~~~~~
# Find the Python interpreter and related Python directories.
#
# This file defines the following variables:
#
# PYTHON_EXECUTABLE - The path and filename of the Python interpreter.
#
# PYTHON_SHORT_VERSION - The version of the Python interpreter found,
# excluding the patch version number. (e.g. 2.5 and not 2.5.1))
#
# PYTHON_LONG_VERSION - The version of the Python interpreter found as a human
# readable string.
#
# PYTHON_SITE_PACKAGES_INSTALL_DIR - this cache variable can be used for installing
# own python modules. You may want to adjust this to be the
# same as ${PYTHON_SITE_PACKAGES_DIR}, but then admin
# privileges may be required for installation.
#
# PYTHON_SITE_PACKAGES_DIR - Location of the Python site-packages directory.
#
# PYTHON_INCLUDE_PATH - Directory holding the python.h include file.
#
# PYTHON_LIBRARY, PYTHON_LIBRARIES- Location of the Python library.
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Copyright (c) 2012, Luca Beltrame <lbeltrame@kde.org>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
include(FindPackageHandleStandardArgs)
find_package(PythonInterp)
if (PYTHONINTERP_FOUND)
option(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX "Install the Python files in the Python packages dir" FALSE)
# Set the Python libraries to what we actually found for interpreters
set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
# These are kept for compatibility
set(PYTHON_SHORT_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
set(PYTHON_LONG_VERSION ${PYTHON_VERSION_STRING})
find_package(PythonLibs QUIET)
if(PYTHONLIBS_FOUND)
set(PYTHON_LIBRARY ${PYTHON_LIBRARIES})
endif(PYTHONLIBS_FOUND)
# Auto detect Python site-packages directory
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))"
OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "Python system site-packages directory: ${PYTHON_SITE_PACKAGES_DIR}")
if(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX)
set(PYTHON_SITE_PACKAGES_INSTALL_DIR ${PYTHON_SITE_PACKAGES_DIR})
else()
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True, prefix='${CMAKE_INSTALL_PREFIX}'))"
OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_INSTALL_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
if(NOT PYTHON_SITE_PACKAGES_INSTALL_DIR STREQUAL PYTHON_SITE_PACKAGES_DIR)
message(STATUS "The Python files will be installed to ${PYTHON_SITE_PACKAGES_INSTALL_DIR}. Make sure to add them to the Python search path (e.g. by setting PYTHONPATH)")
endif()
endif(PYTHONINTERP_FOUND)
find_package_handle_standard_args(PythonLibrary DEFAULT_MSG PYTHON_LIBRARY)
# Find SIP
# ~~~~~~~~
#
# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
#
# Find the installed version of SIP. FindSIP should be called after Python
# has been found.
#
# This file defines the following variables:
#
# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number
# suitable for comparison as a string.
#
# SIP_VERSION_STR - The version of SIP found as a human readable string.
#
# SIP_EXECUTABLE - Path and filename of the SIP command line executable.
#
# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file.
#
# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed
# into.
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF(SIP_VERSION)
# Already in cache, be silent
SET(SIP_FOUND TRUE)
ELSE(SIP_VERSION)
FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH})
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config)
IF(sip_config)
STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config})
STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_EXECUTABLE ${sip_config})
IF(NOT SIP_DEFAULT_SIP_DIR)
STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config})
ENDIF(NOT SIP_DEFAULT_SIP_DIR)
STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config})
FILE(TO_CMAKE_PATH ${SIP_DEFAULT_SIP_DIR} SIP_DEFAULT_SIP_DIR)
FILE(TO_CMAKE_PATH ${SIP_INCLUDE_DIR} SIP_INCLUDE_DIR)
IF(EXISTS ${SIP_EXECUTABLE})
SET(SIP_FOUND TRUE)
ELSE()
MESSAGE(STATUS "Found SIP configuration but the sip executable could not be found.")
ENDIF()
ENDIF(sip_config)
IF(SIP_FOUND)
IF(NOT SIP_FIND_QUIETLY)
MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}")
ENDIF(NOT SIP_FIND_QUIETLY)
ELSE(SIP_FOUND)
IF(SIP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SIP")
ENDIF(SIP_FIND_REQUIRED)
ENDIF(SIP_FOUND)
ENDIF(SIP_VERSION)
# FindSIP.py
#
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
import sys
import sipconfig
sipcfg = sipconfig.Configuration()
print("sip_version:%06.0x" % sipcfg.sip_version)
print("sip_version_str:%s" % sipcfg.sip_version_str)
print("sip_bin:%s" % sipcfg.sip_bin)
print("default_sip_dir:%s" % sipcfg.default_sip_dir)
print("sip_inc_dir:%s" % sipcfg.sip_inc_dir)
# By Simon Edwards <simon@simonzone.com>
# This file is in the public domain.
import py_compile, sys
sys.exit(py_compile.main())
# Python macros
# ~~~~~~~~~~~~~
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Copyright (c) 2012, Luca Beltrame <lbeltrame@kde.org>
# Copyright (c) 2012, Rolf Eike Beer <eike@sf-mail.de>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# This file defines the following macros:
#
# PYTHON_INSTALL (SOURCE_FILE DESTINATION_DIR)
# Install the SOURCE_FILE, which is a Python .py file, into the
# destination directory during install. The file will be byte compiled
# and both the .py file and .pyc file will be installed.
set(PYTHON_MACROS_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
macro(PYTHON_INSTALL SOURCE_FILE DESTINATION_DIR)
find_file(_python_compile_py PythonCompile.py PATHS ${CMAKE_MODULE_PATH})
# Install the source file.
install(FILES ${SOURCE_FILE} DESTINATION ${DESTINATION_DIR})
# Byte compile and install the .pyc file, unless explicitly prevented by env..
if("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "")
get_filename_component(_absfilename ${SOURCE_FILE} ABSOLUTE)
get_filename_component(_filename ${SOURCE_FILE} NAME)
get_filename_component(_filenamebase ${SOURCE_FILE} NAME_WE)
get_filename_component(_basepath ${SOURCE_FILE} PATH)
if(WIN32)
# remove drive letter
string(REGEX REPLACE "^[a-zA-Z]:/" "/" _basepath "${_basepath}")
endif(WIN32)
set(_bin_py ${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filename})
# Python 3.2 changed the pyc file location
if(PYTHON_VERSION_STRING VERSION_GREATER 3.1)
# To get the right version for suffix
set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/__pycache__/${_filenamebase}.cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}.pyc")
set(_py_install_dir "${DESTINATION_DIR}/__pycache__/")
else()
set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filenamebase}.pyc")
set(_py_install_dir "${DESTINATION_DIR}")
endif()
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_basepath})
# Setting because it will be displayed later, in compile_python_files
set(_message "Byte-compiling ${_bin_py} to ${_bin_pyc}")
string(REPLACE "/" "_" _rule_name "${_basepath}/${_bin_pyc}")
add_custom_target("${_rule_name}" ALL)
get_filename_component(_abs_bin_py ${_bin_py} ABSOLUTE)
if(_abs_bin_py STREQUAL _absfilename) # Don't copy the file onto itself.
add_custom_command(
TARGET "${_rule_name}"
COMMAND "${CMAKE_COMMAND}" -E echo "${_message}"
COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}"
DEPENDS "${_absfilename}"
)
else()
add_custom_command(
TARGET "${_rule_name}"
COMMAND "${CMAKE_COMMAND}" -E echo "${_message}"
COMMAND "${CMAKE_COMMAND}" -E copy "${_absfilename}" "${_bin_py}"
COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}"
DEPENDS "${_absfilename}"
)
endif()
install(FILES ${_bin_pyc} DESTINATION "${_py_install_dir}")
unset(_py_install_dir)
unset(_message)
endif("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "")
endmacro(PYTHON_INSTALL)
# Macros for SIP
# ~~~~~~~~~~~~~~
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
#
# This file defines the following macros:
#
# ADD_SIP_PYTHON_MODULE (MODULE_NAME MODULE_SIP [library1, libaray2, ...])
# Specifies a SIP file to be built into a Python module and installed.
# MODULE_NAME is the name of Python module including any path name. (e.g.
# os.sys, Foo.bar etc). MODULE_SIP the path and filename of the .sip file
# to process and compile. libraryN are libraries that the Python module,
# which is typically a shared library, should be linked to. The built
# module will also be install into Python's site-packages directory.
#
# The behaviour of the ADD_SIP_PYTHON_MODULE macro can be controlled by a
# number of variables:
#
# SIP_INCLUDES - List of directories which SIP will scan through when looking
# for included .sip files. (Corresponds to the -I option for SIP.)
#
# SIP_TAGS - List of tags to define when running SIP. (Corresponds to the -t
# option for SIP.)
#
# SIP_CONCAT_PARTS - An integer which defines the number of parts the C++ code
# of each module should be split into. Defaults to 8. (Corresponds to the
# -j option for SIP.)
#
# SIP_DISABLE_FEATURES - List of feature names which should be disabled
# running SIP. (Corresponds to the -x option for SIP.)
#
# SIP_EXTRA_OPTIONS - Extra command line options which should be passed on to
# SIP.
SET(SIP_INCLUDES)
SET(SIP_TAGS)
SET(SIP_CONCAT_PARTS 8)
SET(SIP_DISABLE_FEATURES)
SET(SIP_EXTRA_OPTIONS)
MACRO(ADD_SIP_PYTHON_MODULE MODULE_NAME MODULE_SIP)
SET(EXTRA_LINK_LIBRARIES ${ARGN})
STRING(REPLACE "." "/" _x ${MODULE_NAME})
GET_FILENAME_COMPONENT(_parent_module_path ${_x} PATH)
GET_FILENAME_COMPONENT(_child_module_name ${_x} NAME)
GET_FILENAME_COMPONENT(_module_path ${MODULE_SIP} PATH)
if(_module_path STREQUAL "")
set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
else(_module_path STREQUAL "")
set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_module_path}")
endif(_module_path STREQUAL "")
GET_FILENAME_COMPONENT(_abs_module_sip ${MODULE_SIP} ABSOLUTE)
# We give this target a long logical target name.
# (This is to avoid having the library name clash with any already
# install library names. If that happens then cmake dependancy
# tracking get confused.)
STRING(REPLACE "." "_" _logical_name ${MODULE_NAME})
SET(_logical_name "python_module_${_logical_name}")
FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SIP_OUTPUT_DIR}) # Output goes in this dir.
SET(_sip_includes)
FOREACH (_inc ${SIP_INCLUDES})
GET_FILENAME_COMPONENT(_abs_inc ${_inc} ABSOLUTE)
LIST(APPEND _sip_includes -I ${_abs_inc})
ENDFOREACH (_inc )
SET(_sip_tags)
FOREACH (_tag ${SIP_TAGS})
LIST(APPEND _sip_tags -t ${_tag})
ENDFOREACH (_tag)
SET(_sip_x)
FOREACH (_x ${SIP_DISABLE_FEATURES})
LIST(APPEND _sip_x -x ${_x})
ENDFOREACH (_x ${SIP_DISABLE_FEATURES})
SET(_message "-DMESSAGE=Generating CPP code for module ${MODULE_NAME}")
SET(_sip_output_files)
FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_SIP_OUTPUT_DIR}/sip${_child_module_name}part${CONCAT_NUM}.cpp )
ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
IF(NOT WIN32)
SET(TOUCH_COMMAND touch)
ELSE(NOT WIN32)
SET(TOUCH_COMMAND echo)
# instead of a touch command, give out the name and append to the files
# this is basically what the touch command does.
FOREACH(filename ${_sip_output_files})
FILE(APPEND filename "")
ENDFOREACH(filename ${_sip_output_files})
ENDIF(NOT WIN32)
ADD_CUSTOM_COMMAND(
OUTPUT ${_sip_output_files}
COMMAND ${CMAKE_COMMAND} -E echo ${message}
COMMAND ${TOUCH_COMMAND} ${_sip_output_files}
COMMAND ${SIP_EXECUTABLE} ${_sip_tags} ${_sip_x} ${SIP_EXTRA_OPTIONS} -j ${SIP_CONCAT_PARTS} -c ${CMAKE_CURRENT_SIP_OUTPUT_DIR} ${_sip_includes} ${_abs_module_sip}
DEPENDS ${_abs_module_sip} ${SIP_EXTRA_FILES_DEPEND}
)
# not sure if type MODULE could be uses anywhere, limit to cygwin for now
IF (CYGWIN)
ADD_LIBRARY(${_logical_name} MODULE ${_sip_output_files} )
ELSE (CYGWIN)
ADD_LIBRARY(${_logical_name} SHARED ${_sip_output_files} )
ENDIF (CYGWIN)
TARGET_LINK_LIBRARIES(${_logical_name} ${PYTHON_LIBRARY})
TARGET_LINK_LIBRARIES(${_logical_name} ${EXTRA_LINK_LIBRARIES})
SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES PREFIX "" OUTPUT_NAME ${_child_module_name})
INSTALL(TARGETS ${_logical_name} DESTINATION "${PYTHON_SITE_PACKAGES_INSTALL_DIR}/${_parent_module_path}")
ENDMACRO(ADD_SIP_PYTHON_MODULE)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment