Fix DLL visibility of explicit instantiation "declaration" of internal::basic_data<void> in header format.h and the explicit instantiation "definition" in format.cc (#1134)

* Update format.cc

As the explicit instantiation *declaration* of `internal::basic_data<void>` in format.h, this explicit instantiation *definition* should mirror FMT_API also.

* Mirror visibility of explicit instantiation declaration 

explicit instantiation declaration of internal::basic_data<void> should mirror visibility of FMT_API

* Eliminate `__declspec(dllexport)` designation on extern template internal::basic_data<> when `extern` affected during exporting phase.

* Add `FMT_EXTERN_TEMPLATE_API` for designate DLL export `extern template`

When exporting DLL, do not designate `__declspec(dllexport)` any template that has any explicit class template declaration a.k.a. `extern template`. Instead, designate `__declspec(dllexport)` at single point where we have explicit class template definition a.k.a. normal instantiation without `extern`

Note: this is a c++11 feature.

* Delete whole `FMT_USE_EXTERN_TEMPLATES` block and its condition

1. Remove whole `FMT_USE_EXTERN_TEMPLATES` block
(trailing `FMT_UDL_TEMPLATE` block)
````
#ifndef FMT_USE_EXTERN_TEMPLATES
#  ifndef FMT_HEADER_ONLY
#    define FMT_USE_EXTERN_TEMPLATES                           \
      ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \
       (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))
#  else
#    define FMT_USE_EXTERN_TEMPLATES 0
#  endif
#endif
````

2. Delete `FMT_USE_EXTERN_TEMPLATES` condition, only condition, that trailing basic_data class template definition.
````
#if FMT_USE_EXTERN_TEMPLATES
extern template struct basic_data<void>;
#endif
````

3. Replace `FMT_API` with new `FMT_EXTERN_TEMPLATE_API` added in `core.h` for sake of extern template of `basic_data<void>`

* Add `#define FMT_EXTERN extern` only when not `FMT_HEADER_ONLY`

* Replace `extern` on basic_data<void> with the `FMT_EXTERN` condition in core.h

* replace misspelled if !define() with ifndef
This commit is contained in:
denchat 2019-05-02 21:49:01 +07:00 committed by Victor Zverovich
parent 4a4d72f917
commit 29c10fbf6e
3 changed files with 13 additions and 15 deletions

View File

@ -189,11 +189,21 @@
# define FMT_API __declspec(dllexport) # define FMT_API __declspec(dllexport)
# elif defined(FMT_SHARED) # elif defined(FMT_SHARED)
# define FMT_API __declspec(dllimport) # define FMT_API __declspec(dllimport)
# define FMT_EXTERN_TEMPLATE_API FMT_API
# endif # endif
#endif #endif
#ifndef FMT_API #ifndef FMT_API
# define FMT_API # define FMT_API
#endif #endif
#ifndef FMT_EXTERN_TEMPLATE_API
# define FMT_EXTERN_TEMPLATE_API
#endif
#ifndef FMT_HEADER_ONLY
# define FMT_EXTERN extern
#else
# define FMT_EXTERN
#endif
#ifndef FMT_ASSERT #ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message) # define FMT_ASSERT(condition, message) assert((condition) && message)

View File

@ -159,16 +159,6 @@ FMT_END_NAMESPACE
# define FMT_UDL_TEMPLATE 0 # define FMT_UDL_TEMPLATE 0
#endif #endif
#ifndef FMT_USE_EXTERN_TEMPLATES
# ifndef FMT_HEADER_ONLY
# define FMT_USE_EXTERN_TEMPLATES \
((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \
(FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))
# else
# define FMT_USE_EXTERN_TEMPLATES 0
# endif
#endif
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \ #if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \
FMT_MSC_VER >= 1600 FMT_MSC_VER >= 1600
# define FMT_USE_TRAILING_RETURN 1 # define FMT_USE_TRAILING_RETURN 1
@ -712,7 +702,7 @@ template <typename T> struct int_traits {
// Static data is placed in this class template to allow header-only // Static data is placed in this class template to allow header-only
// configuration. // configuration.
template <typename T = void> struct FMT_API basic_data { template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
static const uint64_t POWERS_OF_10_64[]; static const uint64_t POWERS_OF_10_64[];
static const uint32_t ZERO_OR_POWERS_OF_10_32[]; static const uint32_t ZERO_OR_POWERS_OF_10_32[];
static const uint64_t ZERO_OR_POWERS_OF_10_64[]; static const uint64_t ZERO_OR_POWERS_OF_10_64[];
@ -726,9 +716,7 @@ template <typename T = void> struct FMT_API basic_data {
static const wchar_t WRESET_COLOR[5]; static const wchar_t WRESET_COLOR[5];
}; };
#if FMT_USE_EXTERN_TEMPLATES FMT_EXTERN template struct basic_data<void>;
extern template struct basic_data<void>;
#endif
// This is a struct rather than a typedef to avoid shadowing warnings in gcc. // This is a struct rather than a typedef to avoid shadowing warnings in gcc.
struct data : basic_data<> {}; struct data : basic_data<> {};

View File

@ -8,7 +8,7 @@
#include "fmt/format-inl.h" #include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
template struct internal::basic_data<void>; template struct FMT_API internal::basic_data<void>;
// Workaround a bug in MSVC2013 that prevents instantiation of grisu_format. // Workaround a bug in MSVC2013 that prevents instantiation of grisu_format.
bool (*instantiate_grisu_format)(double, internal::buffer<char>&, int, unsigned, bool (*instantiate_grisu_format)(double, internal::buffer<char>&, int, unsigned,