UseSWIG.cmake 12.8 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 13 14 15 16
#    SWIG_ADD_LIBRARY(<name>
#                     [TYPE <SHARED|MODULE|STATIC>]
#                     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
set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
61 62 63 64

#
# For given swig module initialize variables associated with it
#
65 66 67 68 69 70 71
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}")
72
  if (";${CMAKE_SWIG_FLAGS};" MATCHES ";-noproxy;")
73 74
    set (SWIG_MODULE_${name}_NOPROXY TRUE)
  endif ()
75
  if("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xUNKNOWN")
76
    message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
77
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY)
78 79 80
    # 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
81
    set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
82
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPERL")
83
    set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
84
  elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xCSHARP")
85 86 87
    # 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}")
88
  endif()
89
endmacro()
90 91 92

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

96 97 98
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
99
    ${infile} SWIG_MODULE_NAME)
100
  if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

    # 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 ()

125
  endif()
126 127
  foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
    set(${outfiles} ${${outfiles}}
Bill Hoffman's avatar
Bill Hoffman committed
128
      "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
129 130
  endforeach()
endmacro()
131 132 133 134

#
# Take swig (*.i) file and add proper custom commands for it
#
135 136 137 138 139 140 141 142
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 "")
143
  endif()
144
  get_filename_component(swig_source_file_fullname "${infile}" ABSOLUTE)
145

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

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

159 160 161 162 163 164
  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()
165
  set(swig_generated_file_fullname
166
    "${swig_outfile_dir}/${swig_source_file_name_we}")
Bill Hoffman's avatar
Bill Hoffman committed
167 168
  # 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
169 170
  string(APPEND swig_generated_file_fullname
    "${SWIG_MODULE_${name}_LANGUAGE}_wrap")
171

172
  if(swig_source_file_cplusplus)
Daniel Pfeifer's avatar
Daniel Pfeifer committed
173 174
    string(APPEND swig_generated_file_fullname
      ".${SWIG_CXX_EXTENSION}")
175
  else()
Daniel Pfeifer's avatar
Daniel Pfeifer committed
176 177
    string(APPEND swig_generated_file_fullname
      ".c")
178
  endif()
179

180 181 182
  #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)
183
  list(REMOVE_DUPLICATES cmake_include_directories)
184 185 186
  set(swig_include_dirs)
  foreach(it ${cmake_include_directories})
    set(swig_include_dirs ${swig_include_dirs} "-I${it}")
187
  endforeach()
188

189
  set(swig_special_flags)
Bill Hoffman's avatar
Bill Hoffman committed
190
  # default is c, so add c++ flag if it is c++
191 192
  if(swig_source_file_cplusplus)
    set(swig_special_flags ${swig_special_flags} "-c++")
193
  endif()
194 195 196
  set(swig_extra_flags)
  if(SWIG_MODULE_${name}_EXTRA_FLAGS)
    set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
197
  endif()
198
  add_custom_command(
Ken Martin's avatar
Ken Martin committed
199
    OUTPUT "${swig_generated_file_fullname}" ${swig_extra_generated_files}
200 201
    # 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
202 203 204 205 206 207 208 209 210 211
    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}"
212 213
    MAIN_DEPENDENCY "${swig_source_file_fullname}"
    DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS}
214
    COMMENT "Swig source")
215
  set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
216
    PROPERTIES GENERATED 1)
217
  set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
218
endmacro()
219 220 221 222

#
# Create Swig module
#
223
macro(SWIG_ADD_MODULE name language)
224 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 252 253 254
  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)
  endif()

  swig_module_initialize(${name} ${_SAM_LANGUAGE})

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

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

#
# Like TARGET_LINK_LIBRARIES but for swig modules
#
331 332 333
macro(SWIG_LINK_LIBRARIES name)
  if(SWIG_MODULE_${name}_REAL_NAME)
    target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
334
  else()
335
    message(SEND_ERROR "Cannot find Swig library \"${name}\".")
336 337
  endif()
endmacro()
338