1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2# file Copyright.txt or https://cmake.org/licensing for details. 3 4#[=======================================================================[.rst: 5GenerateExportHeader 6-------------------- 7 8Function for generation of export macros for libraries 9 10This module provides the function ``GENERATE_EXPORT_HEADER()``. 11 12.. versionadded:: 3.12 13 Added support for C projects. Previous versions supported C++ project only. 14 15The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file 16suitable for preprocessor inclusion which contains EXPORT macros to be 17used in library classes:: 18 19 GENERATE_EXPORT_HEADER( LIBRARY_TARGET 20 [BASE_NAME <base_name>] 21 [EXPORT_MACRO_NAME <export_macro_name>] 22 [EXPORT_FILE_NAME <export_file_name>] 23 [DEPRECATED_MACRO_NAME <deprecated_macro_name>] 24 [NO_EXPORT_MACRO_NAME <no_export_macro_name>] 25 [INCLUDE_GUARD_NAME <include_guard_name>] 26 [STATIC_DEFINE <static_define>] 27 [NO_DEPRECATED_MACRO_NAME <no_deprecated_macro_name>] 28 [DEFINE_NO_DEPRECATED] 29 [PREFIX_NAME <prefix_name>] 30 [CUSTOM_CONTENT_FROM_VARIABLE <variable>] 31 ) 32 33The target properties :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` 34and :prop_tgt:`VISIBILITY_INLINES_HIDDEN` can be used to add the appropriate 35compile flags for targets. See the documentation of those target properties, 36and the convenience variables 37:variable:`CMAKE_CXX_VISIBILITY_PRESET <CMAKE_<LANG>_VISIBILITY_PRESET>` and 38:variable:`CMAKE_VISIBILITY_INLINES_HIDDEN`. 39 40By default ``GENERATE_EXPORT_HEADER()`` generates macro names in a file 41name determined by the name of the library. This means that in the 42simplest case, users of ``GenerateExportHeader`` will be equivalent to: 43 44.. code-block:: cmake 45 46 set(CMAKE_CXX_VISIBILITY_PRESET hidden) 47 set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) 48 add_library(somelib someclass.cpp) 49 generate_export_header(somelib) 50 install(TARGETS somelib DESTINATION ${LIBRARY_INSTALL_DIR}) 51 install(FILES 52 someclass.h 53 ${PROJECT_BINARY_DIR}/somelib_export.h DESTINATION ${INCLUDE_INSTALL_DIR} 54 ) 55 56 57And in the ABI header files: 58 59.. code-block:: c++ 60 61 #include "somelib_export.h" 62 class SOMELIB_EXPORT SomeClass { 63 ... 64 }; 65 66 67The CMake fragment will generate a file in the 68``${CMAKE_CURRENT_BINARY_DIR}`` called ``somelib_export.h`` containing the 69macros ``SOMELIB_EXPORT``, ``SOMELIB_NO_EXPORT``, ``SOMELIB_DEPRECATED``, 70``SOMELIB_DEPRECATED_EXPORT`` and ``SOMELIB_DEPRECATED_NO_EXPORT``. 71They will be followed by content taken from the variable specified by 72the ``CUSTOM_CONTENT_FROM_VARIABLE`` option, if any. 73The resulting file should be installed with other headers in the library. 74 75The ``BASE_NAME`` argument can be used to override the file name and the 76names used for the macros: 77 78.. code-block:: cmake 79 80 add_library(somelib someclass.cpp) 81 generate_export_header(somelib 82 BASE_NAME other_name 83 ) 84 85 86Generates a file called ``other_name_export.h`` containing the macros 87``OTHER_NAME_EXPORT``, ``OTHER_NAME_NO_EXPORT`` and ``OTHER_NAME_DEPRECATED`` 88etc. 89 90The ``BASE_NAME`` may be overridden by specifying other options in the 91function. For example: 92 93.. code-block:: cmake 94 95 add_library(somelib someclass.cpp) 96 generate_export_header(somelib 97 EXPORT_MACRO_NAME OTHER_NAME_EXPORT 98 ) 99 100 101creates the macro ``OTHER_NAME_EXPORT`` instead of ``SOMELIB_EXPORT``, but 102other macros and the generated file name is as default: 103 104.. code-block:: cmake 105 106 add_library(somelib someclass.cpp) 107 generate_export_header(somelib 108 DEPRECATED_MACRO_NAME KDE_DEPRECATED 109 ) 110 111 112creates the macro ``KDE_DEPRECATED`` instead of ``SOMELIB_DEPRECATED``. 113 114If ``LIBRARY_TARGET`` is a static library, macros are defined without 115values. 116 117If the same sources are used to create both a shared and a static 118library, the uppercased symbol ``${BASE_NAME}_STATIC_DEFINE`` should be 119used when building the static library: 120 121.. code-block:: cmake 122 123 add_library(shared_variant SHARED ${lib_SRCS}) 124 add_library(static_variant ${lib_SRCS}) 125 generate_export_header(shared_variant BASE_NAME libshared_and_static) 126 set_target_properties(static_variant PROPERTIES 127 COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE) 128 129This will cause the export macros to expand to nothing when building 130the static library. 131 132If ``DEFINE_NO_DEPRECATED`` is specified, then a macro 133``${BASE_NAME}_NO_DEPRECATED`` will be defined This macro can be used to 134remove deprecated code from preprocessor output: 135 136.. code-block:: cmake 137 138 option(EXCLUDE_DEPRECATED "Exclude deprecated parts of the library" FALSE) 139 if (EXCLUDE_DEPRECATED) 140 set(NO_BUILD_DEPRECATED DEFINE_NO_DEPRECATED) 141 endif() 142 generate_export_header(somelib ${NO_BUILD_DEPRECATED}) 143 144 145And then in somelib: 146 147.. code-block:: c++ 148 149 class SOMELIB_EXPORT SomeClass 150 { 151 public: 152 #ifndef SOMELIB_NO_DEPRECATED 153 SOMELIB_DEPRECATED void oldMethod(); 154 #endif 155 }; 156 157.. code-block:: c++ 158 159 #ifndef SOMELIB_NO_DEPRECATED 160 void SomeClass::oldMethod() { } 161 #endif 162 163 164If ``PREFIX_NAME`` is specified, the argument will be used as a prefix to 165all generated macros. 166 167For example: 168 169.. code-block:: cmake 170 171 generate_export_header(somelib PREFIX_NAME VTK_) 172 173Generates the macros ``VTK_SOMELIB_EXPORT`` etc. 174 175.. versionadded:: 3.1 176 Library target can be an ``OBJECT`` library. 177 178.. versionadded:: 3.7 179 Added the ``CUSTOM_CONTENT_FROM_VARIABLE`` option. 180 181.. versionadded:: 3.11 182 Added the ``INCLUDE_GUARD_NAME`` option. 183 184:: 185 186 ADD_COMPILER_EXPORT_FLAGS( [<output_variable>] ) 187 188.. deprecated:: 3.0 189 Set the target properties 190 :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and 191 :prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead. 192 193The ``ADD_COMPILER_EXPORT_FLAGS`` function adds ``-fvisibility=hidden`` to 194:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` if supported, and is a no-op 195on Windows which does not need extra compiler flags for exporting support. 196You may optionally pass a single argument to ``ADD_COMPILER_EXPORT_FLAGS`` 197that will be populated with the ``CXX_FLAGS`` required to enable visibility 198support for the compiler/architecture in use. 199#]=======================================================================] 200 201include(CheckCCompilerFlag) 202include(CheckCXXCompilerFlag) 203 204# TODO: Install this macro separately? 205macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT) 206 check_cxx_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; } 207 int main() { return somefunc();}" ${_RESULT} 208 ) 209endmacro() 210 211# TODO: Install this macro separately? 212macro(_check_c_compiler_attribute _ATTRIBUTE _RESULT) 213 check_c_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; } 214 int main() { return somefunc();}" ${_RESULT} 215 ) 216endmacro() 217 218macro(_test_compiler_hidden_visibility) 219 220 if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2") 221 set(GCC_TOO_OLD TRUE) 222 elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2") 223 set(GCC_TOO_OLD TRUE) 224 elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0") 225 set(_INTEL_TOO_OLD TRUE) 226 endif() 227 228 # Exclude XL here because it misinterprets -fvisibility=hidden even though 229 # the check_cxx_compiler_flag passes 230 if(NOT GCC_TOO_OLD 231 AND NOT _INTEL_TOO_OLD 232 AND NOT WIN32 233 AND NOT CYGWIN 234 AND NOT CMAKE_CXX_COMPILER_ID MATCHES XL 235 AND NOT CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$" 236 AND NOT CMAKE_CXX_COMPILER_ID MATCHES Watcom) 237 if (CMAKE_CXX_COMPILER_LOADED) 238 check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) 239 check_cxx_compiler_flag(-fvisibility-inlines-hidden 240 COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) 241 else() 242 check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) 243 check_c_compiler_flag(-fvisibility-inlines-hidden 244 COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) 245 endif() 246 endif() 247endmacro() 248 249macro(_test_compiler_has_deprecated) 250 # NOTE: Some Embarcadero compilers silently compile __declspec(deprecated) 251 # without error, but this is not a documented feature and the attribute does 252 # not actually generate any warnings. 253 if(CMAKE_CXX_COMPILER_ID MATCHES Borland 254 OR CMAKE_CXX_COMPILER_ID MATCHES Embarcadero 255 OR CMAKE_CXX_COMPILER_ID MATCHES HP 256 OR GCC_TOO_OLD 257 OR CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$" 258 OR CMAKE_CXX_COMPILER_ID MATCHES Watcom) 259 set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL 260 "Compiler support for a deprecated attribute") 261 else() 262 if (CMAKE_CXX_COMPILER_LOADED) 263 _check_cxx_compiler_attribute("__attribute__((__deprecated__))" 264 COMPILER_HAS_DEPRECATED_ATTR) 265 if(COMPILER_HAS_DEPRECATED_ATTR) 266 set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}" 267 CACHE INTERNAL "Compiler support for a deprecated attribute") 268 else() 269 _check_cxx_compiler_attribute("__declspec(deprecated)" 270 COMPILER_HAS_DEPRECATED) 271 endif() 272 else() 273 _check_c_compiler_attribute("__attribute__((__deprecated__))" 274 COMPILER_HAS_DEPRECATED_ATTR) 275 if(COMPILER_HAS_DEPRECATED_ATTR) 276 set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}" 277 CACHE INTERNAL "Compiler support for a deprecated attribute") 278 else() 279 _check_c_compiler_attribute("__declspec(deprecated)" 280 COMPILER_HAS_DEPRECATED) 281 endif() 282 283 endif() 284 endif() 285endmacro() 286 287get_filename_component(_GENERATE_EXPORT_HEADER_MODULE_DIR 288 "${CMAKE_CURRENT_LIST_FILE}" PATH) 289 290macro(_DO_SET_MACRO_VALUES TARGET_LIBRARY) 291 set(DEFINE_DEPRECATED) 292 set(DEFINE_EXPORT) 293 set(DEFINE_IMPORT) 294 set(DEFINE_NO_EXPORT) 295 296 if (COMPILER_HAS_DEPRECATED_ATTR) 297 set(DEFINE_DEPRECATED "__attribute__ ((__deprecated__))") 298 elseif(COMPILER_HAS_DEPRECATED) 299 set(DEFINE_DEPRECATED "__declspec(deprecated)") 300 endif() 301 302 get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE) 303 304 if(NOT ${type} STREQUAL "STATIC_LIBRARY") 305 if(WIN32 OR CYGWIN) 306 set(DEFINE_EXPORT "__declspec(dllexport)") 307 set(DEFINE_IMPORT "__declspec(dllimport)") 308 elseif(COMPILER_HAS_HIDDEN_VISIBILITY) 309 set(DEFINE_EXPORT "__attribute__((visibility(\"default\")))") 310 set(DEFINE_IMPORT "__attribute__((visibility(\"default\")))") 311 set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))") 312 endif() 313 endif() 314endmacro() 315 316macro(_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY) 317 # Option overrides 318 set(options DEFINE_NO_DEPRECATED) 319 set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME EXPORT_FILE_NAME 320 DEPRECATED_MACRO_NAME NO_EXPORT_MACRO_NAME STATIC_DEFINE 321 NO_DEPRECATED_MACRO_NAME CUSTOM_CONTENT_FROM_VARIABLE INCLUDE_GUARD_NAME) 322 set(multiValueArgs) 323 324 cmake_parse_arguments(_GEH "${options}" "${oneValueArgs}" "${multiValueArgs}" 325 ${ARGN}) 326 327 set(BASE_NAME "${TARGET_LIBRARY}") 328 329 if(_GEH_BASE_NAME) 330 set(BASE_NAME ${_GEH_BASE_NAME}) 331 endif() 332 333 string(TOUPPER ${BASE_NAME} BASE_NAME_UPPER) 334 string(TOLOWER ${BASE_NAME} BASE_NAME_LOWER) 335 336 # Default options 337 set(EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_EXPORT") 338 set(NO_EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_EXPORT") 339 set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME_LOWER}_export.h") 340 set(DEPRECATED_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_DEPRECATED") 341 set(STATIC_DEFINE "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_STATIC_DEFINE") 342 set(NO_DEPRECATED_MACRO_NAME 343 "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_DEPRECATED") 344 345 if(_GEH_UNPARSED_ARGUMENTS) 346 message(FATAL_ERROR "Unknown keywords given to GENERATE_EXPORT_HEADER(): \"${_GEH_UNPARSED_ARGUMENTS}\"") 347 endif() 348 349 if(_GEH_EXPORT_MACRO_NAME) 350 set(EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_EXPORT_MACRO_NAME}) 351 endif() 352 string(MAKE_C_IDENTIFIER ${EXPORT_MACRO_NAME} EXPORT_MACRO_NAME) 353 if(_GEH_EXPORT_FILE_NAME) 354 if(IS_ABSOLUTE ${_GEH_EXPORT_FILE_NAME}) 355 set(EXPORT_FILE_NAME ${_GEH_EXPORT_FILE_NAME}) 356 else() 357 set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_GEH_EXPORT_FILE_NAME}") 358 endif() 359 endif() 360 if(_GEH_DEPRECATED_MACRO_NAME) 361 set(DEPRECATED_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_DEPRECATED_MACRO_NAME}) 362 endif() 363 string(MAKE_C_IDENTIFIER ${DEPRECATED_MACRO_NAME} DEPRECATED_MACRO_NAME) 364 if(_GEH_NO_EXPORT_MACRO_NAME) 365 set(NO_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_NO_EXPORT_MACRO_NAME}) 366 endif() 367 string(MAKE_C_IDENTIFIER ${NO_EXPORT_MACRO_NAME} NO_EXPORT_MACRO_NAME) 368 if(_GEH_STATIC_DEFINE) 369 set(STATIC_DEFINE ${_GEH_PREFIX_NAME}${_GEH_STATIC_DEFINE}) 370 endif() 371 string(MAKE_C_IDENTIFIER ${STATIC_DEFINE} STATIC_DEFINE) 372 373 if(_GEH_DEFINE_NO_DEPRECATED) 374 set(DEFINE_NO_DEPRECATED 1) 375 else() 376 set(DEFINE_NO_DEPRECATED 0) 377 endif() 378 379 if(_GEH_NO_DEPRECATED_MACRO_NAME) 380 set(NO_DEPRECATED_MACRO_NAME 381 ${_GEH_PREFIX_NAME}${_GEH_NO_DEPRECATED_MACRO_NAME}) 382 endif() 383 string(MAKE_C_IDENTIFIER ${NO_DEPRECATED_MACRO_NAME} NO_DEPRECATED_MACRO_NAME) 384 385 if(_GEH_INCLUDE_GUARD_NAME) 386 set(INCLUDE_GUARD_NAME ${_GEH_INCLUDE_GUARD_NAME}) 387 else() 388 set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H") 389 endif() 390 391 get_target_property(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY} DEFINE_SYMBOL) 392 393 if(NOT EXPORT_IMPORT_CONDITION) 394 set(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY}_EXPORTS) 395 endif() 396 string(MAKE_C_IDENTIFIER ${EXPORT_IMPORT_CONDITION} EXPORT_IMPORT_CONDITION) 397 398 if(_GEH_CUSTOM_CONTENT_FROM_VARIABLE) 399 if(DEFINED "${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}") 400 set(CUSTOM_CONTENT "${${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}}") 401 else() 402 set(CUSTOM_CONTENT "") 403 endif() 404 endif() 405 406 configure_file("${_GENERATE_EXPORT_HEADER_MODULE_DIR}/exportheader.cmake.in" 407 "${EXPORT_FILE_NAME}" @ONLY) 408endmacro() 409 410function(GENERATE_EXPORT_HEADER TARGET_LIBRARY) 411 get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE) 412 if(NOT ${type} STREQUAL "STATIC_LIBRARY" 413 AND NOT ${type} STREQUAL "SHARED_LIBRARY" 414 AND NOT ${type} STREQUAL "OBJECT_LIBRARY" 415 AND NOT ${type} STREQUAL "MODULE_LIBRARY") 416 message(WARNING "This macro can only be used with libraries") 417 return() 418 endif() 419 _test_compiler_hidden_visibility() 420 _test_compiler_has_deprecated() 421 _do_set_macro_values(${TARGET_LIBRARY}) 422 _do_generate_export_header(${TARGET_LIBRARY} ${ARGN}) 423endfunction() 424 425function(add_compiler_export_flags) 426 if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) 427 message(DEPRECATION "The add_compiler_export_flags function is obsolete. Use the CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN target properties instead.") 428 endif() 429 430 _test_compiler_hidden_visibility() 431 _test_compiler_has_deprecated() 432 433 option(USE_COMPILER_HIDDEN_VISIBILITY 434 "Use HIDDEN visibility support if available." ON) 435 mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY) 436 if(NOT (USE_COMPILER_HIDDEN_VISIBILITY AND COMPILER_HAS_HIDDEN_VISIBILITY)) 437 # Just return if there are no flags to add. 438 return() 439 endif() 440 441 set (EXTRA_FLAGS "-fvisibility=hidden") 442 443 if(COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) 444 set (EXTRA_FLAGS "${EXTRA_FLAGS} -fvisibility-inlines-hidden") 445 endif() 446 447 # Either return the extra flags needed in the supplied argument, or to the 448 # CMAKE_CXX_FLAGS if no argument is supplied. 449 if(ARGC GREATER 0) 450 set(${ARGV0} "${EXTRA_FLAGS}" PARENT_SCOPE) 451 else() 452 string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAGS}") 453 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) 454 endif() 455endfunction() 456