Vasil Velichkov | e9aaeb1 | 2018-04-25 23:25:59 +0300 | [diff] [blame] | 1 | # - 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 | |
| 36 | set(SWIG_CXX_EXTENSION "cxx") |
| 37 | set(SWIG_EXTRA_LIBRARIES "") |
| 38 | |
| 39 | set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py") |
| 40 | |
| 41 | # |
| 42 | # For given swig module initialize variables associated with it |
| 43 | # |
| 44 | macro(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() |
| 61 | endmacro() |
| 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 | |
| 68 | macro(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() |
| 79 | endmacro() |
| 80 | |
| 81 | # |
| 82 | # Take swig (*.i) file and add proper custom commands for it |
| 83 | # |
| 84 | macro(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 |
| 179 | unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] |
| 180 | print(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 | |
| 238 | endmacro() |
| 239 | |
| 240 | # |
| 241 | # Create Swig module |
| 242 | # |
| 243 | macro(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 () |
| 294 | endmacro() |
| 295 | |
| 296 | # |
| 297 | # Like TARGET_LINK_LIBRARIES but for swig modules |
| 298 | # |
| 299 | macro(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() |
| 305 | endmacro() |