【问题标题】:Set java.library.path for testing设置 java.library.path 进行测试
【发布时间】:2016-02-12 15:17:04
【问题描述】:

其中一个测试使用原生库:

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 选项中设置库路径:Settings->Build, Execution, Deployment->Build Tools->Maven->Runner->VM options。该选项对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

【问题讨论】:

  • 您是否尝试过使用 LD_LIBRARY_PATH 环境。多变的 ?您是否也尝试过使用 System.load("/usr/local/lib/libmylib.so"); ?
  • 是的,设置 LD_LIBRARY_PATH 确实有帮助!

标签: java maven testing java-native-interface


【解决方案1】:

您可以在测试运行时借助systemPropertyVariables 属性add system properties to the 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 依赖于构建环境的特性。
  • @MichaelIvko 但是 POM 应该是自包含的。所以它应该取决于构建环境的特性。您的解决方案的问题在于它完全依赖于第 3 方 IntelliJ 来保存信息。如果你在命令行或者 CI 服务器上构建它,它就不再起作用了,这违背了使用 Maven 的原则。
  • 添加对指定外部目录中文件的依赖不会使 POM 自包含。该库未包含在显式依赖项中的事实可能违反了 Maven 原则,但我需要按原样构建项目。
  • maven-surefire-plugin 3.0 版显示警告:java.library.path cannot be set as system property, use &lt;argLine&gt; ...(参见 ajschmidt 回答中的示例)
  • 关于库位置的说明:我认为项目所依赖的库应该是工作区(SCM)的一部分,或者在构建期间由定义良好的存储库(版本控制)提供过程。然后您可以使用相对路径。而且您确信您的测试使用与生产服务器相同的二进制文件。
【解决方案2】:

您很可能会遇到此问题,因为您正在使用诸如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>

【讨论】:

    【解决方案3】:

    在 Sachin Handiekar 的评论中,通过在运行 Idea 的环境中设置 LD_LIBRARY_PATH 解决了该问题。 (但出于某种原因,不在 Idea 设置中。)

    【讨论】:

    • 这样做的问题是,它使您的构建依赖于 IntelliJ,而它不应该依赖于 IntelliJ。一切都应该在 POM 中,以便可以在其他地方构建项目。因此,使用此解决方案,例如,它将无法在命令行上运行。
    • 你真的不应该这样做。 maven 的整个想法是 pom 文件应该包含您需要构建的所有信息,并且构建不应依赖于 IntelliJ 或存在于 pom 文件之外的任何配置。这可能在您的计算机上本地运行,但如果您在一个团队中工作,或者您的环境中有任何类型的持续集成,这将无济于事。
    【解决方案4】:

    “native library path not pass through to Maven by Intellij”问题的解决方法:

    我发现您可以使用 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 测试”中的运行期间都可以使用本机库。

    【讨论】:

      【解决方案5】:

      您可以像这样在 maven surefire 插件中配置 VM 选项,

      <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-surefire-plugin</artifactId>
                      <configuration>
                          <argLine>-Djava.library.path=/usr/local/lib</argLine>
                      </configuration>
                      ....
      </plugin>
      

      参考:https://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html

      【讨论】:

        猜你喜欢
        • 2014-11-03
        • 2020-10-20
        • 2017-08-03
        • 1970-01-01
        • 2014-07-25
        • 2010-10-23
        • 2011-11-05
        • 2016-11-05
        • 2015-06-23
        相关资源
        最近更新 更多