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

Gcc 如何在NixOS上生成静态可执行文件?,gcc,nixos,Gcc,Nixos,今天我在我的NixOS发行版上遇到了一个非常有趣的问题。我只是想创建一个静态编译的OCaml程序,但做不到。然后我尝试使用ANSI C标准玩具“hello world!”应用程序来实现这一点: $> cat mytest.c #include <stdio.h> int main () { puts ("hello world!") ; } 编译器: $> gcc -v Using built-in specs. COLLECT_GCC=/n

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

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

int
main ()
{
  puts ("hello world!") ;
}
编译器:

$> 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
有什么想法吗

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

卢本图没有此类问题。有人建议我尝试另一个发行版,并测试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.*
$> 
这是原因吗

更新2:关于ocamlopt:

源文件

$> cat mytest.ml
print_string "hello world!" ;;
print_newline () ;;
因为你看不到任何特殊的呼叫。让我们尝试使static exec:

$> 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系统

有什么建议吗?

这里解释了如何在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
  ] ;
}
不太好,但可能使用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 
哈斯克尔工作。原因是二进制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。您可以在nix shell中尝试保存我的$$

$nix shell-p glibc.static
。为GCC工作,但我不知道Ocaml.tnx-这对我帮助很大
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 
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