-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Embedded native library in the JAR file #120
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,10 @@ | |
package com.sun.jna; | ||
|
||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.FilenameFilter; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.lang.ref.WeakReference; | ||
import java.lang.ref.Reference; | ||
import java.lang.reflect.Method; | ||
|
@@ -165,13 +168,80 @@ else if (Platform.isWindows()) { | |
try { handle = Native.open(libraryPath); } | ||
catch(UnsatisfiedLinkError e2) { e = e2; } | ||
} | ||
// As a last resort, try to extract the library from the JAR | ||
if (handle == 0) { | ||
final String embeddedLib = getEmbeddedLibraryPathFromJar(mapLibraryName(libraryName)); | ||
if (embeddedLib != null) | ||
{ | ||
try { | ||
handle = Native.open(embeddedLib); | ||
} | ||
catch (UnsatisfiedLinkError e2) { e = e2; } | ||
} | ||
} | ||
if (handle == 0) { | ||
throw new UnsatisfiedLinkError("Unable to load library '" + libraryName + "': " | ||
+ e.getMessage()); | ||
} | ||
} | ||
return new NativeLibrary(libraryName, libraryPath, handle, options); | ||
} | ||
|
||
private static String getEmbeddedLibraryPathFromJar(String libraryName) | ||
{ | ||
// Do not extract the library from JAR if jna.nounpack=true | ||
if (Boolean.getBoolean("jna.nounpack")) { | ||
return null; | ||
} | ||
final String libraryPath = System.getProperty("os.name") + "-" + System.getProperty("os.arch") + "/"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This prefix is problematic in that the two properties are not terribly consistent across OS versions and JVMs. JNA's more canonical representation would be better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. However, the advantage of using these prefixes is that it makes it very easy to copy the native libs in the right folders from Maven or even Ant. But you're right, there are not very consistent (I don't understant why there are so many different names for Windows for exemple). |
||
File libFile; | ||
try | ||
{ | ||
libFile = extractEmbeddedLibraryResource(libraryPath, libraryName); | ||
} | ||
catch (IOException e) | ||
{ | ||
return null; | ||
} | ||
if (libFile == null) | ||
{ | ||
return null; | ||
} | ||
else | ||
{ | ||
return libFile.getAbsolutePath(); | ||
} | ||
} | ||
|
||
private static File extractEmbeddedLibraryResource(String libraryPath, String libraryName) throws IOException { | ||
final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(libraryPath + libraryName); | ||
if (is == null) { | ||
return null; | ||
} | ||
FileOutputStream fos = null; | ||
File lib = null; | ||
try { | ||
// Suffix is required on windows, or library fails to load | ||
// Let Java pick the suffix, except on windows, to avoid | ||
// problems with Web Start. | ||
File dir = Native.getTempDir(); | ||
lib = File.createTempFile(libraryName, Platform.isWindows()?".dll":null, dir); | ||
lib.deleteOnExit(); | ||
fos = new FileOutputStream(lib); | ||
int count; | ||
byte[] buf = new byte[1024]; | ||
while ((count = is.read(buf, 0, buf.length)) > 0) { | ||
fos.write(buf, 0, count); | ||
} | ||
} | ||
finally { | ||
try { is.close(); } catch(IOException e) { } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll let @twall comment on this, but I think catching and ignoring exceptions here is a really bad practice. This is just not supposed to fail, and if it does, something has gone awfully wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part is a small copy/paste of Native.LoadNativeLibraryFromJar(). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a commonly ignored exception in Java; there really is no recourse and in practice I've never actually seen the error. |
||
if (fos != null) { | ||
try { fos.close(); } catch(IOException e) { } | ||
} | ||
} | ||
return lib; | ||
} | ||
|
||
private String getLibraryName(String libraryName) { | ||
String simplified = libraryName; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a different flag;
jna.nounpack
specifically forbids unpacking JNA's native bits; it shouldn't be re-used to forbid unpacking additional native bits unless the two situations are identical (I don't think they are).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the idea was to forbid unpacking because, for example, we were not allowed to write in the temp folder. So I thought both situations were similar.