GenerateExportHeader.cmake 14.9 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 8 9
#[=======================================================================[.rst:
GenerateExportHeader
--------------------

Function for generation of export macros for libraries

10
This module provides the function ``GENERATE_EXPORT_HEADER()``.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file
suitable for preprocessor inclusion which contains EXPORT macros to be
used in library classes::

   GENERATE_EXPORT_HEADER( LIBRARY_TARGET
             [BASE_NAME <base_name>]
             [EXPORT_MACRO_NAME <export_macro_name>]
             [EXPORT_FILE_NAME <export_file_name>]
             [DEPRECATED_MACRO_NAME <deprecated_macro_name>]
             [NO_EXPORT_MACRO_NAME <no_export_macro_name>]
             [INCLUDE_GUARD_NAME <include_guard_name>]
             [STATIC_DEFINE <static_define>]
             [NO_DEPRECATED_MACRO_NAME <no_deprecated_macro_name>]
             [DEFINE_NO_DEPRECATED]
             [PREFIX_NAME <prefix_name>]
             [CUSTOM_CONTENT_FROM_VARIABLE <variable>]
   )


The target properties :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>`
and :prop_tgt:`VISIBILITY_INLINES_HIDDEN` can be used to add the appropriate
compile flags for targets.  See the documentation of those target properties,
and the convenience variables
:variable:`CMAKE_CXX_VISIBILITY_PRESET <CMAKE_<LANG>_VISIBILITY_PRESET>` and
:variable:`CMAKE_VISIBILITY_INLINES_HIDDEN`.

By default ``GENERATE_EXPORT_HEADER()`` generates macro names in a file
name determined by the name of the library.  This means that in the
simplest case, users of ``GenerateExportHeader`` will be equivalent to:

.. code-block:: cmake

   set(CMAKE_CXX_VISIBILITY_PRESET hidden)
   set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
   add_library(somelib someclass.cpp)
   generate_export_header(somelib)
   install(TARGETS somelib DESTINATION ${LIBRARY_INSTALL_DIR})
   install(FILES
    someclass.h
    ${PROJECT_BINARY_DIR}/somelib_export.h DESTINATION ${INCLUDE_INSTALL_DIR}
   )


And in the ABI header files:

.. code-block:: c++

   #include "somelib_export.h"
   class SOMELIB_EXPORT SomeClass {
     ...
   };


The CMake fragment will generate a file in the
``${CMAKE_CURRENT_BINARY_DIR}`` called ``somelib_export.h`` containing the
macros ``SOMELIB_EXPORT``, ``SOMELIB_NO_EXPORT``, ``SOMELIB_DEPRECATED``,
``SOMELIB_DEPRECATED_EXPORT`` and ``SOMELIB_DEPRECATED_NO_EXPORT``.
They will be followed by content taken from the variable specified by
the ``CUSTOM_CONTENT_FROM_VARIABLE`` option, if any.
The resulting file should be installed with other headers in the library.

The ``BASE_NAME`` argument can be used to override the file name and the
names used for the macros:

.. code-block:: cmake

   add_library(somelib someclass.cpp)
   generate_export_header(somelib
     BASE_NAME other_name
   )


Generates a file called ``other_name_export.h`` containing the macros
``OTHER_NAME_EXPORT``, ``OTHER_NAME_NO_EXPORT`` and ``OTHER_NAME_DEPRECATED``
etc.

The ``BASE_NAME`` may be overridden by specifying other options in the
function.  For example:

.. code-block:: cmake

   add_library(somelib someclass.cpp)
   generate_export_header(somelib
     EXPORT_MACRO_NAME OTHER_NAME_EXPORT
   )


creates the macro ``OTHER_NAME_EXPORT`` instead of ``SOMELIB_EXPORT``, but
other macros and the generated file name is as default:

.. code-block:: cmake

   add_library(somelib someclass.cpp)
   generate_export_header(somelib
     DEPRECATED_MACRO_NAME KDE_DEPRECATED
   )


creates the macro ``KDE_DEPRECATED`` instead of ``SOMELIB_DEPRECATED``.

If ``LIBRARY_TARGET`` is a static library, macros are defined without
values.

If the same sources are used to create both a shared and a static
library, the uppercased symbol ``${BASE_NAME}_STATIC_DEFINE`` should be
used when building the static library:

.. code-block:: cmake

   add_library(shared_variant SHARED ${lib_SRCS})
   add_library(static_variant ${lib_SRCS})
   generate_export_header(shared_variant BASE_NAME libshared_and_static)
   set_target_properties(static_variant PROPERTIES
     COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE)

This will cause the export macros to expand to nothing when building
the static library.

If ``DEFINE_NO_DEPRECATED`` is specified, then a macro
``${BASE_NAME}_NO_DEPRECATED`` will be defined This macro can be used to
remove deprecated code from preprocessor output:

.. code-block:: cmake

   option(EXCLUDE_DEPRECATED "Exclude deprecated parts of the library" FALSE)
   if (EXCLUDE_DEPRECATED)
     set(NO_BUILD_DEPRECATED DEFINE_NO_DEPRECATED)
   endif()
   generate_export_header(somelib ${NO_BUILD_DEPRECATED})


And then in somelib:

.. code-block:: c++

   class SOMELIB_EXPORT SomeClass
   {
   public:
   #ifndef SOMELIB_NO_DEPRECATED
     SOMELIB_DEPRECATED void oldMethod();
   #endif
   };

.. code-block:: c++

   #ifndef SOMELIB_NO_DEPRECATED
   void SomeClass::oldMethod() {  }
   #endif


If ``PREFIX_NAME`` is specified, the argument will be used as a prefix to
all generated macros.

For example:

.. code-block:: cmake

   generate_export_header(somelib PREFIX_NAME VTK_)

Generates the macros ``VTK_SOMELIB_EXPORT`` etc.

::

   ADD_COMPILER_EXPORT_FLAGS( [<output_variable>] )

The ``ADD_COMPILER_EXPORT_FLAGS`` function adds ``-fvisibility=hidden`` to
:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` if supported, and is a no-op
on Windows which does not need extra compiler flags for exporting support.
You may optionally pass a single argument to ``ADD_COMPILER_EXPORT_FLAGS``
that will be populated with the ``CXX_FLAGS`` required to enable visibility
support for the compiler/architecture in use.

This function is deprecated.  Set the target properties
:prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and
:prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead.
#]=======================================================================]
188

189
include(CheckCCompilerFlag)
190 191
include(CheckCXXCompilerFlag)

192 193
# TODO: Install this macro separately?
macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT)
194 195
  check_cxx_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; }
    int main() { return somefunc();}" ${_RESULT}
196 197 198
  )
endmacro()

199 200 201 202 203 204 205
# TODO: Install this macro separately?
macro(_check_c_compiler_attribute _ATTRIBUTE _RESULT)
  check_c_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; }
    int main() { return somefunc();}" ${_RESULT}
  )
endmacro()

206
macro(_test_compiler_hidden_visibility)
207

208 209
  if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2")
    set(GCC_TOO_OLD TRUE)
210
  elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2")
211 212 213
    set(GCC_TOO_OLD TRUE)
  elseif(CMAKE_CXX_COMPILER_ID MATCHES Intel AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0")
    set(_INTEL_TOO_OLD TRUE)
214 215
  endif()

216 217
  # Exclude XL here because it misinterprets -fvisibility=hidden even though
  # the check_cxx_compiler_flag passes
218
  if(NOT GCC_TOO_OLD
219 220 221
      AND NOT _INTEL_TOO_OLD
      AND NOT WIN32
      AND NOT CYGWIN
222 223 224
      AND NOT CMAKE_CXX_COMPILER_ID MATCHES XL
      AND NOT CMAKE_CXX_COMPILER_ID MATCHES PGI
      AND NOT CMAKE_CXX_COMPILER_ID MATCHES Watcom)
225 226 227 228 229 230 231 232 233
    if (CMAKE_CXX_COMPILER_LOADED)
      check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
      check_cxx_compiler_flag(-fvisibility-inlines-hidden
        COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
    else()
      check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
      check_c_compiler_flag(-fvisibility-inlines-hidden
        COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
    endif()
234
  endif()
235 236
endmacro()

237
macro(_test_compiler_has_deprecated)
238 239 240
  # NOTE:  Some Embarcadero compilers silently compile __declspec(deprecated)
  # without error, but this is not a documented feature and the attribute does
  # not actually generate any warnings.
241
  if(CMAKE_CXX_COMPILER_ID MATCHES Borland
242
      OR CMAKE_CXX_COMPILER_ID MATCHES Embarcadero
243
      OR CMAKE_CXX_COMPILER_ID MATCHES HP
244
      OR GCC_TOO_OLD
245 246
      OR CMAKE_CXX_COMPILER_ID MATCHES PGI
      OR CMAKE_CXX_COMPILER_ID MATCHES Watcom)
247 248
    set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL
      "Compiler support for a deprecated attribute")
249
  else()
250 251 252 253 254 255 256 257 258 259
    if (CMAKE_CXX_COMPILER_LOADED)
      _check_cxx_compiler_attribute("__attribute__((__deprecated__))"
        COMPILER_HAS_DEPRECATED_ATTR)
      if(COMPILER_HAS_DEPRECATED_ATTR)
        set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}"
          CACHE INTERNAL "Compiler support for a deprecated attribute")
      else()
        _check_cxx_compiler_attribute("__declspec(deprecated)"
          COMPILER_HAS_DEPRECATED)
      endif()
260
    else()
261 262 263 264 265 266 267 268 269 270
      _check_c_compiler_attribute("__attribute__((__deprecated__))"
        COMPILER_HAS_DEPRECATED_ATTR)
      if(COMPILER_HAS_DEPRECATED_ATTR)
        set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}"
          CACHE INTERNAL "Compiler support for a deprecated attribute")
      else()
        _check_c_compiler_attribute("__declspec(deprecated)"
          COMPILER_HAS_DEPRECATED)
      endif()

271
    endif()
272 273 274
  endif()
endmacro()

275 276
get_filename_component(_GENERATE_EXPORT_HEADER_MODULE_DIR
  "${CMAKE_CURRENT_LIST_FILE}" PATH)
277 278 279 280 281 282 283

macro(_DO_SET_MACRO_VALUES TARGET_LIBRARY)
  set(DEFINE_DEPRECATED)
  set(DEFINE_EXPORT)
  set(DEFINE_IMPORT)
  set(DEFINE_NO_EXPORT)

284
  if (COMPILER_HAS_DEPRECATED_ATTR)
285
    set(DEFINE_DEPRECATED "__attribute__ ((__deprecated__))")
286 287
  elseif(COMPILER_HAS_DEPRECATED)
    set(DEFINE_DEPRECATED "__declspec(deprecated)")
288 289 290 291 292
  endif()

  get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)

  if(NOT ${type} STREQUAL "STATIC_LIBRARY")
293
    if(WIN32 OR CYGWIN)
294 295
      set(DEFINE_EXPORT "__declspec(dllexport)")
      set(DEFINE_IMPORT "__declspec(dllimport)")
296
    elseif(COMPILER_HAS_HIDDEN_VISIBILITY)
297 298 299
      set(DEFINE_EXPORT "__attribute__((visibility(\"default\")))")
      set(DEFINE_IMPORT "__attribute__((visibility(\"default\")))")
      set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))")
300 301 302 303 304 305
    endif()
  endif()
endmacro()

macro(_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY)
  # Option overrides
306
  set(options DEFINE_NO_DEPRECATED)
307 308
  set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME EXPORT_FILE_NAME
    DEPRECATED_MACRO_NAME NO_EXPORT_MACRO_NAME STATIC_DEFINE
309
    NO_DEPRECATED_MACRO_NAME CUSTOM_CONTENT_FROM_VARIABLE INCLUDE_GUARD_NAME)
310 311
  set(multiValueArgs)

312 313
  cmake_parse_arguments(_GEH "${options}" "${oneValueArgs}" "${multiValueArgs}"
    ${ARGN})
314 315 316 317 318 319 320 321 322 323 324

  set(BASE_NAME "${TARGET_LIBRARY}")

  if(_GEH_BASE_NAME)
    set(BASE_NAME ${_GEH_BASE_NAME})
  endif()

  string(TOUPPER ${BASE_NAME} BASE_NAME_UPPER)
  string(TOLOWER ${BASE_NAME} BASE_NAME_LOWER)

  # Default options
325 326
  set(EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_EXPORT")
  set(NO_EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_EXPORT")
327
  set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME_LOWER}_export.h")
328 329
  set(DEPRECATED_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_DEPRECATED")
  set(STATIC_DEFINE "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_STATIC_DEFINE")
330 331
  set(NO_DEPRECATED_MACRO_NAME
    "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_DEPRECATED")
332 333 334 335 336 337

  if(_GEH_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "Unknown keywords given to GENERATE_EXPORT_HEADER(): \"${_GEH_UNPARSED_ARGUMENTS}\"")
  endif()

  if(_GEH_EXPORT_MACRO_NAME)
338
    set(EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_EXPORT_MACRO_NAME})
339
  endif()
340
  string(MAKE_C_IDENTIFIER ${EXPORT_MACRO_NAME} EXPORT_MACRO_NAME)
341
  if(_GEH_EXPORT_FILE_NAME)
342
    if(IS_ABSOLUTE ${_GEH_EXPORT_FILE_NAME})
343 344 345 346 347
      set(EXPORT_FILE_NAME ${_GEH_EXPORT_FILE_NAME})
    else()
      set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_GEH_EXPORT_FILE_NAME}")
    endif()
  endif()
348
  if(_GEH_DEPRECATED_MACRO_NAME)
349
    set(DEPRECATED_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_DEPRECATED_MACRO_NAME})
350
  endif()
351
  string(MAKE_C_IDENTIFIER ${DEPRECATED_MACRO_NAME} DEPRECATED_MACRO_NAME)
352
  if(_GEH_NO_EXPORT_MACRO_NAME)
353
    set(NO_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_NO_EXPORT_MACRO_NAME})
354
  endif()
355
  string(MAKE_C_IDENTIFIER ${NO_EXPORT_MACRO_NAME} NO_EXPORT_MACRO_NAME)
356
  if(_GEH_STATIC_DEFINE)
357
    set(STATIC_DEFINE ${_GEH_PREFIX_NAME}${_GEH_STATIC_DEFINE})
358
  endif()
359
  string(MAKE_C_IDENTIFIER ${STATIC_DEFINE} STATIC_DEFINE)
360

361
  if(_GEH_DEFINE_NO_DEPRECATED)
362 363 364
    set(DEFINE_NO_DEPRECATED 1)
  else()
    set(DEFINE_NO_DEPRECATED 0)
365 366
  endif()

367 368 369
  if(_GEH_NO_DEPRECATED_MACRO_NAME)
    set(NO_DEPRECATED_MACRO_NAME
      ${_GEH_PREFIX_NAME}${_GEH_NO_DEPRECATED_MACRO_NAME})
370
  endif()
371
  string(MAKE_C_IDENTIFIER ${NO_DEPRECATED_MACRO_NAME} NO_DEPRECATED_MACRO_NAME)
372

373 374 375 376 377
  if(_GEH_INCLUDE_GUARD_NAME)
    set(INCLUDE_GUARD_NAME ${_GEH_INCLUDE_GUARD_NAME})
  else()
    set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H")
  endif()
378

379 380
  get_target_property(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY} DEFINE_SYMBOL)

381
  if(NOT EXPORT_IMPORT_CONDITION)
382 383
    set(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY}_EXPORTS)
  endif()
384
  string(MAKE_C_IDENTIFIER ${EXPORT_IMPORT_CONDITION} EXPORT_IMPORT_CONDITION)
385

386 387 388 389 390 391 392 393
  if(_GEH_CUSTOM_CONTENT_FROM_VARIABLE)
    if(DEFINED "${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}")
      set(CUSTOM_CONTENT "${${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}}")
    else()
      set(CUSTOM_CONTENT "")
    endif()
  endif()

394 395
  configure_file("${_GENERATE_EXPORT_HEADER_MODULE_DIR}/exportheader.cmake.in"
    "${EXPORT_FILE_NAME}" @ONLY)
396 397 398 399
endmacro()

function(GENERATE_EXPORT_HEADER TARGET_LIBRARY)
  get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)
400 401
  if(NOT ${type} STREQUAL "STATIC_LIBRARY"
      AND NOT ${type} STREQUAL "SHARED_LIBRARY"
402
      AND NOT ${type} STREQUAL "OBJECT_LIBRARY"
403
      AND NOT ${type} STREQUAL "MODULE_LIBRARY")
404 405 406 407
    message(WARNING "This macro can only be used with libraries")
    return()
  endif()
  _test_compiler_hidden_visibility()
408
  _test_compiler_has_deprecated()
409 410 411 412
  _do_set_macro_values(${TARGET_LIBRARY})
  _do_generate_export_header(${TARGET_LIBRARY} ${ARGN})
endfunction()

413
function(add_compiler_export_flags)
414
  if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
415
    message(DEPRECATION "The add_compiler_export_flags function is obsolete. Use the CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN target properties instead.")
416
  endif()
417

418
  _test_compiler_hidden_visibility()
419
  _test_compiler_has_deprecated()
420

421 422 423
  option(USE_COMPILER_HIDDEN_VISIBILITY
    "Use HIDDEN visibility support if available." ON)
  mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY)
424
  if(NOT (USE_COMPILER_HIDDEN_VISIBILITY AND COMPILER_HAS_HIDDEN_VISIBILITY))
425
    # Just return if there are no flags to add.
426 427 428
    return()
  endif()

429
  set (EXTRA_FLAGS "-fvisibility=hidden")
430

431 432
  if(COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
    set (EXTRA_FLAGS "${EXTRA_FLAGS} -fvisibility-inlines-hidden")
433
  endif()
434 435 436

  # Either return the extra flags needed in the supplied argument, or to the
  # CMAKE_CXX_FLAGS if no argument is supplied.
437
  if(ARGC GREATER 0)
438
    set(${ARGV0} "${EXTRA_FLAGS}" PARENT_SCOPE)
439
  else()
440 441
    string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
442
  endif()
443
endfunction()