File indexing completed on 2024-05-12 04:44:33

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 /** @file importexport.h
0005  *
0006  * This file provides support for C++ symbol import and export. */
0007 
0008 #ifndef IMPORTEXPORT_H
0009 #define IMPORTEXPORT_H
0010 
0011 #include <qglobal.h>
0012 
0013 /** @def PERCEPTUALCOLOR_IMPORTEXPORT
0014  *
0015  * @brief A macro that either exports dynamic library symbols or imports
0016  * dynamic library symbols or does nothing.
0017  *
0018  * This approach is proposed in Qt’s documentation (chapter “Creating
0019  * Shared Libraries”) – see there for more details. In short:
0020  *
0021  * @section buildappdynamic Build an application using the dynamic library
0022  *
0023  * When your application is build <em>using</em> the dynamic
0024  * library and includes the header files of the library, the
0025  * macro <em>imports</em> the corresponding symbols of the library
0026  * for you by expanding to Qt’s <tt>Q_DECL_IMPORT</tt> macro. This
0027  * is the default behaviour of this macro.
0028  *
0029  * @section buildlibdynamic Build the dynamic library
0030  *
0031  * When the dynamic library <em>itself</em> is build, the macro
0032  * <em>exports</em> the corresponding symbol by expanding to Qt’s
0033  * <tt>Q_DECL_EXPORT</tt> macro. Exported symbols will be visible
0034  * symbols in the dynamic library. To get this behaviour, it is
0035  * necessary to define <tt>PERCEPTUALCOLORLIB_BUILD_DYNAMIC_LIBRARY</tt>
0036  * always when this library itself is build.
0037  *
0038  * @section buildstatic Build either the static library itself or an application using it
0039  *
0040  * When either
0041  *
0042  * - building the static library itself
0043  *
0044  * or
0045  *
0046  * - your application is build <em>using</em> the static
0047  * library and includes the header files of the library,
0048  *
0049  * the macro expands to <em>nothing</em>, because for static libraries
0050  * no import nor export must happen. To get this behaviour, it is
0051  * necessary to define <tt>PERCEPTUALCOLORLIB_STATIC</tt>.
0052  *
0053  * @section cmakeimportexport CMake code
0054  *
0055  * The definition can be made within CMake:
0056  *
0057  * @code{.unparsed}
0058  * if(BUILD_SHARED_LIBS)
0059  *     target_compile_definitions(
0060  *         my_target_name
0061  *         PRIVATE PERCEPTUALCOLORLIB_BUILD_DYNAMIC_LIBRARY)
0062  * else()
0063  *     target_compile_definitions(
0064  *         my_target_name
0065  *         PUBLIC PERCEPTUALCOLORLIB_STATIC)
0066  * endif()
0067  * @endcode
0068  *
0069  * <tt>PERCEPTUALCOLORLIB_BUILD_DYNAMIC_LIBRARY</tt> is defined
0070  * <tt>PRIVATE</tt>, so it only becomes available when building
0071  * the library <em>itself</em> dynamically, and not when building
0072  * an application <em>using</em> the dynamic library.
0073  *
0074  * <tt>PERCEPTUALCOLORLIB_STATIC</tt> however is defined
0075  * <tt>PUBLIC</tt>, so it only becomes available both, when building
0076  * the library <em>itself</em> statically, and also when building
0077  * an application <em>using</em> the static library.
0078  *
0079  * And you also have to make sure that all symbols that are <em>not</em>
0080  * explicitly exported will be actually hidden on all platforms:
0081  *
0082  * @code{.unparsed}
0083  * set_target_properties(
0084  *     my_target_name PROPERTIES
0085  *     # By default, on Windows all symbols are hidden except those that are
0086  *     # explicitly marked for export using the "__declspec(dllexport)"
0087  *     # or "__declspec(dllimport)" keywords in the code. On Unix-based systems,
0088  *     # however, all symbols are exported by default unless they are explicitly
0089  *     # marked as hidden. To achieve the same behavior as on Windows, set
0090  *     # the "CXX_VISIBILITY_PRESET" property to "hidden" in CMake to hide all
0091  *     # symbols by default, unless they are explicitly marked for export using
0092  *     # compiler-specific attributes.
0093  *     CXX_VISIBILITY_PRESET "hidden"
0094  *     VISIBILITY_INLINES_HIDDEN TRUE)
0095  * @endcode
0096  *
0097  * For your information: The opposite would look like this:
0098  *
0099  * @code{.unparsed}
0100  * set_target_properties(
0101  *     my_target_name PROPERTIES
0102  *     # We want all symbols to be publicly available. On Unix-based systems, this
0103  *     # is the default behavior, and no additional configuration is required.
0104  *     CXX_VISIBILITY_PRESET "default"
0105  *     # However, on Windows, all symbols are hidden by default except for those
0106  *     # that are explicitly marked for export using "__declspec(dllexport)" or
0107  *     # "__declspec(dllimport)" keywords. To achieve the same behavior on Windows
0108  *     # as on Unix-based systems, CMake provides the "WINDOWS_EXPORT_ALL_SYMBOLS"
0109  *     # property, which can be set to "TRUE" to automatically generate the
0110  *     # necessary export symbols for all classes and functions on Windows.
0111  *     # However, please note that this option does not work for global variables.
0112  *     WINDOWS_EXPORT_ALL_SYMBOLS TRUE
0113  *     VISIBILITY_INLINES_HIDDEN FALSE)
0114  * @endcode
0115  *
0116  * @section importexportlinks Further reading
0117  *
0118  * @note CMake also offers support for symbol import and export.
0119  * It can generate a corresponding header by using the <tt><a
0120  * href="https://cmake.org/cmake/help/latest/module/GenerateExportHeader.html">
0121  * generate_export_header()</a></tt> command. However, this is always
0122  * an additional step and makes the build and install configuration
0123  * more complex. Furthermore, we produce a second internal library
0124  * target out of the same source code, which has a different symbol
0125  * visibility for unit tests. As CMake-generated import-export headers
0126  * use the name of the target as part of the macro names it defines, this
0127  * would get complicated. Having our own macro is easier.
0128  *
0129  * @note CMake’s <a
0130  * href="https://cmake.org/cmake/help/latest/module/GenerateExportHeader.html">
0131  * <tt>generate_export_header()</tt></a> command also has portable
0132  * support for deprecating symbols. However, since C++14 there is
0133  * <a href="https://en.cppreference.com/w/cpp/language/attributes/deprecated">
0134  * <tt>[[deprecated(string-literal)]]</tt></a> part of the standard.
0135  * As we require even C++17 anyway, we can use this as a portable standard
0136  * instead of CMake’s macros.
0137  *
0138  * @sa https://doc.qt.io/qt-5/sharedlibrary.html#using-symbols-from-shared-libraries
0139  * @sa http://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html
0140  * @sa https://labjack.com/news/simple-cpp-symbol-visibility-demo */
0141 
0142 #ifdef PERCEPTUALCOLORLIB_STATIC
0143 
0144 #ifndef PERCEPTUALCOLOR_IMPORTEXPORT
0145 #define PERCEPTUALCOLOR_IMPORTEXPORT
0146 #endif
0147 
0148 #else
0149 
0150 #ifndef PERCEPTUALCOLOR_IMPORTEXPORT
0151 #ifdef PERCEPTUALCOLORLIB_BUILD_DYNAMIC_LIBRARY
0152 #define PERCEPTUALCOLOR_IMPORTEXPORT Q_DECL_EXPORT
0153 #else
0154 #define PERCEPTUALCOLOR_IMPORTEXPORT Q_DECL_IMPORT
0155 #endif
0156 #endif
0157 
0158 #endif
0159 
0160 #endif // IMPORTEXPORT_H