1 /* runtime/weak dynamic JACK linking
2 *
3 * (C) 2014 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "weak_libjack.h"
21
22 #ifndef USE_WEAK_JACK
23
have_libjack(void)24 int have_libjack (void) {
25 return 0;
26 }
27
28 #else
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #ifdef _WIN32
35 #include <windows.h>
36 #else
37 #include <dlfcn.h>
38 #endif
39
lib_open(const char * const so)40 static void* lib_open(const char* const so) {
41 #ifdef _WIN32
42 return (void*) LoadLibraryA(so);
43 #else
44 return dlopen(so, RTLD_NOW|RTLD_LOCAL);
45 #endif
46 }
47
lib_symbol(void * const lib,const char * const sym)48 static void* lib_symbol(void* const lib, const char* const sym) {
49 #ifdef _WIN32
50 return (void*) GetProcAddress((HMODULE)lib, sym);
51 #else
52 return dlsym(lib, sym);
53 #endif
54 }
55
56 #if defined(_MSC_VER) && _MSC_VER && !__INTEL_COMPILER
57 typedef void * pvoid_t;
58 #define MAPSYM(SYM, FAIL) _j._ ## SYM = (func_t)lib_symbol(lib, "jack_" # SYM); \
59 if (!_j._ ## SYM) err |= FAIL;
60 #elif defined NDEBUG
61 typedef void * __attribute__ ((__may_alias__)) pvoid_t;
62 #define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
63 if (!_j._ ## SYM) err |= FAIL;
64 #else
65 typedef void * __attribute__ ((__may_alias__)) pvoid_t;
66 #define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
67 if (!_j._ ## SYM) { \
68 if (FAIL) { \
69 fprintf(stderr, "*** WEAK-JACK: required symbol 'jack_%s' was not found\n", "" # SYM); \
70 } \
71 err |= FAIL; \
72 }
73 #endif
74
75 typedef void (* func_t) (void);
76
77 /* function pointers to the real jack API */
78 static struct WeakJack {
79 func_t _client_open; // special case due to varargs
80
81 #define JCFUN(ERR, RTYPE, NAME, RVAL) func_t _ ## NAME ;
82 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) func_t _ ## NAME ;
83 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
84 #define JVFUN(ERR, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
85
86 #include "weak_libjack.def"
87
88 #undef JCFUN
89 #undef JPFUN
90 #undef JXFUN
91 #undef JVFUN
92 } _j;
93
94 static int _status = -1;
95 #if !defined(_MSC_VER)
96 __attribute__((constructor))
97 #endif
init_weak_jack(void)98 static void init_weak_jack(void)
99 {
100 void* lib;
101 int err = 0;
102 #ifndef NDEBUG
103 fprintf(stderr, "*** WEAK-JACK: initializing\n");
104 #endif
105
106 memset(&_j, 0, sizeof(_j));
107
108 #ifdef __APPLE__
109 lib = lib_open("libjack.dylib");
110 if (!lib) {
111 lib = lib_open("/usr/local/lib/libjack.dylib");
112 }
113 #elif (defined _WIN32)
114 # if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__)
115 lib = lib_open("libjack64.dll");
116 # else
117 lib = lib_open("libjack.dll");
118 # endif
119 #else
120 lib = lib_open("libjack.so.0");
121 #endif
122 if (!lib) {
123 #ifndef NDEBUG
124 fprintf(stderr, "*** WEAK-JACK: libjack was not found\n");
125 #endif
126 _status = -2;
127 return;
128 }
129
130 /* found library, now lookup functions */
131 MAPSYM(client_open, 2)
132
133 #define JCFUN(ERR, RTYPE, NAME, RVAL) MAPSYM(NAME, ERR)
134 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) MAPSYM(NAME, ERR)
135 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
136 #define JVFUN(ERR, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
137
138 #include "weak_libjack.def"
139
140 #undef JCFUN
141 #undef JPFUN
142 #undef JXFUN
143 #undef JVFUN
144
145 /* if a required symbol is not found, disable JACK completly */
146 if (err) {
147 _j._client_open = NULL;
148 }
149 _status = err;
150 #ifndef NDEBUG
151 fprintf(stderr, "*** WEAK-JACK: %s. (%d)\n", err ? "jack is not available" : "OK", _status);
152 #endif
153 }
154
have_libjack(void)155 int have_libjack (void) {
156 if (_status == -1) {
157 init_weak_jack();
158 }
159 return _status;
160 }
161
162 /*******************************************************************************
163 * helper macros
164 */
165
166 #if defined(__GNUC__) && (__GNUC__ > 2) && !defined(NDEBUG)
167 #define likely(expr) (__builtin_expect (!!(expr), 1))
168 #else
169 #define likely(expr) (expr)
170 #endif
171
172 #ifndef NDEBUG
173 # define WJACK_WARNING(NAME) \
174 fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME);
175 #else
176 # define WJACK_WARNING(NAME) ;
177 #endif
178
179 /******************************************************************************
180 * JACK API wrapper functions.
181 *
182 * if a function pointer is set in the static struct WeakJack _j,
183 * the function is called directly.
184 * Otherwise a dummy NOOP implementation is provided.
185 * The latter is mainly for compile-time warnings.
186 *
187 * If libjack is not found, jack_client_open() will fail.
188 * In that case the application should not call any other libjack
189 * functions. Hence a real implementation is not needed.
190 * (jack ringbuffer may be an exception for some apps)
191 */
192
193 /* dedicated support for jack_client_open(,..) variable arg function macro */
WJACK_get_client_open(void)194 func_t WJACK_get_client_open(void) {
195 if (_status == -1) {
196 init_weak_jack();
197 }
198 return _j._client_open;
199 }
200
201 /* callback to set status */
WJACK_no_client_open(const char * client_name,jack_options_t options,jack_status_t * status,...)202 jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...) {
203 WJACK_WARNING(client_open);
204 if (status) { *status = JackFailure; }
205 return NULL;
206 }
207
208 /*******************************************************************************
209 * Macros to wrap jack API
210 */
211
212 /* abstraction for jack_client functions
213 * rtype jack_function_name (jack_client_t *client) { return rval; }
214 */
215 #define JCFUN(ERR, RTYPE, NAME, RVAL) \
216 RTYPE WJACK_ ## NAME (jack_client_t *client) { \
217 if likely(_j._ ## NAME) { \
218 return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \
219 } else { \
220 WJACK_WARNING(NAME) \
221 return RVAL; \
222 } \
223 }
224
225 /* abstraction for NOOP functions with return value
226 * rtype jack_function_name (ARGS) { return rval; }
227 */
228 #define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) \
229 RTYPE WJACK_ ## NAME DEF { \
230 if likely(_j._ ## NAME) { \
231 return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
232 } else { \
233 WJACK_WARNING(NAME) \
234 return RVAL; \
235 } \
236 }
237
238 /* abstraction for functions that need custom code.
239 * e.g. functions with return-value-pointer args,
240 * use CODE to initialize value
241 *
242 * rtype jack_function_name (ARGS) { CODE }
243 */
244 #define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) \
245 RTYPE WJACK_ ## NAME DEF { \
246 if likely(_j._ ## NAME) { \
247 return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
248 } else { \
249 WJACK_WARNING(NAME) \
250 CODE \
251 } \
252 }
253
254 /* abstraction for void functions with return-value-pointer args
255 * void jack_function_name (ARGS) { CODE }
256 */
257 #define JVFUN(ERR, NAME, DEF, ARGS, CODE) \
258 void WJACK_ ## NAME DEF { \
259 if likely(_j._ ## NAME) { \
260 ((void (*)DEF) _j._ ## NAME) ARGS; \
261 } else { \
262 WJACK_WARNING(NAME) \
263 CODE \
264 } \
265 }
266
267 #include "weak_libjack.def"
268
269 #undef JCFUN
270 #undef JPFUN
271 #undef JXFUN
272 #undef JVFUN
273
274 #endif // end USE_WEAK_JACK
275