blob: e55543532fba3d83874405fa35d2754b00acf7c1 [file] [log] [blame]
Vasil Velichkov487bf472018-04-25 23:25:59 +03001# - SWIG module for CMake
2# Defines the following macros:
3# SWIG_ADD_MODULE(name language [ files ])
4# - Define swig module with given name and specified language
5# SWIG_LINK_LIBRARIES(name [ libraries ])
6# - Link libraries to swig module
7# All other macros are for internal use only.
8# To get the actual name of the swig module,
9# use: ${SWIG_MODULE_${name}_REAL_NAME}.
10# Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify
11# special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add
12# special flags to all swig calls.
13# Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify
14# where to write all the swig generated module (swig -outdir option)
15# The name-specific variable SWIG_MODULE_<name>_EXTRA_DEPS may be used
16# to specify extra dependencies for the generated modules.
17# If the source file generated by swig need some special flag you can use
18# set_source_files_properties( ${swig_generated_file_fullname}
19# PROPERTIES COMPILE_FLAGS "-bla")
20
21
22#=============================================================================
23# Copyright 2004-2009 Kitware, Inc.
24# Copyright 2009 Mathieu Malaterre <mathieu.malaterre@gmail.com>
25#
26# Distributed under the OSI-approved BSD License (the "License");
27# see accompanying file Copyright.txt for details.
28#
29# This software is distributed WITHOUT ANY WARRANTY; without even the
30# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31# See the License for more information.
32#=============================================================================
33# (To distribute this file outside of CMake, substitute the full
34# License text for the above reference.)
35
36set(SWIG_CXX_EXTENSION "cxx")
37set(SWIG_EXTRA_LIBRARIES "")
38
39set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
40
41#
42# For given swig module initialize variables associated with it
43#
44macro(SWIG_MODULE_INITIALIZE name language)
45 string(TOUPPER "${language}" swig_uppercase_language)
46 string(TOLOWER "${language}" swig_lowercase_language)
47 set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
48 set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")
49
50 set(SWIG_MODULE_${name}_REAL_NAME "${name}")
51 if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN")
52 message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
53 elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON")
54 # when swig is used without the -interface it will produce in the module.py
55 # a 'import _modulename' statement, which implies having a corresponding
56 # _modulename.so (*NIX), _modulename.pyd (Win32).
57 set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
58 elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL")
59 set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
60 endif()
61endmacro()
62
63#
64# For a given language, input file, and output file, determine extra files that
65# will be generated. This is internal swig macro.
66#
67
68macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
69 set(${outfiles} "")
70 get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
71 ${infile} SWIG_MODULE_NAME)
72 if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
73 get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE)
74 endif()
75 foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
76 set(${outfiles} ${${outfiles}}
77 "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
78 endforeach()
79endmacro()
80
81#
82# Take swig (*.i) file and add proper custom commands for it
83#
84macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
85 set(swig_full_infile ${infile})
86 get_filename_component(swig_source_file_path "${infile}" PATH)
87 get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
88 get_source_file_property(swig_source_file_generated ${infile} GENERATED)
89 get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
90 get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
91 if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
92 set(swig_source_file_flags "")
93 endif()
94 set(swig_source_file_fullname "${infile}")
95 if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}")
96 string(REGEX REPLACE
97 "^${CMAKE_CURRENT_SOURCE_DIR}" ""
98 swig_source_file_relative_path
99 "${swig_source_file_path}")
100 else()
101 if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_BINARY_DIR}")
102 string(REGEX REPLACE
103 "^${CMAKE_CURRENT_BINARY_DIR}" ""
104 swig_source_file_relative_path
105 "${swig_source_file_path}")
106 set(swig_source_file_generated 1)
107 else()
108 set(swig_source_file_relative_path "${swig_source_file_path}")
109 if(swig_source_file_generated)
110 set(swig_source_file_fullname "${CMAKE_CURRENT_BINARY_DIR}/${infile}")
111 else()
112 set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}")
113 endif()
114 endif()
115 endif()
116
117 set(swig_generated_file_fullname
118 "${CMAKE_CURRENT_BINARY_DIR}")
119 if(swig_source_file_relative_path)
120 set(swig_generated_file_fullname
121 "${swig_generated_file_fullname}/${swig_source_file_relative_path}")
122 endif()
123 # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
124 if(CMAKE_SWIG_OUTDIR)
125 set(swig_outdir ${CMAKE_SWIG_OUTDIR})
126 else()
127 set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
128 endif()
129 SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
130 swig_extra_generated_files
131 "${swig_outdir}"
132 "${infile}")
133 set(swig_generated_file_fullname
134 "${swig_generated_file_fullname}/${swig_source_file_name_we}")
135 # add the language into the name of the file (i.e. TCL_wrap)
136 # this allows for the same .i file to be wrapped into different languages
137 set(swig_generated_file_fullname
138 "${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap")
139
140 if(swig_source_file_cplusplus)
141 set(swig_generated_file_fullname
142 "${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}")
143 else()
144 set(swig_generated_file_fullname
145 "${swig_generated_file_fullname}.c")
146 endif()
147
148 # Shut up some warnings from poor SWIG code generation that we
149 # can do nothing about, when this flag is available
150 include(CheckCXXCompilerFlag)
151 check_cxx_compiler_flag("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
152 if(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
153 set_source_files_properties(${swig_generated_file_fullname}
154 PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable")
155 endif(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
156
157 get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
158 list(REMOVE_DUPLICATES cmake_include_directories)
159 set(swig_include_dirs)
160 foreach(it ${cmake_include_directories})
161 set(swig_include_dirs ${swig_include_dirs} "-I${it}")
162 endforeach()
163
164 set(swig_special_flags)
165 # default is c, so add c++ flag if it is c++
166 if(swig_source_file_cplusplus)
167 set(swig_special_flags ${swig_special_flags} "-c++")
168 endif()
169 set(swig_extra_flags)
170 if(SWIG_MODULE_${name}_EXTRA_FLAGS)
171 set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
172 endif()
173
174 # hack to work around CMake bug in add_custom_command with multiple OUTPUT files
175
176 file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
177 execute_process(
178 COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
179unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
180print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))"
181 OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE
182 )
183
184 file(
185 WRITE ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
186 "int main(void){return 0;}\n"
187 )
188
189 # create dummy dependencies
190 add_custom_command(
191 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
192 COMMAND ${CMAKE_COMMAND} -E copy
193 ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
194 ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
195 DEPENDS "${swig_source_file_fullname}" ${SWIG_MODULE_${name}_EXTRA_DEPS}
196 COMMENT ""
197 )
198
199 # create the dummy target
200 add_executable(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp)
201
202 # add a custom command to the dummy target
203 add_custom_command(
204 TARGET ${_target}
205 # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
206 COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
207 COMMAND "${SWIG_EXECUTABLE}"
208 ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
209 ${swig_source_file_flags}
210 ${CMAKE_SWIG_FLAGS}
211 -outdir ${swig_outdir}
212 ${swig_special_flags}
213 ${swig_extra_flags}
214 ${swig_include_dirs}
215 -o "${swig_generated_file_fullname}"
216 "${swig_source_file_fullname}"
217 COMMENT "Swig source"
218 )
219
220 #add dummy independent dependencies from the _target to each file
221 #that will be generated by the SWIG command above
222
223 set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
224
225 foreach(swig_gen_file ${${outfiles}})
226 add_custom_command(
227 OUTPUT ${swig_gen_file}
228 COMMAND "${CMAKE_COMMAND}" -E touch_nocreate "${swig_gen_file}"
229 DEPENDS ${_target}
230 COMMENT "dummy command to show ${_target} dependency of ${swig_gen_file}"
231 )
232 endforeach()
233
234 set_source_files_properties(
235 ${outfiles} PROPERTIES GENERATED 1
236 )
237
238endmacro()
239
240#
241# Create Swig module
242#
243macro(SWIG_ADD_MODULE name language)
244 SWIG_MODULE_INITIALIZE(${name} ${language})
245 set(swig_dot_i_sources)
246 set(swig_other_sources)
247 foreach(it ${ARGN})
248 if(${it} MATCHES ".*\\.i$")
249 set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
250 else()
251 set(swig_other_sources ${swig_other_sources} "${it}")
252 endif()
253 endforeach()
254
255 set(swig_generated_sources)
256 foreach(it ${swig_dot_i_sources})
257 SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
258 set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
259 endforeach()
260 get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
261 set_directory_properties(PROPERTIES
262 ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
263 add_library(${SWIG_MODULE_${name}_REAL_NAME}
264 MODULE
265 ${swig_generated_sources}
266 ${swig_other_sources})
267 string(TOLOWER "${language}" swig_lowercase_language)
268 if ("${swig_lowercase_language}" STREQUAL "java")
269 if (APPLE)
270 # In java you want:
271 # System.loadLibrary("LIBRARY");
272 # then JNI will look for a library whose name is platform dependent, namely
273 # MacOS : libLIBRARY.jnilib
274 # Windows: LIBRARY.dll
275 # Linux : libLIBRARY.so
276 set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
277 endif ()
278 endif ()
279 if ("${swig_lowercase_language}" STREQUAL "python")
280 # this is only needed for the python case where a _modulename.so is generated
281 set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
282 # Python extension modules on Windows must have the extension ".pyd"
283 # instead of ".dll" as of Python 2.5. Older python versions do support
284 # this suffix.
285 # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
286 # <quote>
287 # Windows: .dll is no longer supported as a filename extension for extension modules.
288 # .pyd is now the only filename extension that will be searched for.
289 # </quote>
290 if(WIN32 AND NOT CYGWIN)
291 set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
292 endif()
293 endif ()
294endmacro()
295
296#
297# Like TARGET_LINK_LIBRARIES but for swig modules
298#
299macro(SWIG_LINK_LIBRARIES name)
300 if(SWIG_MODULE_${name}_REAL_NAME)
301 target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
302 else()
303 message(SEND_ERROR "Cannot find Swig library \"${name}\".")
304 endif()
305endmacro()