1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // SoftLinking.h: Macros for soft-linking Frameworks and Functions.
8 
9 #ifndef SOFT_LINKING_APPLE_H_
10 #define SOFT_LINKING_APPLE_H_
11 
12 #include "common/platform.h"
13 
14 #if defined(ANGLE_PLATFORM_APPLE)
15 
16 #    include "common/debug.h"
17 
18 #    import <dispatch/dispatch.h>
19 #    import <dlfcn.h>
20 #    import <objc/runtime.h>
21 
22 #    define RELEASE_ASSERT(expression, message)                                               \
23         (expression                                                                           \
24              ? static_cast<void>(0)                                                           \
25              : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ << ":" \
26                         << __LINE__ << "): " << #expression << "\n\t! Message: " << message))
27 
28 #    ifdef __cplusplus
29 #        define EXTERN_C_BEGIN extern "C" {
30 #        define EXTERN_C_END }
31 #    else
32 #        define EXTERN_C_BEGIN
33 #        define EXTERN_C_END
34 #    endif
35 
36 #    define SOFT_LINK_FRAMEWORK_HEADER(framework) extern void *framework##Library();
37 
38 #    define SOFT_LINK_FRAMEWORK_SOURCE(framework)                                               \
39         void *framework##Library()                                                              \
40         {                                                                                       \
41             static dispatch_once_t once   = 0;                                                  \
42             static void *frameworkLibrary = NULL;                                               \
43             dispatch_once(&once, ^{                                                             \
44               frameworkLibrary = dlopen(                                                        \
45                   "/System/Library/Frameworks/" #framework ".framework/" #framework, RTLD_NOW); \
46               RELEASE_ASSERT(frameworkLibrary, "Unable to load " #framework ".framework");      \
47             });                                                                                 \
48             return frameworkLibrary;                                                            \
49         }
50 
51 #    define SOFT_LINK_FUNCTION_HEADER(framework, functionName, resultType, parameterDeclarations, \
52                                       parameterNames)                                             \
53         EXTERN_C_BEGIN                                                                            \
54         resultType functionName parameterDeclarations;                                            \
55         EXTERN_C_END                                                                              \
56         extern resultType init##framework##functionName parameterDeclarations;                    \
57         extern resultType(*softLink##framework##functionName) parameterDeclarations;              \
58         inline __attribute__((__always_inline__)) resultType functionName parameterDeclarations   \
59         {                                                                                         \
60             return softLink##framework##functionName parameterNames;                              \
61         }
62 
63 #    define SOFT_LINK_FUNCTION_SOURCE(framework, functionName, resultType, parameterDeclarations,  \
64                                       parameterNames)                                              \
65         resultType(*softLink##framework##functionName) parameterDeclarations =                     \
66             init##framework##functionName;                                                         \
67         resultType init##framework##functionName parameterDeclarations                             \
68         {                                                                                          \
69             static dispatch_once_t once;                                                           \
70             dispatch_once(&once, ^{                                                                \
71               softLink##framework##functionName =                                                  \
72                   (resultType(*) parameterDeclarations)dlsym(framework##Library(), #functionName); \
73             });                                                                                    \
74             return softLink##framework##functionName parameterNames;                               \
75         }
76 
77 #    define SOFT_LINK_CLASS_HEADER(className)    \
78         @class className;                        \
79         extern Class (*get##className##Class)(); \
80         className *alloc##className##Instance(); \
81         inline className *alloc##className##Instance() { return [get##className##Class() alloc]; }
82 
83 #    define SOFT_LINK_CLASS(framework, className)                                       \
84         @class className;                                                               \
85         static Class init##className();                                                 \
86         Class (*get##className##Class)() = init##className;                             \
87         static Class class##className;                                                  \
88                                                                                         \
89         static Class className##Function() { return class##className; }                 \
90                                                                                         \
91         static Class init##className()                                                  \
92         {                                                                               \
93             static dispatch_once_t once;                                                \
94             dispatch_once(&once, ^{                                                     \
95               framework##Library();                                                     \
96               class##className = objc_getClass(#className);                             \
97               RELEASE_ASSERT(class##className, "objc_getClass failed for " #className); \
98               get##className##Class = className##Function;                              \
99             });                                                                         \
100             return class##className;                                                    \
101         }                                                                               \
102         _Pragma("clang diagnostic push")                                                \
103             _Pragma("clang diagnostic ignored \"-Wunused-function\"") static className  \
104                 *alloc##className##Instance()                                           \
105         {                                                                               \
106             return [get##className##Class() alloc];                                     \
107         }                                                                               \
108         _Pragma("clang diagnostic pop")
109 
110 #endif  // defined(ANGLE_PLATFORM_APPLE)
111 
112 #endif  // SOFT_LINKING_APPLE_H_
113