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
23QT_BEGIN_NAMESPACE
24
25constexpr 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
34constexpr 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
49template <typename T>
50struct DefaultReturn
51{
52 template <typename... Arg>
53 T operator()(Arg &&...) { return val; }
54 T val;
55};
56
57template <>
58struct DefaultReturn<void>
59{
60 template <typename... Arg>
61 void operator()(Arg &&...) { }
62};
63
64template <typename...>
65struct FuncInfo;
66
67template <typename R, typename... A>
68struct FuncInfo<R(A...)>
69{
70 using Return = R;
71 using Args = std::tuple<A...>;
72};
73
74class Q_MULTIMEDIA_EXPORT SymbolsResolver
75{
76public:
77 using LibraryLoader = std::unique_ptr<QLibrary> (*)();
78 static bool isLazyLoadEnabled();
79 bool isLoaded() const { return m_library != nullptr; }
80
81 ~SymbolsResolver();
82protected:
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
93private:
94 const char *m_libLoggingName;
95 std::unique_ptr<QLibrary> m_library;
96};
97
98
99QT_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) \
178QT_BEGIN_NAMESPACE \
179bool FuncName() { return SymbolsResolverImpl::instance().isLoaded(); } \
180QT_END_NAMESPACE
181
182// clang-format on
183
184#endif // Q_SYMBOLSRESOLVEUTILS
185

source code of qtmultimedia/src/multimedia/qsymbolsresolveutils_p.h