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