具有包含本机库的 aar 依赖项的 OSGI jar 中的不满意 link 错误
Unsatisfied link error in an OSGI jar with an aar dependency that includes native libraries
我正在尝试使用 Maven 构建一个 OSGI jar,它依赖于包含本机库的 aar。
我没有将 aar 添加为依赖项,而是提取了 classes.jar 并将其添加为依赖项,然后将共享库添加到 jar 根目录的 libs/ 目录中。
jar 的最终结构如下所示。
/org/MyClasses
/org/LibClasses (from aar)
/libs/armeabi-v7a/allNativeFiles (from aar)
/META-INF/MANIFEST.MF
当调用 LibClasses 提供的方法时,它会调用 System.loadLibrary('some_so_file')加载 .so 文件之一,但调用抛出一个未满足的 link 错误,因为它无法在路径中找到文件。
例外情况:
07-22 06:31:30.112: E/art(2537):
dlopen("/data/data/org.ambientdynamix.core/files/felix/felix-cache/bundle14/version0.0/bundle.jar-lib/0/libs/armeabi-v7a/liboc_logger.so",
RTLD_LAZY) failed: dlopen failed: could not load library
"libgnustl_shared.so" needed by "liboc_logger.so"; caused by library
"libgnustl_shared.so" not found
Android 正在寻找位于 .../bundle 的 .so 文件。jar-lib/0/libs/armeabi-v7a 当文件位于 .../bundle.jar/libs/armeabi-v7a
来自 POM 的插件配置:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<!-- configure plugin to generate MANIFEST.MF -->
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- configure plugin to support jar packaging -->
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
</supportedProjectTypes>
<instructions>
<Export-Package>
org.ambientdynamix.contextplugins.iotivity
</Export-Package>
<Bundle-NativeCode>libs/armeabi-v7a/libca-interface.so ;
libs/armeabi-v7a/libconnectivity_abstraction.so ; libs/armeabi-v7a/libgnustl_shared.so
;libs/armeabi-v7a/liboc.so ;libs/armeabi-v7a/liboc_logger.so
;libs/armeabi-v7a/libocstack-jni.so ;libs/armeabi-v7a/liboctbstack.so ;
osname=Linux;
processor=arm_le
</Bundle-NativeCode>
<Import-Package>org.ambientdynamix.api.application,
org.ambientdynamix.api.contextplugin,
org.ambientdynamix.api.contextplugin.security
</Import-Package>
<Bundle-ClassPath>
.
</Bundle-ClassPath>
<Bundle-Activator/>
<Include-Resource>native=src/main/resources/libs</Include-Resource>
<DynamicImport-Package>*</DynamicImport-Package>
<Bundle-SymbolicName>org.ambientdynamix.contextplugins.iotivity</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
有什么可能的方法来解决这个问题吗?
这里的问题是您有多个相互依赖的库。通常,一个库是通过 System.loadLibrary 调用在 Java 代码中引用的 JNI 代码。然后该库将引用另一个库。问题是 VM 进程不知道如何找到其他库,因为它们位于文件夹中(例如 /data/data/org.ambientdynamix.core/files/felix/felix-cache/bundle14/version0.0/bundle.jar-lib/0/libs/) VM 进程不知道也不在 LD_LIBRARY_PATH.
一个可能的解决方案是让您的 java 代码在每个库上调用 System.loadLibrary,但您必须按正确的顺序执行此操作。首先加载不依赖于任何其他库的库,然后加载依赖于已加载库的库,最后加载 JNI 库。这样每个库的依赖项都已经加载到 VM 进程中以链接到当前加载的库。
这不是一个很好的解决方案,因为您有很多库要加载并且希望依赖图中没有循环。
我正在尝试使用 Maven 构建一个 OSGI jar,它依赖于包含本机库的 aar。
我没有将 aar 添加为依赖项,而是提取了 classes.jar 并将其添加为依赖项,然后将共享库添加到 jar 根目录的 libs/ 目录中。
jar 的最终结构如下所示。
/org/MyClasses
/org/LibClasses (from aar)
/libs/armeabi-v7a/allNativeFiles (from aar)
/META-INF/MANIFEST.MF
当调用 LibClasses 提供的方法时,它会调用 System.loadLibrary('some_so_file')加载 .so 文件之一,但调用抛出一个未满足的 link 错误,因为它无法在路径中找到文件。
例外情况:
07-22 06:31:30.112: E/art(2537): dlopen("/data/data/org.ambientdynamix.core/files/felix/felix-cache/bundle14/version0.0/bundle.jar-lib/0/libs/armeabi-v7a/liboc_logger.so", RTLD_LAZY) failed: dlopen failed: could not load library "libgnustl_shared.so" needed by "liboc_logger.so"; caused by library "libgnustl_shared.so" not found
Android 正在寻找位于 .../bundle 的 .so 文件。jar-lib/0/libs/armeabi-v7a 当文件位于 .../bundle.jar/libs/armeabi-v7a
来自 POM 的插件配置:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<!-- configure plugin to generate MANIFEST.MF -->
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- configure plugin to support jar packaging -->
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
</supportedProjectTypes>
<instructions>
<Export-Package>
org.ambientdynamix.contextplugins.iotivity
</Export-Package>
<Bundle-NativeCode>libs/armeabi-v7a/libca-interface.so ;
libs/armeabi-v7a/libconnectivity_abstraction.so ; libs/armeabi-v7a/libgnustl_shared.so
;libs/armeabi-v7a/liboc.so ;libs/armeabi-v7a/liboc_logger.so
;libs/armeabi-v7a/libocstack-jni.so ;libs/armeabi-v7a/liboctbstack.so ;
osname=Linux;
processor=arm_le
</Bundle-NativeCode>
<Import-Package>org.ambientdynamix.api.application,
org.ambientdynamix.api.contextplugin,
org.ambientdynamix.api.contextplugin.security
</Import-Package>
<Bundle-ClassPath>
.
</Bundle-ClassPath>
<Bundle-Activator/>
<Include-Resource>native=src/main/resources/libs</Include-Resource>
<DynamicImport-Package>*</DynamicImport-Package>
<Bundle-SymbolicName>org.ambientdynamix.contextplugins.iotivity</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
有什么可能的方法来解决这个问题吗?
这里的问题是您有多个相互依赖的库。通常,一个库是通过 System.loadLibrary 调用在 Java 代码中引用的 JNI 代码。然后该库将引用另一个库。问题是 VM 进程不知道如何找到其他库,因为它们位于文件夹中(例如 /data/data/org.ambientdynamix.core/files/felix/felix-cache/bundle14/version0.0/bundle.jar-lib/0/libs/) VM 进程不知道也不在 LD_LIBRARY_PATH.
一个可能的解决方案是让您的 java 代码在每个库上调用 System.loadLibrary,但您必须按正确的顺序执行此操作。首先加载不依赖于任何其他库的库,然后加载依赖于已加载库的库,最后加载 JNI 库。这样每个库的依赖项都已经加载到 VM 进程中以链接到当前加载的库。
这不是一个很好的解决方案,因为您有很多库要加载并且希望依赖图中没有循环。