1# Macros for SIP
2# ~~~~~~~~~~~~~~
3# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
4# Redistribution and use is allowed according to the terms of the BSD license.
5# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
6#
7# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
8#
9# This file defines the following macros:
10#
11# ADD_SIP_PYTHON_MODULE (MODULE_NAME MODULE_SIP [library1, libaray2, ...])
12#     Specifies a SIP file to be built into a Python module and installed.
13#     MODULE_NAME is the name of Python module including any path name. (e.g.
14#     os.sys, Foo.bar etc). MODULE_SIP the path and filename of the .sip file
15#     to process and compile. libraryN are libraries that the Python module,
16#     which is typically a shared library, should be linked to. The built
17#     module will also be install into Python's site-packages directory.
18#
19# The behavior of the ADD_SIP_PYTHON_MODULE macro can be controlled by a
20# number of variables:
21#
22# SIP_INCLUDES - List of directories which SIP will scan through when looking
23#     for included .sip files. (Corresponds to the -I option for SIP.)
24#
25# SIP_TAGS - List of tags to define when running SIP. (Corresponds to the -t
26#     option for SIP.)
27#
28# SIP_CONCAT_PARTS - An integer which defines the number of parts the C++ code
29#     of each module should be split into. Defaults to 8. (Corresponds to the
30#     -j option for SIP.)
31#
32# SIP_DISABLE_FEATURES - List of feature names which should be disabled
33#     running SIP. (Corresponds to the -x option for SIP.)
34#
35# SIP_EXTRA_OPTIONS - Extra command line options which should be passed on to
36#     SIP.
37
38# SIP_BUILD_EXTRA_OPTIONS - Extra command line options which should be passed on to
39#     sip-build.
40
41SET(SIP_INCLUDES)
42SET(SIP_TAGS)
43SET(SIP_CONCAT_PARTS 16)
44SET(SIP_DISABLE_FEATURES)
45SET(SIP_EXTRA_OPTIONS)
46SET(SIP_EXTRA_OBJECTS)
47SET(SIP_BUILD_EXTRA_OPTIONS)
48
49MACRO(GENERATE_SIP_PYTHON_MODULE_CODE MODULE_NAME MODULE_SIP SIP_FILES CPP_FILES)
50
51  STRING(REPLACE "." "/" _x ${MODULE_NAME})
52  GET_FILENAME_COMPONENT(_parent_module_path ${_x} PATH)
53  GET_FILENAME_COMPONENT(_child_module_name ${_x} NAME)
54  GET_FILENAME_COMPONENT(_module_path ${MODULE_SIP} PATH)
55  GET_FILENAME_COMPONENT(_abs_module_sip ${MODULE_SIP} ABSOLUTE)
56
57  # If this is not need anymore (using input configuration file for SIP files)
58  # SIP could be run in the source rather than in binary directory
59  SET(_configured_module_sip ${CMAKE_CURRENT_BINARY_DIR}/${_module_path}/${_module_path}.sip)
60  FOREACH (_sip_file ${SIP_FILES})
61    GET_FILENAME_COMPONENT(_sip_file_path ${_sip_file} PATH)
62    GET_FILENAME_COMPONENT(_sip_file_name_we ${_sip_file} NAME_WE)
63    FILE(RELATIVE_PATH _sip_file_relpath ${CMAKE_CURRENT_SOURCE_DIR} "${_sip_file_path}/${_sip_file_name_we}")
64    SET(_out_sip_file "${CMAKE_CURRENT_BINARY_DIR}/${_sip_file_relpath}.sip")
65    CONFIGURE_FILE(${_sip_file} ${_out_sip_file})
66  ENDFOREACH (_sip_file)
67
68  SET(_message "-DMESSAGE=Generating CPP code for module ${MODULE_NAME}")
69  SET(_sip_output_files)
70
71  # Suppress warnings
72  IF(PEDANTIC)
73    IF(MSVC)
74      ADD_DEFINITIONS(
75        /wd4189  # local variable is initialized but not referenced
76        /wd4996  # deprecation warnings (bindings re-export deprecated methods)
77        /wd4701  # potentially uninitialized variable used (sip generated code)
78        /wd4702  # unreachable code (sip generated code)
79        /wd4703  # potentially uninitialized local pointer variable 'sipType' used
80      )
81    ELSE(MSVC)
82      # disable all warnings
83      ADD_DEFINITIONS( -w -Wno-deprecated-declarations )
84      IF(NOT APPLE)
85        ADD_DEFINITIONS( -fpermissive )
86      ENDIF(NOT APPLE)
87    ENDIF(MSVC)
88  ENDIF(PEDANTIC)
89
90  IF(MSVC)
91    ADD_DEFINITIONS( /bigobj )
92  ENDIF(MSVC)
93
94  IF (SIP_BUILD_EXECUTABLE)
95
96    FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_module_path}/build/${_child_module_name})    # Output goes in this dir.
97
98    FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
99      IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
100        SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_BINARY_DIR}/${_module_path}/build/${_child_module_name}/sip${_child_module_name}part${CONCAT_NUM}.cpp )
101      ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
102    ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
103
104    SET(SIPCMD ${SIP_BUILD_EXECUTABLE} --no-protected-is-public --pep484-pyi --no-make --concatenate=${SIP_CONCAT_PARTS} --qmake=${QMAKE_EXECUTABLE} --include-dir=${CMAKE_CURRENT_BINARY_DIR} --include-dir=${PYQT5_SIP_DIR} ${SIP_BUILD_EXTRA_OPTIONS})
105
106    ADD_CUSTOM_COMMAND(
107      OUTPUT ${_sip_output_files}
108      COMMAND ${CMAKE_COMMAND} -E echo ${message}
109      COMMAND ${SIPCMD}
110      COMMAND ${CMAKE_COMMAND} -E touch ${_sip_output_files}
111      WORKING_DIRECTORY ${_module_path}
112      MAIN_DEPENDENCY ${_configured_module_sip}
113      DEPENDS ${SIP_EXTRA_FILES_DEPEND}
114      VERBATIM
115    )
116
117  ELSE (SIP_BUILD_EXECUTABLE)
118
119    FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_module_path})    # Output goes in this dir.
120
121    SET(_sip_includes)
122    FOREACH (_inc ${SIP_INCLUDES})
123      GET_FILENAME_COMPONENT(_abs_inc ${_inc} ABSOLUTE)
124      LIST(APPEND _sip_includes -I ${_abs_inc})
125    ENDFOREACH (_inc )
126
127    SET(_sip_tags)
128    FOREACH (_tag ${SIP_TAGS})
129      LIST(APPEND _sip_tags -t ${_tag})
130    ENDFOREACH (_tag)
131
132    SET(_sip_x)
133    FOREACH (_x ${SIP_DISABLE_FEATURES})
134      LIST(APPEND _sip_x -x ${_x})
135    ENDFOREACH (_x ${SIP_DISABLE_FEATURES})
136
137    FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
138      IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
139        SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_BINARY_DIR}/${_module_path}/sip${_child_module_name}part${CONCAT_NUM}.cpp )
140      ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
141    ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
142
143    SET(SIPCMD ${SIP_BINARY_PATH} ${_sip_tags} -w -e ${_sip_x} ${SIP_EXTRA_OPTIONS} -j ${SIP_CONCAT_PARTS} -c ${CMAKE_CURRENT_BINARY_DIR}/${_module_path} -I ${CMAKE_CURRENT_BINARY_DIR}/${_module_path} ${_sip_includes} ${_configured_module_sip})
144    ADD_CUSTOM_COMMAND(
145      OUTPUT ${_sip_output_files}
146      COMMAND ${CMAKE_COMMAND} -E echo ${message}
147      COMMAND ${CMAKE_COMMAND} -E touch ${_sip_output_files}
148      COMMAND ${SIPCMD}
149      MAIN_DEPENDENCY ${_configured_module_sip}
150      DEPENDS ${SIP_EXTRA_FILES_DEPEND}
151      VERBATIM
152    )
153
154  ENDIF (SIP_BUILD_EXECUTABLE)
155
156  ADD_CUSTOM_TARGET(generate_sip_${MODULE_NAME}_cpp_files DEPENDS ${_sip_output_files})
157
158  SET(CPP_FILES ${sip_output_files})
159ENDMACRO(GENERATE_SIP_PYTHON_MODULE_CODE)
160
161# Will compile and link the module
162MACRO(BUILD_SIP_PYTHON_MODULE MODULE_NAME SIP_FILES EXTRA_OBJECTS)
163  SET(EXTRA_LINK_LIBRARIES ${ARGN})
164
165  # We give this target a long logical target name.
166  # (This is to avoid having the library name clash with any already
167  # install library names. If that happens then cmake dependency
168  # tracking get confused.)
169  STRING(REPLACE "." "_" _logical_name ${MODULE_NAME})
170  SET(_logical_name "python_module_${_logical_name}")
171  GET_FILENAME_COMPONENT(_module_path ${SIP_FILES} PATH)
172
173  ADD_LIBRARY(${_logical_name} MODULE ${_sip_output_files} ${EXTRA_OBJECTS})
174  SET_PROPERTY(TARGET ${_logical_name} PROPERTY AUTOMOC OFF)
175  TARGET_INCLUDE_DIRECTORIES(${_logical_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_module_path}/build)
176
177  IF (${SIP_VERSION_STR} VERSION_LESS 5.0.0)
178    # require c++14 only -- sip breaks with newer versions due to reliance on throw(...) annotations removed in c++17
179    TARGET_COMPILE_FEATURES(${_logical_name} PRIVATE cxx_std_14)
180  ENDIF (${SIP_VERSION_STR} VERSION_LESS 5.0.0)
181
182  SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES CXX_VISIBILITY_PRESET default)
183  IF (NOT APPLE)
184    TARGET_LINK_LIBRARIES(${_logical_name} ${Python_LIBRARIES})
185  ENDIF (NOT APPLE)
186  TARGET_LINK_LIBRARIES(${_logical_name} ${EXTRA_LINK_LIBRARIES})
187  IF (APPLE)
188    SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
189  ENDIF (APPLE)
190  SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES PREFIX "" OUTPUT_NAME ${_child_module_name})
191
192  IF (WIN32)
193    SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES SUFFIX ".pyd")
194    GET_TARGET_PROPERTY(_runtime_output ${_logical_name} RUNTIME_OUTPUT_DIRECTORY)
195    ADD_CUSTOM_COMMAND(TARGET ${_logical_name} POST_BUILD
196      COMMAND ${CMAKE_COMMAND} -E echo "Copying extension ${_child_module_name}"
197      COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:${_logical_name}>" "${_runtime_output}/${_child_module_name}.pyd"
198      DEPENDS ${_logical_name}
199      )
200  ENDIF(WIN32)
201
202  INSTALL(TARGETS ${_logical_name} DESTINATION "${Python_SITEARCH}/${_parent_module_path}")
203ENDMACRO(BUILD_SIP_PYTHON_MODULE MODULE_NAME SIP_FILES EXTRA_OBJECTS)
204