1# - Function for generation of export macros for libraries
2# This module provides the function GENERATE_EXPORT_HEADER() and the
3# accompanying ADD_COMPILER_EXPORT_FLAGS() function.
4#
5# The GENERATE_EXPORT_HEADER function can be used to generate a file suitable
6# for preprocessor inclusion which contains EXPORT macros to be used in
7# library classes.
8#
9# GENERATE_EXPORT_HEADER( LIBRARY_TARGET
10#             [BASE_NAME <base_name>]
11#             [EXPORT_MACRO_NAME <export_macro_name>]
12#             [EXPORT_FILE_NAME <export_file_name>]
13#             [DEPRECATED_MACRO_NAME <deprecated_macro_name>]
14#             [NO_EXPORT_MACRO_NAME <no_export_macro_name>]
15#             [STATIC_DEFINE <static_define>]
16#             [NO_DEPRECATED_MACRO_NAME <no_deprecated_macro_name>]
17#             [DEFINE_NO_DEPRECATED]
18#             [PREFIX_NAME <prefix_name>]
19# )
20#
21# ADD_COMPILER_EXPORT_FLAGS( [FATAL_WARNINGS] )
22#
23# By default GENERATE_EXPORT_HEADER() generates macro names in a file name
24# determined by the name of the library. The ADD_COMPILER_EXPORT_FLAGS function
25# adds -fvisibility=hidden to CMAKE_CXX_FLAGS if supported, and is a no-op on
26# Windows which does not need extra compiler flags for exporting support. You
27# may optionally pass a single argument to ADD_COMPILER_EXPORT_FLAGS that will
28# be populated with the required CXX_FLAGS required to enable visibility support
29# for the compiler/architecture in use.
30#
31# This means that in the simplest case, users of these functions will be
32# equivalent to:
33#
34#   add_compiler_export_flags()
35#   add_library(somelib someclass.cpp)
36#   generate_export_header(somelib)
37#   install(TARGETS somelib DESTINATION ${LIBRARY_INSTALL_DIR})
38#   install(FILES
39#    someclass.h
40#    ${PROJECT_BINARY_DIR}/somelib_export.h DESTINATION ${INCLUDE_INSTALL_DIR}
41#   )
42#
43# And in the ABI header files:
44#
45#   #include "somelib_export.h"
46#   class SOMELIB_EXPORT SomeClass {
47#     ...
48#   };
49#
50# The CMake fragment will generate a file in the ${CMAKE_CURRENT_BUILD_DIR}
51# called somelib_export.h containing the macros SOMELIB_EXPORT, SOMELIB_NO_EXPORT,
52# SOMELIB_DEPRECATED, SOMELIB_DEPRECATED_EXPORT and SOMELIB_DEPRECATED_NO_EXPORT.
53# The resulting file should be installed with other headers in the library.
54# Set variable <LIBRARY_TARGET>_EXPORT_CODE to specify custom content.
55#
56# The BASE_NAME argument can be used to override the file name and the names
57# used for the macros
58#
59#   add_library(somelib someclass.cpp)
60#   generate_export_header(somelib
61#     BASE_NAME other_name
62#   )
63#
64# Generates a file called other_name_export.h containing the macros
65# OTHER_NAME_EXPORT, OTHER_NAME_NO_EXPORT and OTHER_NAME_DEPRECATED etc.
66#
67# The BASE_NAME may be overridden by specifiying other options in the function.
68# For example:
69#
70#   add_library(somelib someclass.cpp)
71#   generate_export_header(somelib
72#     EXPORT_MACRO_NAME OTHER_NAME_EXPORT
73#   )
74#
75# creates the macro OTHER_NAME_EXPORT instead of SOMELIB_EXPORT, but other macros
76# and the generated file name is as default.
77#
78#   add_library(somelib someclass.cpp)
79#   generate_export_header(somelib
80#     DEPRECATED_MACRO_NAME KDE_DEPRECATED
81#   )
82#
83# creates the macro KDE_DEPRECATED instead of SOMELIB_DEPRECATED.
84#
85# If LIBRARY_TARGET is a static library, macros are defined without values.
86#
87# If the same sources are used to create both a shared and a static library, the
88# uppercased symbol ${BASE_NAME}_STATIC_DEFINE should be used when building the
89# static library
90#
91#   add_library(shared_variant SHARED ${lib_SRCS})
92#   add_library(static_variant ${lib_SRCS})
93#   generate_export_header(shared_variant BASE_NAME libshared_and_static)
94#   set_target_properties(static_variant PROPERTIES
95#     COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE)
96#
97# This will cause the export macros to expand to nothing when building the
98# static library.
99#
100# If DEFINE_NO_DEPRECATED is specified, then a macro ${BASE_NAME}_NO_DEPRECATED
101# will be defined
102# This macro can be used to remove deprecated code from preprocessor output.
103#
104#   option(EXCLUDE_DEPRECATED "Exclude deprecated parts of the library" FALSE)
105#   if (EXCLUDE_DEPRECATED)
106#     set(NO_BUILD_DEPRECATED DEFINE_NO_DEPRECATED)
107#   endif()
108#   generate_export_header(somelib ${NO_BUILD_DEPRECATED})
109#
110# And then in somelib:
111#
112#   class SOMELIB_EXPORT SomeClass
113#   {
114#   public:
115#   #ifndef SOMELIB_NO_DEPRECATED
116#     SOMELIB_DEPRECATED void oldMethod();
117#   #endif
118#   };
119#
120#   #ifndef SOMELIB_NO_DEPRECATED
121#   void SomeClass::oldMethod() {  }
122#   #endif
123#
124# If PREFIX_NAME is specified, the argument will be used as a prefix to all
125# generated macros.
126#
127# For example:
128#
129#   generate_export_header(somelib PREFIX_NAME VTK_)
130#
131# Generates the macros VTK_SOMELIB_EXPORT etc.
132
133#=============================================================================
134# Copyright 2011 Stephen Kelly <steveire@gmail.com>
135#
136# Distributed under the OSI-approved BSD License (the "License");
137# see accompanying file Copyright.txt for details.
138#
139# This software is distributed WITHOUT ANY WARRANTY; without even the
140# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
141# See the License for more information.
142#=============================================================================
143# (To distribute this file outside of CMake, substitute the full
144#  License text for the above reference.)
145
146include(CMakeParseArguments)
147include(CheckCXXCompilerFlag)
148
149# TODO: Install this macro separately?
150macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT)
151  check_cxx_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; }
152    int main() { return somefunc();}" ${_RESULT}
153    # Some compilers do not fail with a bad flag
154    FAIL_REGEX "unrecognized .*option"                     # GNU
155    FAIL_REGEX "ignoring unknown option"                   # MSVC
156    FAIL_REGEX "warning D9002"                             # MSVC, any lang
157    FAIL_REGEX "[Uu]nknown option"                         # HP
158    FAIL_REGEX "[Ww]arning: [Oo]ption"                     # SunPro
159    FAIL_REGEX "command option .* is not recognized"       # XL
160  )
161endmacro()
162
163macro(_test_compiler_hidden_visibility)
164
165  if(CMAKE_COMPILER_IS_GNUCXX)
166    execute_process(COMMAND ${CMAKE_C_COMPILER} ARGS --version
167      OUTPUT_VARIABLE _gcc_version_info
168      ERROR_VARIABLE _gcc_version_info)
169    string(REGEX MATCH "[0-9]\\.[0-9]"
170      _gcc_version "${_gcc_version_info}")
171    # gcc on mac just reports: "gcc (GCC) 3.3 20030304 ..." without the
172    # patch level, handle this here:
173    if(NOT _gcc_version)
174      string(REGEX REPLACE ".*\\(GCC\\).*([34]\\.[0-9]).*" "\\1.0"
175        _gcc_version "${_gcc_version_info}")
176    endif()
177
178    if(${_gcc_version} VERSION_LESS "4.2")
179      set(GCC_TOO_OLD TRUE)
180    endif()
181  endif()
182
183  if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
184    execute_process(COMMAND ${CMAKE_CXX_COMPILER} ARGS -V
185      OUTPUT_VARIABLE _intel_version_info
186      ERROR_VARIABLE _intel_version_info)
187    string(REGEX REPLACE ".*Version ([0-9]+(\\.[0-9]+)+).*" "\\1"
188      _intel_version "${_intel_version_info}")
189
190    if(_intel_version VERSION_LESS "12.0")
191      set(_INTEL_TOO_OLD TRUE)
192    endif()
193  endif()
194
195
196  # Exclude XL here because it misinterprets -fvisibility=hidden even though
197  # the check_cxx_compiler_flag passes
198  # http://www.cdash.org/CDash/testDetails.php?test=109109951&build=1419259
199  if(NOT GCC_TOO_OLD
200      AND NOT _INTEL_TOO_OLD
201      AND NOT WIN32
202      AND NOT CYGWIN
203      AND NOT CMAKE_CXX_COMPILER_ID MATCHES "XL"
204      AND NOT CMAKE_CXX_COMPILER_ID MATCHES "PGI"
205      AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
206    check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
207    check_cxx_compiler_flag(-fvisibility-inlines-hidden
208      COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
209    option(USE_COMPILER_HIDDEN_VISIBILITY
210      "Use HIDDEN visibility support if available." ON)
211    mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY)
212  endif()
213endmacro()
214
215macro(_test_compiler_has_deprecated)
216  if(CMAKE_CXX_COMPILER_ID MATCHES "Borland"
217      OR CMAKE_CXX_COMPILER_ID MATCHES "HP"
218      OR GCC_TOO_OLD
219      OR CMAKE_CXX_COMPILER_ID MATCHES "PGI"
220      OR CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
221    set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL
222      "Compiler support for a deprecated attribute")
223  else()
224    _check_cxx_compiler_attribute("__attribute__((__deprecated__))"
225      COMPILER_HAS_DEPRECATED_ATTR)
226    if(COMPILER_HAS_DEPRECATED_ATTR)
227      set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}"
228        CACHE INTERNAL "Compiler support for a deprecated attribute")
229    else()
230      _check_cxx_compiler_attribute("__declspec(deprecated)"
231        COMPILER_HAS_DEPRECATED)
232    endif()
233  endif()
234endmacro()
235
236get_filename_component(_GENERATE_EXPORT_HEADER_MODULE_DIR
237  "${CMAKE_CURRENT_LIST_FILE}" PATH)
238
239macro(_DO_SET_MACRO_VALUES TARGET_LIBRARY)
240  set(DEFINE_DEPRECATED)
241  set(DEFINE_EXPORT)
242  set(DEFINE_IMPORT)
243  set(DEFINE_NO_EXPORT)
244
245  if (COMPILER_HAS_DEPRECATED_ATTR)
246    set(DEFINE_DEPRECATED "__attribute__ ((__deprecated__))")
247  elseif(COMPILER_HAS_DEPRECATED)
248    set(DEFINE_DEPRECATED "__declspec(deprecated)")
249  endif()
250
251  get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)
252
253  if(NOT type STREQUAL "STATIC_LIBRARY")
254    if(WIN32)
255      set(DEFINE_EXPORT "__declspec(dllexport)")
256      set(DEFINE_IMPORT "__declspec(dllimport)")
257    elseif(COMPILER_HAS_HIDDEN_VISIBILITY AND USE_COMPILER_HIDDEN_VISIBILITY)
258      set(DEFINE_EXPORT "__attribute__((visibility(\"default\")))")
259      set(DEFINE_IMPORT "__attribute__((visibility(\"default\")))")
260      set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))")
261    endif()
262  endif()
263endmacro()
264
265macro(_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY)
266  # Option overrides
267  set(options DEFINE_NO_DEPRECATED)
268  set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME EXPORT_FILE_NAME
269    DEPRECATED_MACRO_NAME NO_EXPORT_MACRO_NAME STATIC_DEFINE
270    NO_DEPRECATED_MACRO_NAME)
271  set(multiValueArgs)
272
273  cmake_parse_arguments(_GEH "${options}" "${oneValueArgs}" "${multiValueArgs}"
274    ${ARGN})
275
276  set(BASE_NAME "${TARGET_LIBRARY}")
277
278  if(_GEH_BASE_NAME)
279    set(BASE_NAME ${_GEH_BASE_NAME})
280  endif()
281
282  string(TOUPPER ${BASE_NAME} BASE_NAME_UPPER)
283  string(TOLOWER ${BASE_NAME} BASE_NAME_LOWER)
284
285  # Default options
286  set(EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_EXPORT")
287  set(NO_EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_EXPORT")
288  set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME_LOWER}_export.h")
289  set(DEPRECATED_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_DEPRECATED")
290  set(STATIC_DEFINE "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_STATIC_DEFINE")
291  set(NO_DEPRECATED_MACRO_NAME
292    "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_DEPRECATED")
293
294  if(_GEH_UNPARSED_ARGUMENTS)
295    message(FATAL_ERROR "Unknown keywords given to GENERATE_EXPORT_HEADER(): \"${_GEH_UNPARSED_ARGUMENTS}\"")
296  endif()
297
298  if(_GEH_EXPORT_MACRO_NAME)
299    set(EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_EXPORT_MACRO_NAME})
300  endif()
301  if(_GEH_EXPORT_FILE_NAME)
302    if(IS_ABSOLUTE _GEH_EXPORT_FILE_NAME)
303      set(EXPORT_FILE_NAME ${_GEH_EXPORT_FILE_NAME})
304    else()
305      set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_GEH_EXPORT_FILE_NAME}")
306    endif()
307  endif()
308  if(_GEH_DEPRECATED_MACRO_NAME)
309    set(DEPRECATED_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_DEPRECATED_MACRO_NAME})
310  endif()
311  if(_GEH_NO_EXPORT_MACRO_NAME)
312    set(NO_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_NO_EXPORT_MACRO_NAME})
313  endif()
314  if(_GEH_STATIC_DEFINE)
315    set(STATIC_DEFINE ${_GEH_PREFIX_NAME}${_GEH_STATIC_DEFINE})
316  endif()
317  if(DEFINED ${TARGET_LIBRARY}_EXPORT_CODE)
318    set(EXPORT_CODE "${${TARGET_LIBRARY}_EXPORT_CODE}")
319  else()
320    set(EXPORT_CODE "")
321  endif()
322
323  if(_GEH_DEFINE_NO_DEPRECATED)
324    set(DEFINE_NO_DEPRECATED TRUE)
325  endif()
326
327  if(_GEH_NO_DEPRECATED_MACRO_NAME)
328    set(NO_DEPRECATED_MACRO_NAME
329      ${_GEH_PREFIX_NAME}${_GEH_NO_DEPRECATED_MACRO_NAME})
330  endif()
331
332  set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H")
333
334  get_target_property(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY} DEFINE_SYMBOL)
335
336  if(NOT EXPORT_IMPORT_CONDITION)
337    set(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY}_EXPORTS)
338  endif()
339
340  configure_file("${_GENERATE_EXPORT_HEADER_MODULE_DIR}/exportheader.cmake.in"
341    "${EXPORT_FILE_NAME}" @ONLY)
342endmacro()
343
344function(GENERATE_EXPORT_HEADER TARGET_LIBRARY)
345  get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)
346  if(type STREQUAL "MODULE")
347    message(WARNING "This macro should not be used with libraries of type MODULE")
348    return()
349  endif()
350  if(NOT type STREQUAL "STATIC_LIBRARY" AND NOT type STREQUAL "SHARED_LIBRARY" AND NOT type STREQUAL "OBJECT_LIBRARY")
351    message(WARNING "This macro can only be used with libraries")
352    return()
353  endif()
354  _test_compiler_hidden_visibility()
355  _test_compiler_has_deprecated()
356  _do_set_macro_values(${TARGET_LIBRARY})
357  _do_generate_export_header(${TARGET_LIBRARY} ${ARGN})
358endfunction()
359
360function(add_compiler_export_flags)
361
362  _test_compiler_hidden_visibility()
363  _test_compiler_has_deprecated()
364
365  if(NOT (USE_COMPILER_HIDDEN_VISIBILITY AND COMPILER_HAS_HIDDEN_VISIBILITY))
366    # Just return if there are no flags to add.
367    return()
368  endif()
369
370  set (EXTRA_FLAGS "-fvisibility=hidden")
371
372  if(COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
373    set (EXTRA_FLAGS "${EXTRA_FLAGS} -fvisibility-inlines-hidden")
374  endif()
375
376  # Either return the extra flags needed in the supplied argument, or to the
377  # CMAKE_CXX_FLAGS if no argument is supplied.
378  if(ARGV0)
379    set(${ARGV0} "${EXTRA_FLAGS}" PARENT_SCOPE)
380  else()
381    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_FLAGS}" PARENT_SCOPE)
382  endif()
383endfunction()
384