我正在使用Google或tools library(v6.4)进行一个项目(尽管我的问题并不是针对这个库)。这包括一个jar,它有几个本机依赖项(一组“.so”/.dylib”对象文件,具体取决于操作系统)。我的这个项目的构建是在Ubuntu 14.04上完成的
我面临的问题是:在运行时尝试加载特定的对象文件时(使用
System.load()
),我收到一个不满意的链接错误,消息为“undefined symbol”(我在下面添加了stacktrace)。但是,我正在加载在此之前定义此符号的对象文件,所以我不确定为什么会抛出此错误。
我以以下方式加载依赖项:对象文件被打包到Maven在构建期间创建的jar中,并被提取和加载(使用
系统加载()
)在运行时。其方法如下:
public class EnvironmentUtils {
public static void loadResourceFromJar(String prefix, String suffix) {
String tempFilesDirectory = System.getProperty("java.io.tmpdir");
File tempFile = null;
try {
tempFile = new File(tempFilesDirectory + "/" + prefix + suffix);
tempFile.deleteOnExit();
try (final InputStream inputStream = EnvironmentUtils.class.getClassLoader().
getResourceAsStream(prefix+suffix)) {
if (inputStream == null) {
throw new RuntimeException(prefix + suffix + " was not found inside JAR.");
} else {
Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
System.load(tempFile.getAbsolutePath());
} catch (Exception e) {
}
}
}
正在静态块内为所有依赖项调用此方法:
public class DummyClass {
static {
String sharedLibraryExtension = EnvironmentUtils.getSharedLibraryExtension();
String jniLibraryExtension = EnvironmentUtils.getJniLibraryExtension();
EnvironmentUtils.loadResourceFromJar("libfap", sharedLibraryExtension);
EnvironmentUtils.loadResourceFromJar("libcvrptw_lib", sharedLibraryExtension);
EnvironmentUtils.loadResourceFromJar("libortools", sharedLibraryExtension);
EnvironmentUtils.loadResourceFromJar("libdimacs", sharedLibraryExtension);
EnvironmentUtils.loadResourceFromJar("libjniortools", jniLibraryExtension);
}
}
运行时
系统加载()
对于libdimacs。因此,抛出了一个UnsatifiedLinkError。堆栈跟踪:
java.lang.UnsatisfiedLinkError: /tmp/libdimacs.so: /tmp/libdimacs.so: undefined symbol: _ZN6google14FlagRegistererC1IbEEPKcS3_S3_PT_S5_
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
at java.lang.Runtime.load0(Runtime.java:809)
at java.lang.System.load(System.java:1086)
at com.(PROJECT_NAME).utils.EnvironmentUtils.loadResourceFromJar(EnvironmentUtils.java:78)
at com.(PROJECT_NAME).DummyClass.<clinit>(DummyClass.java:28)
但是,libortools中存在此符号“\u ZN6google14FlagRegistererC1IbEEPKcS3\u S3\u PT\u S5\u”。所以,它是在libdimacs之前加载的。我通过运行以下命令验证了这一点:
objdump -t (LIBRARY_PATH)/libortools.so | grep _ZN6google14FlagRegistererC1IbEEPKcS3_S3_PT_S5_
这给了我以下输出:
0000000000ce12cc gw F .text 00000091 _ZN6google14FlagRegistererC1IbEEPKcS3_S3_PT_S5_
因此,似乎符号应该在
系统加载()
调用,除非加载包含的对象文件时出现问题。为了检查对象文件是否已正确加载,我使用了中详细介绍的方法
this solution
.除了答案中详述的课程外,我在后面添加了以下几行
系统加载()
请来
EnvironmentUtils.loadResourceFromJar()
要打印最近加载的库名称,请执行以下操作:
public class EnvironmentUtils {
public static void loadResourceFromJar(String prefix, String suffix) {
...
System.load(tempFile.getAbsolutePath());
final String[] libraries = ClassScope.getLoadedLibraries(ClassLoader.getSystemClassLoader());
System.out.println(libraries[libraries.length - 1]);
}
}
输出(直到UnsatifiedLinkError之前)如下所示:
/tmp/libfap.so
/tmp/libcvrptw_lib.so
/tmp/libortools.so
所以libortools。因此似乎加载正确,这意味着符号应该加载到内存中。完全相同的代码与相应的Mac(“.dylib”)依赖项(构建于MacOS Sierra 10.12.5)完美配合。如果您有任何关于解决此问题的建议,我们将不胜感激。非常感谢。