gcc - 如何在 NixOS 上生成静态可执行文件?

标签 gcc nixos

今天,我在使用 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)
无法产生静态 exec :
$> 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
有任何想法吗?
通常是“动态链接”程序hellogcc 生成没有问题。
Lubuntu 上没有这样的问题。有人建议我尝试不同的发行版并测试 exec 在 NixOS 上运行。我做到了 - 用 gcc 生成了一个 exec在 Lubuntu 上并在 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.*
$> 
这可能是原因吗?
更新2:关于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
有什么建议吗?

最佳答案

这里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 libs 复制到您的文件夹中并关闭 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 所有关心的人。你省了我的a$$

关于gcc - 如何在 NixOS 上生成静态可执行文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62065592/

相关文章:

c++ - 哈希符号 + 数字 "# 1"形式的 gcc 预处理输出行是什么意思?

c++ - 所有版本的 GCC 都在使用在定义中具有默认类型的模板

c - 结构数组

configuration - 为 Nix 配置 Iosevka

Linux 可执行文件在 patchelf 后不起作用

union 成员的编译错误 "has no member named"

c - 如何纠正 valgrind 错误?

linux - NixOS:启动到终端

haskell - 如何在本地 nix 构建中保持纯度

linux - 在 NixOS 上将 twitch lambdabot 配置为服务