UseSWIG.cmake 13.1 KB
Newer Older
1 2 3
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

4 5 6 7
#.rst:
# UseSWIG
# -------
#
8
# Defines the following macros for use with SWIG:
9 10 11
#
# ::
#
12
#    SWIG_ADD_LIBRARY(<name>
13
#                     [TYPE <SHARED|MODULE|STATIC|USE_BUILD_SHARED_LIBS>]
14 15 16
#                     LANGUAGE <language>
#                     SOURCES <file>...
#                     )
17 18 19 20
#      - Define swig module with given name and specified language
#    SWIG_LINK_LIBRARIES(name [ libraries ])
#      - Link libraries to swig module
#
21
# Source files properties on module files can be set before the invocation
22
# of the SWIG_ADD_LIBRARY macro to specify special behavior of SWIG.
23 24 25 26
#
# The source file property CPLUSPLUS calls SWIG in c++ mode, e.g.::
#
#    set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON)
27
#    swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#
# The source file property SWIG_FLAGS adds custom flags to the SWIG executable.
#
# The source-file property SWIG_MODULE_NAME have to be provided to specify the actual
# import name of the module in the target language if it cannot be scanned automatically
# from source or different from the module file basename.::
#
#    set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod_realname)
#
# To get the name of the swig module target library, use: ${SWIG_MODULE_${name}_REAL_NAME}.
#
# Also some variables can be set to specify special behavior of SWIG.
#
# CMAKE_SWIG_FLAGS can be used to add special flags to all swig calls.
#
43 44 45 46 47
# CMAKE_SWIG_OUTDIR allows one to specify where to write
# the language specific files (swig -outdir option).
#
# SWIG_OUTFILE_DIR allows one to specify where to write the output file
# (swig -o option).  If not specified, CMAKE_SWIG_OUTDIR is used.
48 49 50 51 52 53 54 55
#
# The name-specific variable SWIG_MODULE_<name>_EXTRA_DEPS may be used to specify extra
# dependencies for the generated modules.
#
# If the source file generated by swig need some special flag you can use::
#
#    set_source_files_properties( ${swig_generated_file_fullname}
#                                 PROPERTIES COMPILE_FLAGS "-bla")
56

57 58
set(SWIG_CXX_EXTENSION "cxx")
set(SWIG_EXTRA_LIBRARIES "")
59

60 61
set(SWIG_PYTHON_EXTRA_FILE_EXTENSIONS ".py")
set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java")
62 63 64 65

#
# For given swig module initialize variables associated with it
#
66 67 68 69 70 71 72
macro(SWIG_MODULE_INITIALIZE name language)
  string(TOUPPER "${language}" swig_uppercase_language)
  string(TOLOWER "${language}" swig_lowercase_language)
  set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
  set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")

  set(SWIG_MODULE_${name}_REAL_NAME "${name}")
73
  if (";${CMAKE_SWIG_FLAGS};" MATCHES ";-noproxy;")
74 75
    set (SWIG_MODULE_${name}_NOPROXY TRUE)
  endif ()
76
  if("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xUNKNOWN")
77
    message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
78
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY)
79 80 81
    # swig will produce a module.py containing an 'import _modulename' statement,
    # which implies having a corresponding _modulename.so (*NIX), _modulename.pyd (Win32),
    # unless the -noproxy flag is used
82
    set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
83
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPERL")
84
    set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
85
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xCSHARP")
86 87 88
    # This makes sure that the name used in the generated DllImport
    # matches the library name created by CMake
    set(SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport;${name}")
89
  endif()
90
endmacro()
91 92 93

#
# For a given language, input file, and output file, determine extra files that
94
# will be generated. This is internal swig macro.
95 96
#

97 98 99
macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
  set(${outfiles} "")
  get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
Bill Hoffman's avatar
Bill Hoffman committed
100
    ${infile} SWIG_MODULE_NAME)
101
  if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

    # try to get module name from "%module foo" syntax
    if ( EXISTS ${infile} )
      file ( STRINGS ${infile} _MODULE_NAME REGEX "[ ]*%module[ ]*[a-zA-Z0-9_]+.*" )
    endif ()
    if ( _MODULE_NAME )
      string ( REGEX REPLACE "[ ]*%module[ ]*([a-zA-Z0-9_]+).*" "\\1" _MODULE_NAME "${_MODULE_NAME}" )
      set(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${_MODULE_NAME}")

    else ()
      # try to get module name from "%module (options=...) foo" syntax
      if ( EXISTS ${infile} )
        file ( STRINGS ${infile} _MODULE_NAME REGEX "[ ]*%module[ ]*\\(.*\\)[ ]*[a-zA-Z0-9_]+.*" )
      endif ()
      if ( _MODULE_NAME )
        string ( REGEX REPLACE "[ ]*%module[ ]*\\(.*\\)[ ]*([a-zA-Z0-9_]+).*" "\\1" _MODULE_NAME "${_MODULE_NAME}" )
        set(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${_MODULE_NAME}")

      else ()
        # fallback to file basename
        get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename ${infile} NAME_WE)
      endif ()
    endif ()

126
  endif()
127
  foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSIONS})
128
    set(${outfiles} ${${outfiles}}
129
      "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}${it}")
130 131
  endforeach()
endmacro()
132 133 134 135

#
# Take swig (*.i) file and add proper custom commands for it
#
136 137 138 139 140 141 142 143
macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
  set(swig_full_infile ${infile})
  get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
  get_source_file_property(swig_source_file_generated ${infile} GENERATED)
  get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
  get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
  if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
    set(swig_source_file_flags "")
144
  endif()
145
  get_filename_component(swig_source_file_fullname "${infile}" ABSOLUTE)
146

147
  # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
148 149
  if(CMAKE_SWIG_OUTDIR)
    set(swig_outdir ${CMAKE_SWIG_OUTDIR})
150
  else()
151
    set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
152
  endif()
153 154 155 156 157 158 159

  if(SWIG_OUTFILE_DIR)
    set(swig_outfile_dir ${SWIG_OUTFILE_DIR})
  else()
    set(swig_outfile_dir ${swig_outdir})
  endif()

160 161 162 163 164 165
  if (NOT SWIG_MODULE_${name}_NOPROXY)
    SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
      swig_extra_generated_files
      "${swig_outdir}"
      "${swig_source_file_fullname}")
  endif()
166
  set(swig_generated_file_fullname
167
    "${swig_outfile_dir}/${swig_source_file_name_we}")
Bill Hoffman's avatar
Bill Hoffman committed
168 169
  # add the language into the name of the file (i.e. TCL_wrap)
  # this allows for the same .i file to be wrapped into different languages
170 171
  string(APPEND swig_generated_file_fullname
    "${SWIG_MODULE_${name}_LANGUAGE}_wrap")
172

173
  if(swig_source_file_cplusplus)
174 175
    string(APPEND swig_generated_file_fullname
      ".${SWIG_CXX_EXTENSION}")
176
  else()
177 178
    string(APPEND swig_generated_file_fullname
      ".c")
179
  endif()
180

181 182 183
  #message("Full path to source file: ${swig_source_file_fullname}")
  #message("Full path to the output file: ${swig_generated_file_fullname}")
  get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
184
  list(REMOVE_DUPLICATES cmake_include_directories)
185 186 187
  set(swig_include_dirs)
  foreach(it ${cmake_include_directories})
    set(swig_include_dirs ${swig_include_dirs} "-I${it}")
188
  endforeach()
189

190
  set(swig_special_flags)
Bill Hoffman's avatar
Bill Hoffman committed
191
  # default is c, so add c++ flag if it is c++
192 193
  if(swig_source_file_cplusplus)
    set(swig_special_flags ${swig_special_flags} "-c++")
194
  endif()
195 196 197
  set(swig_extra_flags)
  if(SWIG_MODULE_${name}_EXTRA_FLAGS)
    set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
198
  endif()
199
  add_custom_command(
200
    OUTPUT "${swig_generated_file_fullname}" ${swig_extra_generated_files}
201 202
    # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
    COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
203 204 205 206 207 208 209 210 211 212
    COMMAND "${SWIG_EXECUTABLE}"
    ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
    ${swig_source_file_flags}
    ${CMAKE_SWIG_FLAGS}
    -outdir ${swig_outdir}
    ${swig_special_flags}
    ${swig_extra_flags}
    ${swig_include_dirs}
    -o "${swig_generated_file_fullname}"
    "${swig_source_file_fullname}"
213 214
    MAIN_DEPENDENCY "${swig_source_file_fullname}"
    DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS}
215
    IMPLICIT_DEPENDS CXX "${swig_source_file_fullname}"
216
    COMMENT "Swig source")
217
  set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
218
    PROPERTIES GENERATED 1)
219
  set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
220
endmacro()
221 222 223 224

#
# Create Swig module
#
225
macro(SWIG_ADD_MODULE name language)
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  message(DEPRECATION "SWIG_ADD_MODULE is deprecated. Use SWIG_ADD_LIBRARY instead.")
  swig_add_library(${name}
                   LANGUAGE ${language}
                   TYPE MODULE
                   SOURCES ${ARGN})
endmacro()


macro(SWIG_ADD_LIBRARY name)

  include(CMakeParseArguments)
  set(options "")
  set(oneValueArgs LANGUAGE
                   TYPE)
  set(multiValueArgs SOURCES)
  cmake_parse_arguments(_SAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(NOT DEFINED _SAM_LANGUAGE)
    message(FATAL_ERROR "SWIG_ADD_LIBRARY: Missing LANGUAGE argument")
  endif()

  if(NOT DEFINED _SAM_SOURCES)
    message(FATAL_ERROR "SWIG_ADD_LIBRARY: Missing SOURCES argument")
  endif()

  if(NOT DEFINED _SAM_TYPE)
    set(_SAM_TYPE MODULE)
253 254
  elseif("${_SAM_TYPE}" STREQUAL "USE_BUILD_SHARED_LIBS")
    unset(_SAM_TYPE)
255 256 257 258
  endif()

  swig_module_initialize(${name} ${_SAM_LANGUAGE})

259 260
  set(swig_dot_i_sources)
  set(swig_other_sources)
261
  foreach(it ${_SAM_SOURCES})
262
    if(${it} MATCHES "\\.i$")
263
      set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
264
    else()
265
      set(swig_other_sources ${swig_other_sources} "${it}")
266 267
    endif()
  endforeach()
268 269 270

  set(swig_generated_sources)
  foreach(it ${swig_dot_i_sources})
271
    SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
272
    set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
273
  endforeach()
274 275
  get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
  set_directory_properties(PROPERTIES
Bill Hoffman's avatar
Bill Hoffman committed
276
    ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
277
  add_library(${SWIG_MODULE_${name}_REAL_NAME}
278
    ${_SAM_TYPE}
279 280
    ${swig_generated_sources}
    ${swig_other_sources})
281 282 283
  if("${_SAM_TYPE}" STREQUAL "MODULE")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES NO_SONAME ON)
  endif()
284
  string(TOLOWER "${_SAM_LANGUAGE}" swig_lowercase_language)
285 286 287
  if ("${swig_lowercase_language}" STREQUAL "octave")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".oct")
288 289
  elseif ("${swig_lowercase_language}" STREQUAL "go")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
290
  elseif ("${swig_lowercase_language}" STREQUAL "java")
291
    if (APPLE)
292 293 294 295 296 297
        # In java you want:
        #      System.loadLibrary("LIBRARY");
        # then JNI will look for a library whose name is platform dependent, namely
        #   MacOS  : libLIBRARY.jnilib
        #   Windows: LIBRARY.dll
        #   Linux  : libLIBRARY.so
298
        set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
299
      endif ()
300
  elseif ("${swig_lowercase_language}" STREQUAL "lua")
301 302 303
    if("${_SAM_TYPE}" STREQUAL "MODULE")
      set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
    endif()
304
  elseif ("${swig_lowercase_language}" STREQUAL "python")
305
    # this is only needed for the python case where a _modulename.so is generated
306
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
307 308 309 310 311 312 313 314
    # Python extension modules on Windows must have the extension ".pyd"
    # instead of ".dll" as of Python 2.5.  Older python versions do support
    # this suffix.
    # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
    # <quote>
    # Windows: .dll is no longer supported as a filename extension for extension modules.
    # .pyd is now the only filename extension that will be searched for.
    # </quote>
315 316
    if(WIN32 AND NOT CYGWIN)
      set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
317
    endif()
318 319
  elseif ("${swig_lowercase_language}" STREQUAL "r")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
320 321 322 323 324 325 326 327 328 329 330
  elseif ("${swig_lowercase_language}" STREQUAL "ruby")
    # In ruby you want:
    #      require 'LIBRARY'
    # then ruby will look for a library whose name is platform dependent, namely
    #   MacOS  : LIBRARY.bundle
    #   Windows: LIBRARY.dll
    #   Linux  : LIBRARY.so
    set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
    if (APPLE)
      set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".bundle")
    endif ()
331 332
  endif ()
endmacro()
333 334 335 336

#
# Like TARGET_LINK_LIBRARIES but for swig modules
#
337 338 339
macro(SWIG_LINK_LIBRARIES name)
  if(SWIG_MODULE_${name}_REAL_NAME)
    target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
340
  else()
341
    message(SEND_ERROR "Cannot find Swig library \"${name}\".")
342 343
  endif()
endmacro()
344