【问题标题】:How to produce static executable on NixOS?如何在 NixOS 上生成静态可执行文件?
【发布时间】:2020-11-15 00:21:21
【问题描述】:

今天我的 NixOS 发行版遇到了一个非常有趣的问题。我只是想创建一个静态编译的 OCaml 程序,但做不到。然后我尝试使用 ANSI C 规范玩具“hello world!”来做到这一点。应用:

$> cat mytest.c 
#include <stdio.h>

int
main ()
{
  puts ("hello world!") ;
}

我的发行版:

$> uname -a
Linux cat 4.19.36 #1-NixOS SMP Sat Apr 20 07:16:05 UTC 2019 x86_64 GNU/Linux

编译器:

$> gcc -v
Using built-in specs.
COLLECT_GCC=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/bin/gcc
COLLECT_LTO_WRAPPER=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/libexec/gcc/x86_64-unknown-linux-gnu/7.4.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: 
Thread model: posix
gcc version 7.4.0 (GCC)

无法产生静态执行:

$> gcc -static mytest.c -o hello
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

有什么想法吗?

通常由gcc生成“动态链接”程序hello没有问题。

在 Lubuntu 上没有此类问题。有人建议我尝试不同的发行版并测试 exec 在 NixOS 上运行。我做到了——在 Lubuntu 上用gcc 生成了一个 exec,并在 NixOS 上启动了它。因此我认为问题不在于gcc,而在于 NixOS。

NixOS 如何处理这个问题(即生成静态编译的 exec 文件)?

当然,我也对ocamlopt 编译器而不是gcc 的结果感兴趣,但我认为这个问题对于所有编译器都很常见(顺便说一下,我也尝试过 Haskell ghc结果相同)。

brgs

更新:来自另一个线程的讨论:

  1 @Ston17 You may have the .so but not the .a – norok2 
  2 
  3 yes - i have .so what the difference? can the presence of .a improve the situation? – Ston17
  4 
  5 Yes. You typically need .a library to have the static linking work correctly – norok2


$> find /nix/store/ -name *libc.a.*
$> 

可能是这个原因吗?

UPDATE2:关于 ocamlopt:

源文件

$> cat mytest.ml
print_string "hello world!" ;;
print_newline () ;;

你可以看到没有对任何东西的特殊调用。让我们尝试做静态执行:

$> ocamlopt -ccopt -static mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lm
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -ldl
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

所以 ld 只是无法链接到 libc 的静态版本。我在孔系统中找不到 libc.a

有什么建议吗?

【问题讨论】:

  • 你可以在 nix-shell 中尝试:$ nix-shell -p glibc.static。适用于 GCC,但我不了解 Ocaml。
  • tnx - 这对我帮助很大

标签: gcc nixos


【解决方案1】:

这里https://vaibhavsagar.com/blog/2018/01/03/static-haskell-nix/ 解释了如何在 NixOS 中获取静态版本的 sys 库

nix-shell 配置文件:

let
  pkgs = import <nixpkgs> {} ;
in pkgs.buildFHSUserEnv {
  name = "fhs" ;
  targetPkgs = pkgs: with pkgs; [
    pkgs.glibc.static
    pkgs.zlib.static
    pkgs.libffi
    pkgs.libtool
    pkgs.musl
    pkgs.ghc
    pkgs.gcc
    pkgs.ocaml
  ] ;
}

然后在 nix-shell 中启动 chroot FHS 并将所需的 sys 库复制到您的文件夹中并关闭 chroot FHS

然后静态编译你的文件

gcc 很好:

$> gcc -static -L/home/.local/lib/ mytest.c -o ansiC_test
$> ldd ansiC_test 
  not a dynamic executable

不太好,但可能与 ocaml 合作:

ocamlopt -ccopt -static -cclib -L/home/.local/lib mytest.ml -o ocaml_test

ocamlopt -ccopt -static -cclib -L/home/nomad/.local/lib mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/j1v6kkxq081q4m4fw7gazaf6rb3vy87p-ocaml-4.06.1/lib/ocaml/libasmrun.a(unix.o): in function `caml_dlopen':
/build/ocaml-4.06.1/asmrun/unix.c:273: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

$> ldd ocaml_test 
  not a dynamic executable

不要使用 ghc :

ghc -static -optl-static -L/home/.local/lib/ mytest.hs -o haskell_test
[1 of 1] Compiling Main             ( mytest.hs, mytest.o )
Linking haskell_test ...
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/wfgrz42bpcl1r635dasfk7r236hm83az-ghc-8.6.4/lib/ghc-8.6.4/rts/libHSrts.a(Linker.o): in function `internal_dlopen':
Linker.c:(.text.internal_dlopen+0x7): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lffi
collect2: error: ld returned 1 exit status
`cc' failed in phase `Linker'. (Exit code: 1)
make: *** [makefile:5: haskell] Error 1

好的。 ocaml 工作:

lubuntu@lubuntu:~/Documents$ ./ocaml_hello_nix 
hello world!

lubuntu@lubuntu:~/Documents$ readelf -l ocaml_hello_nix 

Elf file type is EXEC (Executable file)
Entry point 0x4017a0
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000005d8 0x00000000000005d8  R      0x1000
  LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000
                 0x0000000000107275 0x0000000000107275  R E    0x1000
  LOAD           0x0000000000109000 0x0000000000509000 0x0000000000509000
                 0x00000000000db191 0x00000000000db191  R      0x1000
  LOAD           0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
                 0x0000000000008a18 0x000000000001dfe0  RW     0x1000
  NOTE           0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x0000000000000020 0x0000000000000020  R      0x4
  NOTE           0x0000000000000258 0x0000000000400258 0x0000000000400258
                 0x0000000000000020 0x0000000000000020  R      0x8
  TLS            0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
                 0x0000000000000020 0x0000000000000060  R      0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000

                     0x0000000000000000 0x0000000000000000  RW     0x10
      GNU_RELRO      0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
                     0x0000000000002ec0 0x0000000000002ec0  R      0x1

     Section to Segment mapping:
      Segment Sections...
       00     .note.ABI-tag .note.gnu.property .rela.plt 
       01     .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini 
       02     .rodata .eh_frame .gcc_except_table 
       03     .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data __libc_subfreeres __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs 
       04     .note.ABI-tag 
       05     .note.gnu.property 
       06     .tdata .tbss 
       07     
       08     .tdata .init_array .fini_array .data.rel.ro .got 

haskell 有效。原因是二进制 NixOS 数据包是在没有 FFI 支持的情况下构建的。我从源代码安装了 ghc,一切都变得很好:

lubuntu@lubuntu:~/Documents$ ./haskell_hello_nix 
hello world!

lubuntu@lubuntu:~/Documents$ readelf -l haskell_hello_nix 

Elf file type is EXEC (Executable file)
Entry point 0x405d40
There are 6 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000188ba4 0x0000000000188ba4  R E    0x1000
  LOAD           0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
                 0x00000000000104c0 0x000000000001ac98  RW     0x1000
  NOTE           0x0000000000000190 0x0000000000400190 0x0000000000400190
                 0x0000000000000020 0x0000000000000020  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  TLS            0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
                 0x0000000000000070 0x00000000000000b8  R      0x8
  GNU_RELRO      0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
                 0x0000000000003140 0x0000000000003140  RW     0x20

 Section to Segment mapping:
  Segment Sections...
   00     .note.ABI-tag .rela.plt .init .plt .text __libc_thread_freeres_fn .fini .rodata .gcc_except_table .eh_frame 
   01     .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got .got.plt .data .tm_clone_table __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs 
   02     .note.ABI-tag 
   03     
   04     .tdata .tbss 
   05     .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got 

很好。 tnx 给所有关心的人。你省了我的$$

【讨论】:

    猜你喜欢
    • 2015-10-24
    • 1970-01-01
    • 2018-06-27
    • 2019-07-18
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多