blob: b4fc8fe5fbd79b89bd8758c09da77231a34cffdf [file] [log] [blame]
mdempsky8a519042016-02-09 05:41:471// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Mounir Lamouri130ad752017-10-13 17:07:155#ifndef BASE_EXPORT_TEMPLATE_H_
6#define BASE_EXPORT_TEMPLATE_H_
mdempsky8a519042016-02-09 05:41:477
8// Synopsis
9//
10// This header provides macros for using FOO_EXPORT macros with explicit
11// template instantiation declarations and definitions.
12// Generally, the FOO_EXPORT macros are used at declarations,
13// and GCC requires them to be used at explicit instantiation declarations,
14// but MSVC requires __declspec(dllexport) to be used at the explicit
15// instantiation definitions instead.
16
17// Usage
18//
19// In a header file, write:
20//
21// extern template class EXPORT_TEMPLATE_DECLARE(FOO_EXPORT) foo<bar>;
22//
23// In a source file, write:
24//
25// template class EXPORT_TEMPLATE_DEFINE(FOO_EXPORT) foo<bar>;
26
27// Implementation notes
28//
Nico Weberd8222a32019-10-30 19:01:2129// On Windows, when building the FOO library (that is, when FOO_EXPORT expands
30// to __declspec(dllexport)), we want the two lines to expand to:
31//
32// extern template class foo<bar>;
33// template class FOO_EXPORT foo<bar>;
34//
35// In all other cases (non-Windows, and Windows when using the FOO library (that
36// is when FOO_EXPORT expands to __declspec(dllimport)), we want:
37//
38// extern template class FOO_EXPORT foo<bar>;
39// template class foo<bar>;
40//
mdempsky8a519042016-02-09 05:41:4741// The implementation of this header uses some subtle macro semantics to
42// detect what the provided FOO_EXPORT value was defined as and then
Nico Weber2f2f97592020-02-19 15:09:3143// to dispatch to appropriate macro definitions.
mdempsky8a519042016-02-09 05:41:4744
Nico Weberd7452f22020-02-20 00:20:4545#define EXPORT_TEMPLATE_DECLARE(foo_export) \
46 EXPORT_TEMPLATE_INVOKE(DECLARE, EXPORT_TEMPLATE_STYLE(foo_export), foo_export)
47#define EXPORT_TEMPLATE_DEFINE(foo_export) \
48 EXPORT_TEMPLATE_INVOKE(DEFINE, EXPORT_TEMPLATE_STYLE(foo_export), foo_export)
mdempsky8a519042016-02-09 05:41:4749
50// INVOKE is an internal helper macro to perform parameter replacements
51// and token pasting to chain invoke another macro. E.g.,
52// EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, FOO_EXPORT)
Nico Weberd7452f22020-02-20 00:20:4553// will expand to call
Nico Weber2f2f97592020-02-19 15:09:3154// EXPORT_TEMPLATE_DECLARE_DEFAULT(FOO_EXPORT)
mdempsky8a519042016-02-09 05:41:4755// (but with FOO_EXPORT expanded too).
Nico Weberd7452f22020-02-20 00:20:4556#define EXPORT_TEMPLATE_INVOKE(which, style, foo_export) \
57 EXPORT_TEMPLATE_INVOKE_2(which, style, foo_export)
58#define EXPORT_TEMPLATE_INVOKE_2(which, style, foo_export) \
59 EXPORT_TEMPLATE_##which##_##style(foo_export)
mdempsky8a519042016-02-09 05:41:4760
61// Default style is to apply the FOO_EXPORT macro at declaration sites.
Nico Weberd7452f22020-02-20 00:20:4562#define EXPORT_TEMPLATE_DECLARE_DEFAULT(foo_export) foo_export
63#define EXPORT_TEMPLATE_DEFINE_DEFAULT(foo_export)
mdempsky8a519042016-02-09 05:41:4764
Nico Weberd7452f22020-02-20 00:20:4565// The "declspec" style is used when FOO_EXPORT is defined
mdempsky8a519042016-02-09 05:41:4766// as __declspec(dllexport), which MSVC requires to be used at
67// definition sites instead.
Nico Weberd7452f22020-02-20 00:20:4568#define EXPORT_TEMPLATE_DECLARE_EXPORT_DLLEXPORT(foo_export)
69#define EXPORT_TEMPLATE_DEFINE_EXPORT_DLLEXPORT(foo_export) foo_export
mdempsky8a519042016-02-09 05:41:4770
71// EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which
72// export style needs to be used for the provided FOO_EXPORT macro definition.
73// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped
Nico Weberd7452f22020-02-20 00:20:4574// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "EXPORT_DLLEXPORT".
75// (NaCl headers define "DLLEXPORT" already, else we'd use that.
76// TODO(thakis): Rename once nacl is gone.)
mdempsky8a519042016-02-09 05:41:4777//
78// It's implemented with token pasting to transform the __attribute__ and
79// __declspec annotations into macro invocations. E.g., if FOO_EXPORT is
80// defined as "__declspec(dllimport)", it undergoes the following sequence of
81// macro substitutions:
Nico Weber2f2f97592020-02-19 15:09:3182// EXPORT_TEMPLATE_STYLE(FOO_EXPORT)
83// EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport))
mdempsky8a519042016-02-09 05:41:4784// EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)
85// EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport
86// DEFAULT
Nico Weberd7452f22020-02-20 00:20:4587#define EXPORT_TEMPLATE_STYLE(foo_export) EXPORT_TEMPLATE_STYLE_2(foo_export)
88#define EXPORT_TEMPLATE_STYLE_2(foo_export) \
89 EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##foo_export
mdempsky8a519042016-02-09 05:41:4790
91// Internal helper macros for EXPORT_TEMPLATE_STYLE.
92//
93// XXX: C++ reserves all identifiers containing "__" for the implementation,
94// but "__attribute__" and "__declspec" already contain "__" and the token-paste
95// operator can only add characters; not remove them. To minimize the risk of
96// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random
97// 128-bit string, encoded in Base64) in the macro name.
98#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT
99#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__(...) \
100 DEFAULT
101#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \
102 EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg
103
104// Internal helper macros for EXPORT_TEMPLATE_STYLE.
Nico Weberd7452f22020-02-20 00:20:45105#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport EXPORT_DLLEXPORT
mdempsky8a519042016-02-09 05:41:47106#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT
107
108// Sanity checks.
109//
110// EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as
111// EXPORT_TEMPLATE_DECLARE and EXPORT_TEMPLATE_DEFINE do to check that they're
112// working correctly. When they're working correctly, the sequence of macro
113// replacements should go something like:
114//
115// EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
116//
117// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
Nico Weber2f2f97592020-02-19 15:09:31118// EXPORT_TEMPLATE_STYLE(__declspec(dllimport)),
mdempsky8a519042016-02-09 05:41:47119// __declspec(dllimport)), "__declspec(dllimport)");
120//
121// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
122// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)");
123//
124// static_assert(EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(
125// __declspec(dllimport)), "__declspec(dllimport)");
126//
127// static_assert(true, "__declspec(dllimport)");
128//
129// When they're not working correctly, a syntax error should occur instead.
Nico Weberd7452f22020-02-20 00:20:45130#define EXPORT_TEMPLATE_TEST(want, foo_export) \
131 static_assert( \
132 EXPORT_TEMPLATE_INVOKE(TEST_##want, EXPORT_TEMPLATE_STYLE(foo_export), \
133 foo_export), \
134 #foo_export)
mdempsky8a519042016-02-09 05:41:47135#define EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true
Nico Weberd7452f22020-02-20 00:20:45136#define EXPORT_TEMPLATE_TEST_EXPORT_DLLEXPORT_EXPORT_DLLEXPORT(...) true
mdempsky8a519042016-02-09 05:41:47137
138EXPORT_TEMPLATE_TEST(DEFAULT, );
139EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default"))));
Nico Weberd7452f22020-02-20 00:20:45140EXPORT_TEMPLATE_TEST(EXPORT_DLLEXPORT, __declspec(dllexport));
mdempsky8a519042016-02-09 05:41:47141EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
142
143#undef EXPORT_TEMPLATE_TEST
144#undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT
Nico Weberd7452f22020-02-20 00:20:45145#undef EXPORT_TEMPLATE_TEST_EXPORT_DLLEXPORT_EXPORT_DLLEXPORT
mdempsky8a519042016-02-09 05:41:47146
Mounir Lamouri130ad752017-10-13 17:07:15147#endif // BASE_EXPORT_TEMPLATE_H_