GlueGen v2.6.0-rc-20250706
GlueGen, Native Binding Generator for Java™ (public API).
NativeLibrary.java
Go to the documentation of this file.
1/**
2 * Copyright 2011-2023 JogAmp Community. All rights reserved.
3 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification, are
6 * permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * The views and conclusions contained in the software and documentation are those of the
26 * authors and should not be interpreted as representing official policies, either expressed
27 * or implied, of JogAmp Community.
28 */
29
30package com.jogamp.common.os;
31
32import java.io.File;
33import java.io.IOException;
34import java.lang.reflect.Method;
35import java.net.URISyntaxException;
36import java.security.PrivilegedAction;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.Iterator;
40import java.util.List;
41import java.util.StringTokenizer;
42
43import jogamp.common.os.BionicDynamicLinker32bitImpl;
44import jogamp.common.os.BionicDynamicLinker64BitImpl;
45import jogamp.common.os.MacOSXDynamicLinkerImpl;
46import jogamp.common.os.PlatformPropsImpl;
47import jogamp.common.os.PosixDynamicLinkerImpl;
48import jogamp.common.os.WindowsDynamicLinkerImpl;
49
50import com.jogamp.common.ExceptionUtils;
51import com.jogamp.common.util.IOUtil;
52import com.jogamp.common.util.SecurityUtil;
53import com.jogamp.common.util.cache.TempJarCache;
54
55/** Provides low-level, relatively platform-independent access to
56 shared ("native") libraries. The core library routines
57 <code>System.load()</code> and <code>System.loadLibrary()</code>
58 in general provide suitable functionality for applications using
59 native code, but are not flexible enough to support certain kinds
60 of glue code generation and deployment strategies. This class
61 supports direct linking of native libraries to other shared
62 objects not necessarily installed on the system (in particular,
63 via the use of dlopen(RTLD_GLOBAL) on Unix platforms) as well as
64 manual lookup of function names to support e.g. GlueGen's
65 ProcAddressTable glue code generation style without additional
66 supporting code needed in the generated library. */
67
68public final class NativeLibrary implements DynamicLookupHelper {
69 private static final String[] prefixes;
70 private static final String[] suffixes;
71 private static final boolean isOSX;
72 private static String sys_env_lib_path_varname;
73
74 static {
75 // Instantiate dynamic linker implementation
76 switch (PlatformPropsImpl.OS_TYPE) {
77 case WINDOWS:
78 prefixes = new String[] { "" };
79 suffixes = new String[] { ".dll" };
80 sys_env_lib_path_varname = "PATH";
81 isOSX = false;
82 break;
83
84 case MACOS:
85 case IOS:
86 prefixes = new String[] { "lib" };
87 suffixes = new String[] { ".dylib" };
88 sys_env_lib_path_varname = "DYLD_LIBRARY_PATH";
89 isOSX = true;
90 break;
91
92 /*
93 case ANDROID:
94 case FREEBSD:
95 case SUNOS:
96 case HPUX:
97 case OPENKODE:
98 case LINUX: */
99 default:
100 prefixes = new String[] { "lib" };
101 suffixes = new String[] { ".so" };
102 sys_env_lib_path_varname = "LD_LIBRARY_PATH";
103 isOSX = false;
104 break;
105 }
106 }
107
108 private final DynamicLinker dynLink;
109
110 // Platform-specific representation for the handle to the open
111 // library. This is an HMODULE on Windows and a void* (the result of
112 // a dlopen() call) on Unix and Mac OS X platforms.
113 private long libraryHandle;
114
115 // May as well keep around the path to the library we opened
116 private final String libraryPath;
117
118 // Native library path of the opened native libraryHandle, maybe null
119 private final String nativeLibraryPath;
120
121 private final boolean global;
122
123 // Private constructor to prevent arbitrary instances from floating around
124 private NativeLibrary(final DynamicLinker dynLink, final long libraryHandle, final String libraryPath, final boolean global, final String symbolName) {
125 this.dynLink = dynLink;
126 this.libraryHandle = libraryHandle;
127 this.libraryPath = libraryPath;
128 this.nativeLibraryPath = dynLink.lookupLibraryPathname(libraryHandle, symbolName);
129 this.global = global;
130 if (DEBUG) {
131 System.err.println("NativeLibrary.open(): Successfully loaded: " + this);
132 }
133 }
134
135 @Override
136 public final String toString() {
137 final String nlp_s = null != nativeLibraryPath ? ", native '"+nativeLibraryPath+"'" : "";
138 return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", path[given '" + libraryPath + "'"+nlp_s+"], 0x" +
139 Long.toHexString(libraryHandle) + ", global " + global + "]";
140 }
141
142 /**
143 * Returns the system's environment variable name used for the dynamic linker to resolve library locations, e.g.
144 * - Windows: PATH
145 * - MacOS: DYLD_LIBRARY_PATH
146 * - Unix: LD_LIBRARY_PATH
147 */
148 public static final String getSystemEnvLibraryPathVarname() { return sys_env_lib_path_varname; }
149
150 /**
151 * Returns a list of system paths, from the {@link #getSystemEnvLibraryPathVarname()} variable.
152 */
153 public static final List<String> getSystemEnvLibraryPaths() {
154 final String paths =
155 SecurityUtil.doPrivileged(new PrivilegedAction<String>() {
156 @Override
157 public String run() {
158 return System.getenv(getSystemEnvLibraryPathVarname());
159 }
160 });
161 final List<String> res = new ArrayList<String>();
162 if( null != paths && paths.length() > 0 ) {
163 final StringTokenizer st = new StringTokenizer(paths, File.pathSeparator);
164 while (st.hasMoreTokens()) {
165 res.add(st.nextToken());
166 }
167 }
168 return res;
169 }
170
171 /** Opens the given native library, assuming it has the same base
172 name on all platforms.
173 <p>
174 The {@code searchSystemPath} argument changes the behavior to
175 either use the default system path or not at all.
176 </p>
177 <p>
178 Assuming {@code searchSystemPath} is {@code true},
179 the {@code searchSystemPathFirst} argument changes the behavior to first
180 search the default system path rather than searching it last.
181 </p>
182 * @param libName library name, with or without prefix and suffix
183 * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
184 * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
185 * if {@code searchSystemPath} is {@code false} this argument is ignored.
186 * @param loader {@link ClassLoader} to locate the library
187 * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process.
188 * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded.
189 * @throws SecurityException if user is not granted access for the named library.
190 * @since 2.4.0
191 */
192 public static final NativeLibrary open(final String libName,
193 final boolean searchSystemPath,
194 final boolean searchSystemPathFirst,
195 final ClassLoader loader, final boolean global) throws SecurityException {
196 return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global, null);
197 }
198
199 /** Opens the given native library, assuming it has the same base
200 name on all platforms.
201 <p>
202 The {@code searchSystemPath} argument changes the behavior to
203 either use the default system path or not at all.
204 </p>
205 <p>
206 Assuming {@code searchSystemPath} is {@code true},
207 the {@code searchSystemPathFirst} argument changes the behavior to first
208 search the default system path rather than searching it last.
209 </p>
210 * @param libName library name, with or without prefix and suffix
211 * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
212 * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
213 * if {@code searchSystemPath} is {@code false} this argument is ignored.
214 * @param loader {@link ClassLoader} to locate the library
215 * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process.
216 * @param symbolName optional symbol name for an OS which requires the symbol's address to retrieve the path of the containing library
217 * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded.
218 * @throws SecurityException if user is not granted access for the named library.
219 * @since 2.4.0
220 */
221 public static final NativeLibrary open(final String libName,
222 final boolean searchSystemPath,
223 final boolean searchSystemPathFirst,
224 final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException {
225 return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global, symbolName);
226 }
227
228 /** Opens the given native library, assuming it has the given base
229 names (no "lib" prefix or ".dll/.so/.dylib" suffix) on the
230 Windows, Unix and Mac OS X platforms, respectively, and in the
231 context of the specified ClassLoader, which is used to help find
232 the library in the case of e.g. Java Web Start.
233 <p>
234 The {@code searchSystemPath} argument changes the behavior to
235 either use the default system path or not at all.
236 </p>
237 <p>
238 Assuming {@code searchSystemPath} is {@code true},
239 the {@code searchSystemPathFirst} argument changes the behavior to first
240 search the default system path rather than searching it last.
241 </p>
242 Note that we do not currently handle DSO versioning on Unix.
243 Experience with JOAL and OpenAL has shown that it is extremely
244 problematic to rely on a specific .so version (for one thing,
245 ClassLoader.findLibrary on Unix doesn't work with files not
246 ending in .so, for example .so.0), and in general if this
247 dynamic loading facility is used correctly the version number
248 will be irrelevant.
249 * @param windowsLibName windows library name, with or without prefix and suffix
250 * @param unixLibName unix library name, with or without prefix and suffix
251 * @param macOSXLibName mac-osx library name, with or without prefix and suffix
252 * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
253 * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
254 * if {@code searchSystemPath} is {@code false} this argument is ignored.
255 * @param loader {@link ClassLoader} to locate the library
256 * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process.
257 * @param symbolName optional symbol name for an OS which requires the symbol's address to retrieve the path of the containing library
258 * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded.
259 * @throws SecurityException if user is not granted access for the named library.
260 */
261 public static final NativeLibrary open(final String windowsLibName,
262 final String unixLibName,
263 final String macOSXLibName,
264 final boolean searchSystemPath,
265 final boolean searchSystemPathFirst,
266 final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException {
267 final List<String> possiblePaths = enumerateLibraryPaths(windowsLibName,
268 unixLibName,
269 macOSXLibName,
270 searchSystemPath, searchSystemPathFirst,
271 loader);
272 Platform.initSingleton(); // loads native gluegen_rt library
273
274 final DynamicLinker dynLink = getDynamicLinker();
275
276 // Iterate down these and see which one if any we can actually find.
277 for (final Iterator<String> iter = possiblePaths.iterator(); iter.hasNext(); ) {
278 final String path = iter.next();
279 if (DEBUG) {
280 System.err.println("NativeLibrary.open(global "+global+"): Trying to load " + path);
281 }
282 long res;
283 Throwable t = null;
284 try {
285 if(global) {
286 res = dynLink.openLibraryGlobal(path, DEBUG);
287 } else {
288 res = dynLink.openLibraryLocal(path, DEBUG);
289 }
290 } catch (final Throwable t1) {
291 t = t1;
292 res = 0;
293 }
294 if ( 0 != res ) {
295 return new NativeLibrary(dynLink, res, path, global, symbolName);
296 } else if( DEBUG ) {
297 if( null != t ) {
298 System.err.println("NativeLibrary.open: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
299 }
300 String errstr;
301 try {
302 errstr = dynLink.getLastError();
303 } catch (final Throwable t2) { errstr=null; }
304 System.err.println("NativeLibrary.open: Last error "+errstr);
305 if( null != t ) {
306 t.printStackTrace();
307 }
308 }
309 }
310
311 if (DEBUG) {
312 System.err.println("NativeLibrary.open(global "+global+"): Did not succeed in loading (" + windowsLibName + ", " + unixLibName + ", " + macOSXLibName + ")");
313 }
314
315 // For now, just return null to indicate the open operation didn't
316 // succeed (could also throw an exception if we could tell which
317 // of the openLibrary operations actually failed)
318 return null;
319 }
320
321 @Override
322 public final void claimAllLinkPermission() throws SecurityException {
323 dynLink.claimAllLinkPermission();
324 }
325 @Override
326 public final void releaseAllLinkPermission() throws SecurityException {
327 dynLink.releaseAllLinkPermission();
328 }
329
330 @Override
331 public final long dynamicLookupFunction(final String funcName) throws SecurityException {
332 if ( 0 == libraryHandle ) {
333 throw new RuntimeException("Library is not open");
334 }
335 return dynLink.lookupSymbol(libraryHandle, funcName);
336 }
337
338 @Override
339 public final boolean isFunctionAvailable(final String funcName) throws SecurityException {
340 if ( 0 == libraryHandle ) {
341 throw new RuntimeException("Library is not open");
342 }
343 return 0 != dynLink.lookupSymbol(libraryHandle, funcName);
344 }
345
346 /** Looks up the given function name in all loaded libraries.
347 * @throws SecurityException if user is not granted access for the named library.
348 */
349 public final long dynamicLookupFunctionGlobal(final String funcName) throws SecurityException {
350 return dynLink.lookupSymbolGlobal(funcName);
351 }
352
353 /* pp */ final DynamicLinker dynamicLinker() { return dynLink; }
354
355 /* pp */ static DynamicLinker getDynamicLinker() {
356 final DynamicLinker dynLink;
357 switch (PlatformPropsImpl.OS_TYPE) {
358 case WINDOWS:
359 dynLink = new WindowsDynamicLinkerImpl();
360 break;
361
362 case MACOS:
363 case IOS:
364 dynLink = new MacOSXDynamicLinkerImpl();
365 break;
366
367 case ANDROID:
368 if( PlatformPropsImpl.CPU_ARCH.is32Bit ) {
369 dynLink = new BionicDynamicLinker32bitImpl();
370 } else {
371 dynLink = new BionicDynamicLinker64BitImpl();
372 }
373 break;
374
375 default:
376 dynLink = new PosixDynamicLinkerImpl();
377 break;
378 }
379 return dynLink;
380 }
381
382 /** Retrieves the low-level library handle from this NativeLibrary
383 object. On the Windows platform this is an HMODULE, and on Unix
384 and Mac OS X platforms the void* result of calling dlopen(). */
385 public final long getLibraryHandle() {
386 return libraryHandle;
387 }
388
389 @Override
390 public final boolean isOpen() { return 0 != libraryHandle; }
391
392 /** Retrieves the path under which this library was opened. */
393 public final String getLibraryPath() {
394 return libraryPath;
395 }
396
397 /** Returns the native library path of the opened native {@link #getLibraryHandle()}, maybe null if not supported by OS. */
398 public final String getNativeLibraryPath() {
399 return nativeLibraryPath;
400 }
401
402 /** Closes this native library. Further lookup operations are not
403 allowed after calling this method.
404 * @throws SecurityException if user is not granted access for the named library.
405 */
406 public final void close() throws SecurityException {
407 if (DEBUG) {
408 System.err.println("NativeLibrary.close(): closing " + this);
409 }
410 if ( 0 == libraryHandle ) {
411 throw new RuntimeException("Library already closed");
412 }
413 final long handle = libraryHandle;
414 libraryHandle = 0;
415 dynLink.closeLibrary(handle, DEBUG);
416 if (DEBUG) {
417 System.err.println("NativeLibrary.close(): Successfully closed " + this);
418 ExceptionUtils.dumpStack(System.err);
419 }
420 }
421
422 /**
423 * Comparison of prefix and suffix of the given libName's basename
424 * is performed case insensitive <br>
425 *
426 * @param libName the full path library name with prefix and suffix
427 * @param isLowerCaseAlready indicates if libName is already lower-case
428 *
429 * @return basename of libName w/o path, ie. /usr/lib/libDrinkBeer.so -> DrinkBeer on Unix systems, but null on Windows.
430 */
431 public static final String isValidNativeLibraryName(final String libName, final boolean isLowerCaseAlready) {
432 final String libBaseName;
433 try {
434 libBaseName = IOUtil.getBasename(libName);
435 } catch (final URISyntaxException uriEx) {
436 throw new IllegalArgumentException(uriEx);
437 }
438 final String libBaseNameLC = isLowerCaseAlready ? libBaseName : libBaseName.toLowerCase();
439 int prefixIdx = -1;
440 for(int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
441 if (libBaseNameLC.startsWith(prefixes[i])) {
442 prefixIdx = i;
443 }
444 }
445 if( 0 <= prefixIdx ) {
446 for(int i=0; i<suffixes.length; i++) {
447 if (libBaseNameLC.endsWith(suffixes[i])) {
448 final int s = prefixes[prefixIdx].length();
449 final int e = suffixes[i].length();
450 return libBaseName.substring(s, libBaseName.length()-e);
451 }
452 }
453 }
454 return null;
455 }
456
457 /** Given the base library names (no prefixes/suffixes) for the
458 various platforms, enumerate the possible locations and names of
459 the indicated native library on the system not using the system path. */
460 public static final List<String> enumerateLibraryPaths(final String windowsLibName,
461 final String unixLibName,
462 final String macOSXLibName,
463 final ClassLoader loader) {
464 return enumerateLibraryPaths(windowsLibName, unixLibName, macOSXLibName,
465 false /* searchSystemPath */, false /* searchSystemPathFirst */,
466 loader);
467 }
468 /** Given the base library names (no prefixes/suffixes) for the
469 various platforms, enumerate the possible locations and names of
470 the indicated native library on the system using the system path. */
471 public static final List<String> enumerateLibraryPaths(final String windowsLibName,
472 final String unixLibName,
473 final String macOSXLibName,
474 final boolean searchSystemPathFirst,
475 final ClassLoader loader) {
476 return enumerateLibraryPaths(windowsLibName, unixLibName, macOSXLibName,
477 true /* searchSystemPath */, searchSystemPathFirst,
478 loader);
479 }
480 private static final List<String> enumerateLibraryPaths(final String windowsLibName,
481 final String unixLibName,
482 final String macOSXLibName,
483 final boolean searchSystemPath,
484 final boolean searchSystemPathFirst,
485 final ClassLoader loader) {
486 final List<String> paths = new ArrayList<String>();
487 final String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
488 if (libName == null) {
489 if (DEBUG) {
490 System.err.println("NativeLibrary.enumerateLibraryPaths: empty, no libName selected");
491 }
492 return paths;
493 }
494 if (DEBUG) {
495 System.err.println("NativeLibrary.enumerateLibraryPaths: libName '"+libName+"'");
496 }
497
498 // Allow user's full path specification to override our building of paths
499 final File file = new File(libName);
500 if (file.isAbsolute()) {
501 paths.add(libName);
502 if (DEBUG) {
503 System.err.println("NativeLibrary.enumerateLibraryPaths: done, absolute path found '"+libName+"'");
504 }
505 return paths;
506 }
507
508 final String[] baseNames = buildNames(libName);
509 if (DEBUG) {
510 System.err.println("NativeLibrary.enumerateLibraryPaths: baseNames: "+Arrays.toString(baseNames));
511 }
512
513 if( searchSystemPath && searchSystemPathFirst ) {
514 // Utilize system's library path environment variable first
515 {
516 final List<String> sysLibPaths = getSystemEnvLibraryPaths();
517 int count = 0;
518 for(final String sysLibPath : sysLibPaths) {
519 addRelPaths("add.ssp_path_"+count, sysLibPath, baseNames, paths);
520 ++count;
521 }
522 }
523 // Add just the library names to use the OS's search algorithm
524 for (int i = 0; i < baseNames.length; i++) {
525 if (DEBUG) {
526 System.err.println("NativeLibrary.enumerateLibraryPaths: add.ssp_default: "+baseNames[i]);
527 }
528 paths.add(baseNames[i]);
529 }
530 // Add probable Mac OS X-specific paths
531 if ( isOSX ) {
532 // Add historical location
533 addAbsPaths("add.ssp_1st_macos_old", "/Library/Frameworks/" + libName + ".framework", baseNames, paths);
534 // Add current location
535 addAbsPaths("add.ssp_1st_macos_cur", "/System/Library/Frameworks/" + libName + ".framework", baseNames, paths);
536 }
537 }
538
539 // The idea to ask the ClassLoader to find the library is borrowed
540 // from the LWJGL library
541 final String clPath = findLibrary(libName, loader);
542 if (clPath != null) {
543 if (DEBUG) {
544 System.err.println("NativeLibrary.enumerateLibraryPaths: add.clp: "+clPath);
545 }
546 paths.add(clPath);
547 }
548
549 // Add entries from java.library.path
550 final String[] javaLibraryPaths =
551 SecurityUtil.doPrivileged(new PrivilegedAction<String[]>() {
552 @Override
553 public String[] run() {
554 int count = 0;
555 final String usrPath = System.getProperty("java.library.path");
556 if(null != usrPath) {
557 count++;
558 }
559 final String sysPath;
560 if( searchSystemPath ) {
561 sysPath = System.getProperty("sun.boot.library.path");
562 if(null != sysPath) {
563 count++;
564 }
565 } else {
566 sysPath = null;
567 }
568 final String[] res = new String[count];
569 int i=0;
570 if( null != sysPath && searchSystemPathFirst ) {
571 res[i++] = sysPath;
572 }
573 if(null != usrPath) {
574 res[i++] = usrPath;
575 }
576 if( null != sysPath && !searchSystemPathFirst ) {
577 res[i++] = sysPath;
578 }
579 return res;
580 }
581 });
582 if ( null != javaLibraryPaths ) {
583 int count = 0;
584 for( int i=0; i < javaLibraryPaths.length; i++ ) {
585 final StringTokenizer tokenizer = new StringTokenizer(javaLibraryPaths[i], File.pathSeparator);
586 while (tokenizer.hasMoreTokens()) {
587 addRelPaths("add.java.library.path_"+count, tokenizer.nextToken(), baseNames, paths);
588 ++count;
589 }
590 }
591 }
592
593 // Add current working directory
594 final String userDir =
595 SecurityUtil.doPrivileged(new PrivilegedAction<String>() {
596 @Override
597 public String run() {
598 return System.getProperty("user.dir");
599 }
600 });
601 addAbsPaths("add.user.dir.std", userDir, baseNames, paths);
602
603 // Add current working directory + natives/os-arch/ + library names
604 // to handle Bug 1145 cc1 using an unpacked fat-jar
605 addAbsPaths("add.user.dir.fat", userDir+File.separator+"natives"+File.separator+PlatformPropsImpl.os_and_arch, baseNames, paths);
606
607 if( searchSystemPath && !searchSystemPathFirst ) {
608 // Utilize system's library path environment variable first
609 {
610 final List<String> sysLibPaths = getSystemEnvLibraryPaths();
611 int count = 0;
612 for(final String sysLibPath : sysLibPaths) {
613 addRelPaths("add.ssp_path_"+count, sysLibPath, baseNames, paths);
614 ++count;
615 }
616 }
617 // Add just the library names to use the OS's search algorithm
618 for (int i = 0; i < baseNames.length; i++) {
619 if (DEBUG) {
620 System.err.println("NativeLibrary.enumerateLibraryPaths: add.ssp_default: "+baseNames[i]);
621 }
622 paths.add(baseNames[i]);
623 }
624 // Add probable Mac OS X-specific paths
625 if ( isOSX ) {
626 // Add historical location
627 addAbsPaths("add.ssp_lst_macos_old", "/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
628 // Add current location
629 addAbsPaths("add.ssp_lst_macos_cur", "/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
630 }
631 }
632 if (DEBUG) {
633 System.err.println("NativeLibrary.enumerateLibraryPaths: done: "+paths.toString());
634 }
635 return paths;
636 }
637
638
639 private static final String selectName(final String windowsLibName,
640 final String unixLibName,
641 final String macOSXLibName) {
642 switch (PlatformPropsImpl.OS_TYPE) {
643 case WINDOWS:
644 return windowsLibName;
645
646 case MACOS:
647 case IOS:
648 return macOSXLibName;
649
650 default:
651 return unixLibName;
652 }
653 }
654
655 private static final String[] buildNames(final String libName) {
656 // If the library name already has the prefix / suffix added
657 // (principally because we want to force a version number on Unix
658 // operating systems) then just return the library name.
659 final String libBaseNameLC;
660 try {
661 libBaseNameLC = IOUtil.getBasename(libName).toLowerCase();
662 } catch (final URISyntaxException uriEx) {
663 throw new IllegalArgumentException(uriEx);
664 }
665
666 int prefixIdx = -1;
667 for(int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
668 if (libBaseNameLC.startsWith(prefixes[i])) {
669 prefixIdx = i;
670 }
671 }
672 if( 0 <= prefixIdx ) {
673 for(int i=0; i<suffixes.length; i++) {
674 if (libBaseNameLC.endsWith(suffixes[i])) {
675 return new String[] { libName };
676 }
677 }
678 int suffixIdx = -1;
679 for(int i=0; i<suffixes.length && 0 > suffixIdx; i++) {
680 suffixIdx = libBaseNameLC.indexOf(suffixes[i]);
681 }
682 boolean ok = true;
683 if (suffixIdx >= 0) {
684 // Check to see if everything after it is a Unix version number
685 for (int i = suffixIdx + suffixes[0].length();
686 i < libName.length();
687 i++) {
688 final char c = libName.charAt(i);
689 if (!(c == '.' || (c >= '0' && c <= '9'))) {
690 ok = false;
691 break;
692 }
693 }
694 if (ok) {
695 return new String[] { libName };
696 }
697 }
698 }
699
700 final String[] res = new String[prefixes.length * suffixes.length + ( isOSX ? 1 : 0 )];
701 int idx = 0;
702 for (int i = 0; i < prefixes.length; i++) {
703 for (int j = 0; j < suffixes.length; j++) {
704 res[idx++] = prefixes[i] + libName + suffixes[j];
705 }
706 }
707 if ( isOSX ) {
708 // Plain library-base-name in Framework folder
709 res[idx++] = libName;
710 }
711 return res;
712 }
713
714 private static final void addRelPaths(final String cause, final String path, final String[] baseNames, final List<String> paths) {
715 final String abs_path;
716 try {
717 final File fpath = new File(path);
718 abs_path = fpath.getCanonicalPath();
719 } catch( final IOException ioe ) {
720 if (DEBUG) {
721 System.err.println("NativeLibrary.enumerateLibraryPaths: "+cause+": Exception "+ioe.getMessage()+", from path "+path);
722 }
723 return;
724 }
725 addAbsPaths(cause, abs_path, baseNames, paths);
726 }
727 private static final void addAbsPaths(final String cause, final String abs_path, final String[] baseNames, final List<String> paths) {
728 for (int j = 0; j < baseNames.length; j++) {
729 final String p = abs_path + File.separator + baseNames[j];
730 if (DEBUG) {
731 System.err.println("NativeLibrary.enumerateLibraryPaths: "+cause+": "+p+", from path "+abs_path);
732 }
733 paths.add(p);
734 }
735 }
736
737 private static boolean initializedFindLibraryMethod = false;
738 private static Method findLibraryMethod = null;
739 private static final String findLibraryImpl(final String libName, final ClassLoader loader) {
740 if( PlatformPropsImpl.JAVA_9 ) {
741 return null;
742 }
743 if (loader == null) {
744 return null;
745 }
746 if (!initializedFindLibraryMethod) {
747 SecurityUtil.doPrivileged(new PrivilegedAction<Object>() {
748 @Override
749 public Object run() {
750 try {
751 findLibraryMethod = ClassLoader.class.getDeclaredMethod("findLibrary",
752 new Class[] { String.class });
753 findLibraryMethod.setAccessible(true);
754 } catch (final Exception e) {
755 // Fail silently disabling this functionality
756 }
757 initializedFindLibraryMethod = true;
758 return null;
759 }
760 });
761 }
762 if (findLibraryMethod != null) {
763 try {
764 return SecurityUtil.doPrivileged(new PrivilegedAction<String>() {
765 @Override
766 public String run() {
767 try {
768 return (String) findLibraryMethod.invoke(loader, new Object[] { libName });
769 } catch (final Exception e) {
770 throw new RuntimeException(e);
771 }
772 }
773 });
774 } catch (final Exception e) {
775 if (DEBUG) {
776 e.printStackTrace();
777 }
778 // Fail silently and continue with other search algorithms
779 }
780 }
781 return null;
782 }
783 public static final String findLibrary(final String libName, final ClassLoader loader) {
784 String res = null;
785 if( TempJarCache.isInitialized(true) ) {
786 res = TempJarCache.findLibrary(libName);
787 if (DEBUG) {
788 System.err.println("NativeLibrary.findLibrary(<"+libName+">) (TempJarCache): "+res);
789 }
790 }
791 if(null == res) {
792 res = findLibraryImpl(libName, loader);
793 if (DEBUG) {
794 System.err.println("NativeLibrary.findLibrary(<"+libName+">, "+loader+") (CL): "+res);
795 }
796 }
797 return res;
798 }
799}
static void dumpStack(final PrintStream out)
Provides low-level, relatively platform-independent access to shared ("native") libraries.
final String getLibraryPath()
Retrieves the path under which this library was opened.
static final String isValidNativeLibraryName(final String libName, final boolean isLowerCaseAlready)
Comparison of prefix and suffix of the given libName's basename is performed case insensitive
final boolean isFunctionAvailable(final String funcName)
Queries whether function 'funcName' is available.
static final List< String > enumerateLibraryPaths(final String windowsLibName, final String unixLibName, final String macOSXLibName, final boolean searchSystemPathFirst, final ClassLoader loader)
Given the base library names (no prefixes/suffixes) for the various platforms, enumerate the possible...
final boolean isOpen()
Returns true if library is loaded and open, otherwise false.
final long dynamicLookupFunctionGlobal(final String funcName)
Looks up the given function name in all loaded libraries.
static final NativeLibrary open(final String windowsLibName, final String unixLibName, final String macOSXLibName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global, final String symbolName)
Opens the given native library, assuming it has the given base names (no "lib" prefix or "....
final long getLibraryHandle()
Retrieves the low-level library handle from this NativeLibrary object.
final String getNativeLibraryPath()
Returns the native library path of the opened native getLibraryHandle(), maybe null if not supported ...
static final NativeLibrary open(final String libName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global)
Opens the given native library, assuming it has the same base name on all platforms.
static final NativeLibrary open(final String libName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global, final String symbolName)
Opens the given native library, assuming it has the same base name on all platforms.
final long dynamicLookupFunction(final String funcName)
Returns the function handle for function 'funcName'.
static final String getSystemEnvLibraryPathVarname()
Returns the system's environment variable name used for the dynamic linker to resolve library locatio...
static final List< String > enumerateLibraryPaths(final String windowsLibName, final String unixLibName, final String macOSXLibName, final ClassLoader loader)
Given the base library names (no prefixes/suffixes) for the various platforms, enumerate the possible...
final void close()
Closes this native library.
static final String findLibrary(final String libName, final ClassLoader loader)
static final List< String > getSystemEnvLibraryPaths()
Returns a list of system paths, from the getSystemEnvLibraryPathVarname() variable.
Utility class for querying platform specific properties.
Definition: Platform.java:58
static void initSingleton()
kick off static initialization of platform property information and native gluegen_rt lib loading
Definition: Platform.java:359
static String getBasename(String fname)
Returns the basename of the given fname w/o directory part.
Definition: IOUtil.java:486
static< T > T doPrivileged(final PrivilegedAction< T > o)
Call wrapper for java.security.AccessController#doPrivileged(PrivilegedAction).
Static Jar file cache handler using an underlying instance of TempFileCache, see getTempFileCache().
static boolean isInitialized(final boolean forExecutables)
static synchronized final String findLibrary(final String libName)
If isInitialized(true) is false due to lack of executable support only, this method always returns fa...
Low level secure dynamic linker access.
long openLibraryLocal(String pathname, boolean debug)
If a SecurityManager is installed, user needs link permissions for the named library.
long lookupSymbolGlobal(String symbolName)
If a SecurityManager is installed, user needs link permissions for all libraries, i....
String getLastError()
Returns a string containing the last error.
String lookupLibraryPathname(long libraryHandle, String symbolName)
Security checks are implicit by previous call of openLibraryLocal(String, boolean) or openLibraryGlob...
long openLibraryGlobal(String pathname, boolean debug)
If a SecurityManager is installed, user needs link permissions for the named library.
long lookupSymbol(long libraryHandle, String symbolName)
Security checks are implicit by previous call of openLibraryLocal(String, boolean) or openLibraryGlob...
Interface callers may use ProcAddressHelper's reset helper method to install function pointers into a...