【问题标题】:Can standalone Haskell Executable run across Machine having the same OS?独立的 Haskell 可执行文件可以在具有相同操作系统的机器上运行吗?
【发布时间】:2020-04-09 06:12:47
【问题描述】:

注意:我正在使用堆栈。 当我们这样做时(比如在 CentOS 机器上)

stack install --ghc-options='-optl-static -optl-pthread' --force-dirty --local-bin-path path-to-executable(my-project-exe)

新创建的 my-project-exe 可执行文件能否通过运行 ./my-project-exe 跨机器运行(具有相同的操作系统/架构)? 对不起,如果这个问题看起来很基本,但我想从第一原则来理解这一点。

这个 haskell 可执行文件到底是什么?:除了基本的系统/操作系统调用之外,这是一个安装了所有依赖项的单个文件吗?

我的用例:我在我的机器上为我的项目创建了一个 haskell 可执行文件。只需将其复制到具有相同操作系统的另一台机器上,我就可以运行此可执行文件,所需的最少安装次数是多少?新安装数量为零是最好的。

PS:./my-project-exe 在我运行 stack-install 命令的机器上就像一个魅力。

【问题讨论】:

  • 在任何 linux 可执行文件上,ldd name-of-exe 应该生成运行时需要的共享库列表。如果这些存在于其他机器中,你应该没问题。 Haskell 可执行文件通常是静态链接的,因此您应该只找到几个 C 库。
  • 我运行了命令 stack build --ghc-options='-fPIC -optl-pthread' --force-dirty:在执行 ldd name-of-exe 时,我得到了一个共享库的列表。当我将此可执行文件复制到新机器时,我还需要手动将其中一些 .so 文件复制到该新机器。我的问题是,即使使用 -fPIC 标志(位置无关代码),为什么它仍然依赖于这么多共享库。它不应该构建 1 个独立的可执行文件吗?

标签: haskell ghc haskell-stack haskell-platform


【解决方案1】:

也许吧。

在一台机器上构建的可执行文件可能无法在另一台机器上正常运行有几个原因。您可以按照自己的方式在列表中进行操作,并考虑每种方法如何适用于您的具体案例。 (前三个您已经提到过,但为了完整起见,我还是将它们包括在内。)

  1. 不同的操作系统。每个操作系统都有自己的二进制容器格式,它们通常不能互操作。但是,容器格式在不同操作系统版本中保持相同是很常见的。
  2. 架构不同。 不同公司制造的 CPU 通常具有完全不同的指令集。如今,几乎所有消费级计算机都使用 x86-64 指令集,因此除非您正在做一些相当特别的事情,否则这应该不是问题。但是,如果您正在为嵌入式系统或其他利基市场开发,您可能需要更加注意这一点。
  3. 不同的动态库。许多程序使用来自外部库的代码,并且通常依赖操作系统来定位和加载这些库。即使使用静态链接,也有一些核心库对于“将所有代码直接转储到二进制文件”请求几乎总是例外。在 Linux 上,您可能会问 ldd 特定二进制文件期望能够链接到哪些库。当然,对于每个链接的库,这里也有一个需要注意的版本控制故事。
  4. 不同的外围设备/硬件。例如,一台计算机可能是某人的宠物超级计算机,具有 128GB 的​​ RAM,而另一台则运行在他们老化的具有 4GB RAM 的工作笔记本电脑上。但也有许多不太明显的可能问题的例子:也许一个显示器是高清的,另一个是 4K;或者一台计算机有 GPU 而另一台没有;或者一台电脑有麦克风而另一台没有;或其他一百万个可能潜入你的小差异。
  5. 不同的文件系统属性。这里最大的问题是有些文件系统不区分大小写,有些则不。如果您为一个程序开发并在另一个程序上运行,您的程序可能会与您预期的不同。
  6. 不同的磁盘资源。 许多程序都依赖于包含运行所需数据的文件;例如,游戏与音效、关卡地图、精灵等捆绑在一起,而 Web 服务器通常会附带一组他们希望从静态目录中提供服务的文件,或者 CRUD 应用程序可能会附带一个描述布局的文件它的 GUI 小部件或编排层可能需要安装某些辅助程序。这些文件需要转移到另一台机器上的适当位置,程序才能正常运行。
  7. 不同的服务。 许多程序进行进程间通信,例如通过连接端口、在 DBUS 上发送消息、查找特定套接字等。如果提供这些机制的服务尚未安装或尚未启动,则会导致程序无法正常工作。
  8. 不同的环境变量。正确传输程序可能涉及通过环境设置一些配置信息。

可能还有其他的,但这些都会直接浮现在脑海中。

【讨论】:

    【解决方案2】:

    默认情况下,Stack 创建一个带有 GHC 运行时的可执行文件,并将已编译的 Haskell 库静态链接到该可执行文件中。但是,它通常会链接到标准 O/S 库的动态版本(例如,libclibpthread)以及——更重要的是——Haskell 包使用的外部 C 库。例如,我有一个使用 hmatrixhmatrix-glpk 包的 Stack 项目。它们使用 BLAS、LAPACK 和 GLPK 库,并且可执行文件依赖于这些库上的共享版本,除其他外:

    $ ldd ctest
        linux-vdso.so.1 (0x00007fff791bd000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd45e197000)
        libglpk.so.40 => /lib/x86_64-linux-gnu/libglpk.so.40 (0x00007fd45deb8000)
        libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007fd45de4b000)
        liblapack.so.3 => /lib/x86_64-linux-gnu/liblapack.so.3 (0x00007fd45d7b1000)
        libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fd45d730000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fd45d725000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd45d71d000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd45d6fa000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd45d509000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd45e301000)
        libcolamd.so.2 => /lib/x86_64-linux-gnu/libcolamd.so.2 (0x00007fd45d500000)
        libamd.so.2 => /lib/x86_64-linux-gnu/libamd.so.2 (0x00007fd45d4f5000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fd45d4d9000)
        libltdl.so.7 => /lib/x86_64-linux-gnu/libltdl.so.7 (0x00007fd45d4cc000)
        libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007fd45d22c000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd45d212000)
        libsuitesparseconfig.so.5 => /lib/x86_64-linux-gnu/libsuitesparseconfig.so.5 (0x00007fd45d20d000)
        libquadmath.so.0 => /lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007fd45d1c3000)
    

    除了这些对共享库的依赖之外,可执行文件是自包含的,因此它可以被复制到另一台机器即使没有堆栈或 GHC 安装,只要共享库就在那里。

    如果您可以说服 Stack 创建一个真正的静态二进制文件,那么它应该是完全独立的(嗯,除了对您或某些库引入的其他资源的任何显式依赖)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      相关资源
      最近更新 更多