UseSWIG.cmake 13 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

Ken Martin's avatar
Ken Martin committed
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
Daniel Pfeifer's avatar
Daniel Pfeifer committed
170 171
  string(APPEND swig_generated_file_fullname
    "${SWIG_MODULE_${name}_LANGUAGE}_wrap")
172

173
  if(swig_source_file_cplusplus)
Daniel Pfeifer's avatar
Daniel Pfeifer committed
174 175
    string(APPEND swig_generated_file_fullname
      ".${SWIG_CXX_EXTENSION}")
176
  else()
Daniel Pfeifer's avatar
Daniel Pfeifer committed
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(
Ken Martin's avatar
Ken Martin committed
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}
Ken Martin's avatar
Ken Martin committed
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
    COMMENT "Swig source")
216
  set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
217
    PROPERTIES GENERATED 1)
218
  set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
219
endmacro()
220 221 222 223

#
# Create Swig module
#
224
macro(SWIG_ADD_MODULE name language)
225 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
  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)
252 253
  elseif("${_SAM_TYPE}" STREQUAL "USE_BUILD_SHARED_LIBS")
    unset(_SAM_TYPE)
254 255 256 257
  endif()

  swig_module_initialize(${name} ${_SAM_LANGUAGE})

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

  set(swig_generated_sources)
  foreach(it ${swig_dot_i_sources})
270
    SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
271
    set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
272
  endforeach()
273 274
  get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
  set_directory_properties(PROPERTIES
Bill Hoffman's avatar
Bill Hoffman committed
275
    ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
276
  add_library(${SWIG_MODULE_${name}_REAL_NAME}
277
    ${_SAM_TYPE}
278 279
    ${swig_generated_sources}
    ${swig_other_sources})
280 281 282
  if("${_SAM_TYPE}" STREQUAL "MODULE")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES NO_SONAME ON)
  endif()
283
  string(TOLOWER "${_SAM_LANGUAGE}" swig_lowercase_language)
284 285 286
  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")
287 288
  elseif ("${swig_lowercase_language}" STREQUAL "go")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
289
  elseif ("${swig_lowercase_language}" STREQUAL "java")
290
    if (APPLE)
291 292 293 294 295 296
        # 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
297
        set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
298
      endif ()
299
  elseif ("${swig_lowercase_language}" STREQUAL "lua")
300 301 302
    if("${_SAM_TYPE}" STREQUAL "MODULE")
      set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
    endif()
303
  elseif ("${swig_lowercase_language}" STREQUAL "python")
304
    # this is only needed for the python case where a _modulename.so is generated
305
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
306 307 308 309 310 311 312 313
    # 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>
314 315
    if(WIN32 AND NOT CYGWIN)
      set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
316
    endif()
317 318
  elseif ("${swig_lowercase_language}" STREQUAL "r")
    set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
319 320 321 322 323 324 325 326 327 328 329
  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 ()
330 331
  endif ()
endmacro()
332 333 334 335

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