动态连接库在不同平台的加载

本文介绍了一种按平台架构分类存放并加载动态连接库的方法,通过将动态库解压到临时目录来实现跨平台的动态库加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态连接库在不同平台的加载,代码来源于JNA项目
原理把动态连接库按平台架构进行分类存放,加载时就把对应的平台架构的动态连接库解压到临时目录再进行加载,这样就不需要把动态连接放到system32或lib等指定的目录下。
以下是动态连接放置的路径结构:
===============================
rxtxlib
|_______darwin
|_______linux-amd64
|_______linux-i386
|_______linux-i686
|_______linux-ia64
|_______linux-x86_64
|_______sunos-sparc
|_______sunos-sparc32
|_______sunos-sparc64
|_______sunos-x86
|_______win32-x86
===============================

package gnu.io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class LoadLibrary {

private static Map nativeLibMap = new HashMap();

private static String getNativeLibraryResourcePath() {
String arch = System.getProperty("os.arch");
String osPrefix;
if (Platform.isWindows()) {
osPrefix = "win32-" + arch;
} else if (Platform.isMac()) {
osPrefix = "darwin";
} else if (Platform.isLinux()) {
osPrefix = "linux-" + arch;
} else if (Platform.isSolaris()) {
osPrefix = "sunos-" + arch;
} else {
osPrefix = System.getProperty("os.name").toLowerCase();
int space = osPrefix.indexOf(" ");
if (space != -1) {
osPrefix = osPrefix.substring(0, space);
}
osPrefix += "-" + arch;
}
return "/rxtxlib/" + osPrefix;
}

private static String getNativeLibraryResourceSuffix() {
String arch = System.getProperty("os.arch");
String osPrefix;
if (Platform.isWindows()) {
osPrefix = ".dll";
} else if (Platform.isMac()) {
osPrefix = ".jnilib";
} else if (Platform.isLinux()) {
osPrefix = ".so";
} else if (Platform.isSolaris()) {
osPrefix = ".so";
} else {
osPrefix = ".so";
}
return osPrefix;
}

public static void loadNativeLibrary(String nativeLibName) {

if (nativeLibMap.get(nativeLibName) != null) {
System.load(nativeLibMap.get(nativeLibName).toString());
return;
}

String libname = System.mapLibraryName(nativeLibName);
String resourceName = getNativeLibraryResourcePath() + "/" + libname;
URL url = LoadLibrary.class.getResource(resourceName);

// Add an ugly hack for OpenJDK (soylatte) - JNI libs use the usual .dylib extension
if (url == null && Platform.isMac() && resourceName.endsWith(".dylib")) {
resourceName = resourceName.substring(0, resourceName
.lastIndexOf(".dylib"))
+ ".jnilib";
url = LoadLibrary.class.getResource(resourceName);
}
if (url == null) {
throw new UnsatisfiedLinkError("jnidispatch (" + resourceName
+ ") not found in resource path");
}

File lib = null;
if (url.getProtocol().toLowerCase().equals("file")) {
try {
lib = new File(URLDecoder.decode(url.getPath(), "UTF8"));
} catch (UnsupportedEncodingException e) {
throw new Error("JRE is unexpectedly missing UTF8 encoding");
}
} else {
InputStream is = LoadLibrary.class
.getResourceAsStream(resourceName);
if (is == null) {
throw new Error("Can't obtain jnidispatch InputStream");
}

FileOutputStream fos = null;
try {
// Suffix is required on windows, or library fails to load
// Let Java pick the suffix
lib = File.createTempFile(nativeLibName, null);
lib.deleteOnExit();
// Have to remove the temp file after VM exit on w32
if (Platform.isWindows() && nativeLibMap.isEmpty()) {
Runtime.getRuntime().addShutdownHook(new W32Cleanup());
}
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);
}
} catch (IOException e) {
throw new Error(
"Failed to create temporary file for jnidispatch library",
e);
} finally {
try {
is.close();
} catch (IOException e) {}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {}
}
}
}

nativeLibMap.put(nativeLibName, lib.getAbsolutePath());

System.load(lib.getAbsolutePath());
}

public static class W32Cleanup extends Thread {

public W32Cleanup() {}

public void run() {
StringBuffer sb = new StringBuffer();
if (!nativeLibMap.isEmpty()) {
for (Iterator it = nativeLibMap.values().iterator(); it
.hasNext();) {
sb.append(it.next()).append(";");
}
}
nativeLibMap.clear();
System.out.println(sb.toString());
try {
Runtime.getRuntime()
.exec(
new String[] {
System.getProperty("java.home")
+ "/bin/java", "-cp",
System.getProperty("java.class.path"),
getClass().getName(), sb.toString() });
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
sb.append(args[i]);
}
}
if (sb.length() > 0) {
String[] fileNames = sb.toString().split(";");
for (int i = 0; i < fileNames.length; i++) {
File file = new File(fileNames[i]);
if (file.exists()) {
long start = System.currentTimeMillis();
while (!file.delete() && file.exists()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
if (System.currentTimeMillis() - start > 1000)
break;
}
}
}
}
System.exit(0);
}
}

public final static class Platform {
private static final int UNSPECIFIED = -1;
private static final int MAC = 0;
private static final int LINUX = 1;
private static final int WINDOWS = 2;
private static final int SOLARIS = 3;
private static final int FREEBSD = 4;
private static final int osType;

static {
String osName = System.getProperty("os.name");
if (osName.startsWith("Linux")) {
osType = LINUX;
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
osType = MAC;
} else if (osName.startsWith("Windows")) {
osType = WINDOWS;
} else if (osName.startsWith("Solaris")
|| osName.startsWith("SunOS")) {
osType = SOLARIS;
} else if (osName.startsWith("FreeBSD")) {
osType = FREEBSD;
} else {
osType = UNSPECIFIED;
}
}

private Platform() {}

public static final boolean isMac() {
return osType == MAC;
}

public static final boolean isLinux() {
return osType == LINUX;
}

public static final boolean isWindows() {
return osType == WINDOWS;
}

public static final boolean isSolaris() {
return osType == SOLARIS;
}

public static final boolean isFreeBSD() {
return osType == FREEBSD;
}

public static final boolean isX11() {
// TODO: check FS or do some other X11-specific test
return !Platform.isWindows() && !Platform.isMac();
}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值