【问题标题】:Referencing libraries for a Linux executable引用 Linux 可执行文件的库
【发布时间】:2010-01-20 15:36:17
【问题描述】:

我用 Java 编写了一个应用程序,并使用 gcj 成功编译了它。它运行得非常好,但我遇到了一个障碍:我只能通过 shell 脚本运行可执行文件,因为我必须指定库路径。

我需要的库是 SWT、Xerces 和 GNU-crypto。

gcj 中编译时有没有办法静态链接库,或者这不是一个好主意?或者,我可以在编译时指定(相对)库路径吗?

目前,我的 shell 脚本如下所示:

#!/bin/sh
export LD_LIBRARY_PATH=./libs/:$LD_LIBRARY_PATH
exec ./MyJavaApp $*

【问题讨论】:

  • 这个应用是你自己用的吗?还是您打算将其提供给其他人?如果您自己使用,您可以修改 bashrc 或类似 rc 文件中的 LD_LIBRARY_PATH ,以便在您登录时设置它,您可以取消 shell 脚本。我想这只是你想避免的烦恼?
  • 该应用程序旨在分布在所有平台上。我想避免让用户运行 shell 脚本来运行应用程序。

标签: java linux gcc executable gcj


【解决方案1】:

这个想法是让静态字段“sys_paths”为空,这样它就可以根据更改的值构造路径。 请参阅此处的帖子(AjaySingh516 的帖子#223)http://forums.sun.com/thread.jspa?messageID=3744346#3744346

Class clazz = ClassLoader.class;
Field field = clazz.getDeclaredField("sys_paths");
boolean accessible = field.isAccessible();
if (!accessible)
    field.setAccessible(true);
Object original = field.get(clazz);
// Reset it to null so that whenever "System.loadLibrary" is called, it
// will be reconstructed with the changed value.
field.set(clazz, null);
try {
    // Change the value and load the library.
    System.setProperty("java.library.path", "./libs/");
    System.loadLibrary("mylibapr");
} finally {
    // Revert back the changes.
    field.set(clazz, original);
    field.setAccessible(accessible);
}

.

gcj 系统属性(参见:libgcj 支持的标准属性)

http://gcc.gnu.org/onlinedocs/gcj/System-properties.html

.

解决方案#2 : 在编译时设置系统环境变量

http://linux.die.net/man/1/gcj

为此,您必须使用参数-Djava.library.path=./libs/gcj

来自 gcj 手册(以上链接):

--main= 类名

在链接时使用此选项来指定在运行生成的可执行文件时应调用其“main”方法的类的名称。

-Dname[=值]

此选项只能与“--main”一起使用。它定义了一个名为 name 的系统属性,其值为 value。如果未指定值,则默认为空字符串。 这些系统属性在程序启动时初始化,可以在运行时检索使用“java.lang.System.getProperty”方法。

我从未使用过 gcj,但根据文档,这些系统属性可以在运行时检索,因此它也可以移植到其他系统。

另见:http://gcc.gnu.org/wiki/Statically_linking_libgcj?action=show&redirect=Statically+linking+libgcj

【讨论】:

  • 您可以将“./libs/”和“mylibapr”作为命令行参数传入。
  • 这看起来很有希望;我明天早上去看看!
  • @Paul:想让你知道这个解决方案可能是 JVM 特定的,因此不会超级便携。在这里,我们正在使用 ClassLoader 类的私有变量。这个 Open JDK ClassLoader 源代码有它“docjar.com/html/api/java/lang/ClassLoader.java.html
  • 使用-Djava.library.path 设置环境变量是否只影响我的本地机器,还是会在我运行它的任何Linux 机器上设置可执行文件的库路径?
  • @Paul:有帮助吗?使用额外信息更新解决方案“这些系统属性在程序启动时初始化,可以在运行时检索”。
【解决方案2】:

回答你问题的第一部分 -

来自 gcj 手册页: “libgcj的静态链接可能会导致libgcj的重要部分被省略。libgcj的某些部分在运行时使用反射加载类。由于链接器在链接时看不到这些引用,它可以省略引用的类。结果是通常(但不总是)在运行时抛出“ClassNotFoundException”。使用此选项时必须小心。”

对于其他库的静态链接,我不确定。我没有理由这样做。

Linux 可执行文件不同于 Windows。通常,您有一个“启动器”或类似的东西,具体取决于您使用的确切窗口系统。您在其中设置图标,而不是在可执行文件本身上。通常,启动脚本用于设置运行可执行文件所需的任何环境。同样,这完全取决于您的确切桌面窗口系统。

【讨论】:

  • 所以静态链接可能不是最好的方法。是否有一些指定共享库的标准方法?想到使用make install
  • 我已经拆分了问题;现在可以在这里找到有关图标的部分:stackoverflow.com/questions/2126545/…
【解决方案3】:

您为什么使用 AOT?我建议阅读following article。它提到的 AOT 的缺点之一如下......

动态应用程序。应用程序在运行时动态加载的类可能对应用程序开发人员不可用。这些可以是第三方插件、动态代理和其他运行时生成的类等等。所以运行时系统必须包含一个 Java 字节码解释器和/或一个 JIT 编译器。

【讨论】:

  • 恐怕这不是我的选择。是的,使用解释器会更容易,但我需要提供本机代码的可执行文件。
  • 啊,我看到您在这里找到了第一个问题的答案? stackoverflow.com/questions/1171525/…
  • 嗯,不是真的。我编译了我在回答中演示的库,但是除了在 shell 脚本中更改库路径之外,我无法找到在运行可执行文件时找到它们的方法。感觉很笨拙,必须有一个更整洁的解决方案。
猜你喜欢
  • 2014-01-14
  • 1970-01-01
  • 2018-05-02
  • 2023-03-07
  • 1970-01-01
  • 2021-02-14
  • 2018-06-12
  • 1970-01-01
  • 2013-05-08
相关资源
最近更新 更多