为测试设置Java.library.path

13

其中一个测试使用了本地库:

System.loadLibrary("mylib");

libmylib.so位于/usr/local/lib,所以我在配置VM选项中添加了该目录:-Djava.library.path=/usr/local/lib

但是,当我使用Maven运行测试时,这一行会抛出UnsatisfiedLinkError异常:

java.library.path中没有mylib

Java在未使用此选项的情况下被调用:

/usr/lib/jvm/java-8-oracle/bin/java -Dmaven.home=/opt/idea/plugins/maven/lib/maven3 -Dclassworlds.conf=/opt/idea/plugins/maven/lib/maven3/bin/m2.conf -Didea.launcher.port=7538 -Didea.launcher.bin.path=/opt/idea/bin -Dfile.encoding=UTF-8 -classpath /opt/idea/plugins/maven/lib/maven3/boot/plexus-classworlds-2.4.jar:/opt/idea/lib/idea_rt.jar com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher -Didea.version=15.0.3 test

当捕获异常时,打印System.getProperty("java.library.path")会得到/opt/idea/bin::/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib。显然,运行配置中的VM选项对Maven任务没有影响。

因此,我尝试在Maven的VM选项中设置库路径:设置 -> 构建、执行、部署 -> 构建工具 -> Maven -> 运行器 -> VM选项。此选项对Java调用命令产生影响:

/usr/lib/jvm/java-8-oracle/bin/java -Djava.library.path=/usr/local/lib -Dmaven.home=/opt/idea/plugins/maven/lib/maven3 -Dclassworlds.conf=/opt/idea/plugins/maven/lib/maven3/bin/m2.conf -Didea.launcher.port=7539 -Didea.launcher.bin.path=/opt/idea/bin -Dfile.encoding=UTF-8 -classpath /opt/idea/plugins/maven/lib/maven3/boot/plexus-classworlds-2.4.jar:/opt/idea/lib/idea_rt.jar com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher -Didea.version=15.0.3 test
即使现在Java使用了这个选项,它仍然无法加载库,并且`System.getProperty("java.library.path")`仍包含相同的内容!
如何为使用Maven调用的测试设置`java.library.path`?

1
你尝试过使用LD_LIBRARY_PATH环境变量吗?另外,你尝试使用System.load("/usr/local/lib/libmylib.so");吗? - Sachin
1
是的,设置LD_LIBRARY_PATH确实有帮助! - Michael Ivko
5个回答

7
当使用systemPropertyVariables属性时,您可以在测试运行时通过maven-surefire-plugin添加系统属性来帮助测试。
<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.19.1</version>
  <configuration>
    <systemPropertyVariables>
      <propertyName>java.library.path</propertyName>
      <buildDirectory>/usr/local/lib</buildDirectory>
    </systemPropertyVariables>
  </configuration>
</plugin>

这将在测试运行时将java.library.path添加为系统属性。由于测试是在分叉的VM中运行的,因此不会考虑您所做的修改。

这可能会有所帮助,但我会避免使用它,因为它会使pom.xml依赖于构建环境的特殊性。 - Michael Ivko
@MichaelIvko 但是POM应该是自包含的。因此,它应该依赖于构建环境的特殊性。您解决方案的问题在于它完全依赖于第三方IntelliJ来保存信息。如果您要在命令行或CI服务器上构建此项目,则它将不再起作用,这违反了使用Maven的原则。 - Tunaki
将指定的外部目录中文件的依赖关系添加到项目对象模型(POM)中并不能使其自包含。事实上,库未包含在显式依赖项中可能违反Maven的原则,但我需要按照当前的项目构建方式进行构建。 - Michael Ivko
2
maven-surefire-plugin 的 3.0 版本显示警告:java.library.path 无法设置为系统属性,请使用 <argLine>...(请参考 ajschmidt 的答案示例)。 - Heri
关于库的位置说明:我认为项目所依赖的库应该是工作区(SCM)的一部分,或者在构建过程中由一个明确定义的仓库(版本控制)提供。这样你就可以使用相对路径进行操作。并且你可以确保你的测试使用的二进制文件与生产服务器将要使用的相同。 - Heri
你发布了一个来自手册的配置副本。应该这样进行调整: /usr/local/lib ${project.build.directory} - dimirsen Z

4
你很可能遇到了这个问题,是因为你正在使用像surefire或failsafe这样的Maven插件,它启动一个新的JVM来运行测试,但是你的启动配置没有传递过去。此外,你可能还需要在新进程的命令行上设置'java.library.path',以便在启动时链接本地库及其所有依赖关系。如果你使用'systemPropertyVariables',它将不会产生相同的效果,但如果你幸运的话,它可能会起作用。这是一个对我有用的示例插件配置:
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.19</version>
            <executions>
                <execution>
                    <id>my-external-tests</id>
                    <goals>
                        ...
                    </goals>
                    <configuration>
                        <argLine>-Djava.library.path=/usr/local/lib</argLine>
                        <groups>com.myCompany.ExternalTest</groups>
                        <includes>
                            <include>**/*Suite.java</include>
                        </includes>
                    </configuration>
                </execution>
            </executions>
        </plugin>

2

正如Sachin Handiekar评论中所述,问题可以通过在运行Idea的环境中设置LD_LIBRARY_PATH来解决。(但出于某些原因,不能在Idea设置中解决。)


1
问题在于这会使得你的构建依赖于 IntelliJ,而实际上不应该这样。所有东西都应该在 POM 中,以便项目可以在其他地方构建。因此,使用这种解决方案,在命令行中就无法工作。 - Tunaki
2
你真的不应该这样做。Maven 的整个理念是 pom 文件应该包含构建所需的所有信息,并且构建不应依赖于 IntelliJ 或存在于 pom 文件之外的任何配置。这在你的本地计算机上可能有效,但如果你在团队中工作或者环境中有任何形式的持续集成,这将毫无帮助。 - Dawood ibn Kareem

0
解决“Intellij未将本地库路径传递给Maven”的问题:
我发现你可以利用JVM已经搜索的本地目录。
首先,在Junit测试或实时代码期间,使用System.out消息打印您的java.library.path。
在我的Mac上,我得到了以下结果:
/Users/gareth/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.

这个库路径的第一部分为我们提供了一个解决问题的方法,因为JVM首先搜索用户本地目录(/Users/gareth/Library/Java/Extensions),我们可以将jnilib文件链接到这里:
所以:
$ mkdir -p /Users/gareth/Library/Java/Extensions

$ cd /Users/gareth/Library/Java/Extensions

$ ln -s /Users/gareth/Applications/IBM/ILOG/CPLEX_Studio_Community127/cplex/bin/x86-64_osx/libcplex1270.jnilib libcplex1270.jnilib

这种方法的不便之处在于它是一项定制的“每个用户”操作,但似乎与在IDE中为每个用户执行此操作没有什么区别。

现在本地库既可以在Intellij中进行单独的单元测试运行时使用,也可以在“maven test”中运行时使用。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接