1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef Q_SYMBOLSRESOLVEUTILS |
5 | #define Q_SYMBOLSRESOLVEUTILS |
6 | |
7 | #include <QtCore/qlibrary.h> |
8 | #include <QtMultimedia/qtmultimediaexports.h> |
9 | #include <tuple> |
10 | #include <memory> |
11 | |
12 | // |
13 | // W A R N I N G |
14 | // ------------- |
15 | // |
16 | // This file is not part of the Qt API. It exists purely as an |
17 | // implementation detail. This header file may change from version to |
18 | // version without notice, or even be removed. |
19 | // |
20 | // We mean it. |
21 | // |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | constexpr bool areVersionsEqual(const char lhs[], const char rhs[]) |
26 | { |
27 | int i = 0; |
28 | for (; lhs[i] && rhs[i]; ++i) |
29 | if (lhs[i] != rhs[i]) |
30 | return false; |
31 | return lhs[i] == rhs[i]; |
32 | } |
33 | |
34 | constexpr bool areVersionsEqual(const char lhs[], int rhsInt) |
35 | { |
36 | int lhsInt = 0; |
37 | for (int i = 0; lhs[i]; ++i) { |
38 | if (lhs[i] < '0' || lhs[i] > '9') |
39 | return false; |
40 | |
41 | lhsInt *= 10; |
42 | lhsInt += lhs[i] - '0'; |
43 | } |
44 | |
45 | return lhsInt == rhsInt; |
46 | } |
47 | |
48 | |
49 | template <typename T> |
50 | struct DefaultReturn |
51 | { |
52 | template <typename... Arg> |
53 | T operator()(Arg &&...) { return val; } |
54 | T val; |
55 | }; |
56 | |
57 | template <> |
58 | struct DefaultReturn<void> |
59 | { |
60 | template <typename... Arg> |
61 | void operator()(Arg &&...) { } |
62 | }; |
63 | |
64 | template <typename...> |
65 | struct FuncInfo; |
66 | |
67 | template <typename R, typename... A> |
68 | struct FuncInfo<R(A...)> |
69 | { |
70 | using Return = R; |
71 | using Args = std::tuple<A...>; |
72 | }; |
73 | |
74 | class Q_MULTIMEDIA_EXPORT SymbolsResolver |
75 | { |
76 | public: |
77 | using LibraryLoader = std::unique_ptr<QLibrary> (*)(); |
78 | static bool isLazyLoadEnabled(); |
79 | bool isLoaded() const { return m_library != nullptr; } |
80 | |
81 | ~SymbolsResolver(); |
82 | protected: |
83 | SymbolsResolver(const char *libLoggingName, LibraryLoader loader); |
84 | |
85 | SymbolsResolver(const char *libName, const char *version = "" , |
86 | const char *libLoggingName = nullptr); |
87 | |
88 | QFunctionPointer initFunction(const char *name); |
89 | |
90 | struct SymbolsMarker {}; |
91 | void checkLibrariesLoaded(SymbolsMarker *begin, SymbolsMarker *end); |
92 | |
93 | private: |
94 | const char *m_libLoggingName; |
95 | std::unique_ptr<QLibrary> m_library; |
96 | }; |
97 | |
98 | |
99 | QT_END_NAMESPACE |
100 | |
101 | // clang-format off |
102 | |
103 | #define CHECK_VERSIONS(Name, NeededSoversion, DetectedVersion) \ |
104 | static_assert(areVersionsEqual(NeededSoversion, DetectedVersion), \ |
105 | "Configuartion error: misleading " Name " versions!") |
106 | |
107 | #define BEGIN_INIT_FUNCS(...) \ |
108 | QT_USE_NAMESPACE \ |
109 | namespace { \ |
110 | class SymbolsResolverImpl : public SymbolsResolver { \ |
111 | public: \ |
112 | SymbolsResolverImpl() : SymbolsResolver(__VA_ARGS__) \ |
113 | { checkLibrariesLoaded(&symbolsBegin, &symbolsEnd); } \ |
114 | static const SymbolsResolverImpl& instance() \ |
115 | { static const SymbolsResolverImpl instance; return instance; } \ |
116 | SymbolsMarker symbolsBegin; |
117 | |
118 | #define INIT_FUNC(F) QFunctionPointer F = initFunction(#F); |
119 | |
120 | #define END_INIT_FUNCS() \ |
121 | SymbolsMarker symbolsEnd; \ |
122 | }; \ |
123 | [[maybe_unused]] static const auto *instantResolver = \ |
124 | SymbolsResolver::isLazyLoadEnabled() ? &SymbolsResolverImpl::instance() : nullptr; \ |
125 | } |
126 | |
127 | |
128 | #ifdef Q_EXPORT_STUB_SYMBOLS |
129 | #define EXPORT_FUNC Q_MULTIMEDIA_EXPORT |
130 | #else |
131 | #define EXPORT_FUNC |
132 | #endif |
133 | |
134 | #define DEFINE_FUNC_IMPL(F, Vars, TypesWithVars, ReturnFunc) \ |
135 | using F##_ReturnType = FuncInfo<decltype(F)>::Return; \ |
136 | extern "C" EXPORT_FUNC [[maybe_unused]] F##_ReturnType F(TypesWithVars(F)) { \ |
137 | using F##_Type = F##_ReturnType (*)(TypesWithVars(F)); \ |
138 | const auto f = SymbolsResolverImpl::instance().F; \ |
139 | return f ? (reinterpret_cast<F##_Type>(f))(Vars()) : ReturnFunc(); \ |
140 | } |
141 | |
142 | |
143 | #define VAR(I) a##I |
144 | #define VARS0() |
145 | #define VARS1() VAR(0) |
146 | #define VARS2() VARS1(), VAR(1) |
147 | #define VARS3() VARS2(), VAR(2) |
148 | #define VARS4() VARS3(), VAR(3) |
149 | #define VARS5() VARS4(), VAR(4) |
150 | #define VARS6() VARS5(), VAR(5) |
151 | #define VARS7() VARS6(), VAR(6) |
152 | #define VARS8() VARS7(), VAR(7) |
153 | #define VARS9() VARS8(), VAR(8) |
154 | #define VARS10() VARS9(), VAR(9) |
155 | #define VARS11() VARS10(), VAR(10) |
156 | |
157 | #define TYPE_WITH_VAR(F, I) std::tuple_element_t<I, FuncInfo<decltype(F)>::Args> VAR(I) |
158 | #define TYPES_WITH_VARS0(F) |
159 | #define TYPES_WITH_VARS1(F) TYPE_WITH_VAR(F, 0) |
160 | #define TYPES_WITH_VARS2(F) TYPES_WITH_VARS1(F), TYPE_WITH_VAR(F, 1) |
161 | #define TYPES_WITH_VARS3(F) TYPES_WITH_VARS2(F), TYPE_WITH_VAR(F, 2) |
162 | #define TYPES_WITH_VARS4(F) TYPES_WITH_VARS3(F), TYPE_WITH_VAR(F, 3) |
163 | #define TYPES_WITH_VARS5(F) TYPES_WITH_VARS4(F), TYPE_WITH_VAR(F, 4) |
164 | #define TYPES_WITH_VARS6(F) TYPES_WITH_VARS5(F), TYPE_WITH_VAR(F, 5) |
165 | #define TYPES_WITH_VARS7(F) TYPES_WITH_VARS6(F), TYPE_WITH_VAR(F, 6) |
166 | #define TYPES_WITH_VARS8(F) TYPES_WITH_VARS7(F), TYPE_WITH_VAR(F, 7) |
167 | #define TYPES_WITH_VARS9(F) TYPES_WITH_VARS8(F), TYPE_WITH_VAR(F, 8) |
168 | #define TYPES_WITH_VARS10(F) TYPES_WITH_VARS9(F), TYPE_WITH_VAR(F, 9) |
169 | #define TYPES_WITH_VARS11(F) TYPES_WITH_VARS10(F), TYPE_WITH_VAR(F, 10) |
170 | |
171 | |
172 | #define RET(F, ...) DefaultReturn<FuncInfo<decltype(F)>::Return>{__VA_ARGS__} |
173 | |
174 | #define DEFINE_FUNC(F, ArgsCount, /*Return value*/...) \ |
175 | DEFINE_FUNC_IMPL(F, VARS##ArgsCount, TYPES_WITH_VARS##ArgsCount, RET(F, __VA_ARGS__)); |
176 | |
177 | #define DEFINE_IS_LOADED_CHECKER(FuncName) \ |
178 | QT_BEGIN_NAMESPACE \ |
179 | bool FuncName() { return SymbolsResolverImpl::instance().isLoaded(); } \ |
180 | QT_END_NAMESPACE |
181 | |
182 | // clang-format on |
183 | |
184 | #endif // Q_SYMBOLSRESOLVEUTILS |
185 | |