2022.05.29
静态链接,以qemu为例
太长不看
- 实现了qemu静态链接,无任何动态链接库的依赖。 采用了两个版本的qemu,当前版本Nix的qemu(nix 21.11, qemu 6.1.1) 和qemu3.1.0这两个版本。
- nix脚本:pkgs_qemu_static.nix
pkgsStatic及其源代码
Nixpkgs含有pkgsStatic软件包,但是大多软件无法直接使用。 需要进行手动修复。
pkgsStatic加载过程的源码
-
pkgs/top-level/stage.nix 将crossSystem设置为static且abi为musl。 之所以用Musl是因为,
Currently uses Musl on Linux (couldn’t get static glibc to work).
其代码大致的如下,
pkgsStatic = nixpkgsFun { crossSystem = { isStatic = true; parsed = stdenv.hostPlatform.parsed // { abi = musl; };};};
- nixpkgsFun = newArgs: import pkgs/top-level/default.nix (...)
- pkgs/top-level/default.nix: stdenvStages {..., crossSystem, ...}
- pkgs/stdenv/default.nix: stagesCross
- pkgs/stdenv/cross/default.nix: stdenvAdapters.makeStatic
- pkgs/stdenv/adapters.nix: makeStatic
- makeStaticLibraries
- 添加configureFlags "--enable-static" "--disable-shared"
- 添加cmakeFlags "-DBUILD_SHARED_LIBS:BOOL=OFF"
- 添加mesonFlags "-Ddefault_library=static"
- makeStaticBinaries
- 添加NIX_CFLAGS_LINK "-static"
- 添加configureFlags "--disable-shared"
- makeStaticLibraries
- pkgs/stdenv/adapters.nix: makeStatic
- pkgs/stdenv/cross/default.nix: stdenvAdapters.makeStatic
- pkgs/stdenv/default.nix: stagesCross
- pkgs/top-level/default.nix: stdenvStages {..., crossSystem, ...}
- nixpkgsFun = newArgs: import pkgs/top-level/default.nix (...)
TODO: 读懂makeStaticLibraries和makeStaticBinaries。
基本思路
对于当前版本的qemu,使用pkgsStatic.qemu ,挨个修复编译报错即可。
对于历史版本的qemu,以3.1.0为例,编译方式已和现在有区别, 比如之前完全是configure, make,而现在引入了meson。 初步设想两种方案,
- 嫁接老版本nixpkgs到当前版本 将qemu-3.1.0对应的nixpkgs嫁接到当前的nixpkgs
- 改造新版本nixpkgs以适应老版本 通过overlay,override方法修改当前nixpkgs的qemu的nix表达式
我采用的第一种办法,将老版本nixpkgs嫁接到当前版本nixpkgs。 使用lazamar.co.uk/nix-versions 查询支持qemu-3.1.0的nixpkgs版本。 引入qemu-3.1.0的示例代码如下,详细见pkgs_qemu_static.nix
# get old nixpkgs which contains qemu-3.1.0
oldNixpkgsSrc = builtins.fetchTarball {...}
qemu31 = pkgs.callPackage (
oldNixpkgsSrc + "/pkgs/applications/virtualization/qemu/default.nix"
) {...}
然后挨个修复编译报错即可。
调试手段
还原构建环境
# 保留构建失败的现场
nix-build pkgs_qemu_static.nix -K
进入现场包含env-vars文件和失败时的源码文件夹。 恢复环境,
. ./env-vars
. $stdenv/setup
查看依赖树
nix-store --query --tree <xxx.drv>
结果
目前仅需要命令行的qemu,因此为了省事, 我去掉了声音和图像支持。
注:在NixOS 21.11上和在ubuntu 22配合nix上编译出来的qemu二进制文件一模一样。
xieby1@yoga14s:~ $ pkgs_qemu_static.nix /nix/store/gs6plgyc0jr9i5qams0ifksijnq9hkq2-qemu-static-x86_64-unknown-linux-musl-6.1.1 /nix/store/lm9kl1nm7bs4hy6l4qng03k4srx1x28n-qemu-3.1.0-x86_64-unknown-linux-musl xieby1@yoga14s:~ $ ldd result/bin/qemu-system-x86_64 not a dynamic executable xieby1@yoga14s:~ $ result/bin/qemu-system-x86_64 --version QEMU emulator version 6.1.1 Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers xieby1@yoga14s:~ $ ldd result-2/bin/qemu-system-x86_64 not a dynamic executable xieby1@yoga14s:~ $ result-2/bin/qemu-system-x86_64 --version QEMU emulator version 3.1.0 Copyright (c) 2003-2018 Fabrice Bellard and the QEMU Project developers