打包求助:如何在目标应用中成功调用ld?

背景

我正在开发一些关于Scheme语言的开源项目,需要使用chez-exe将代码打包为可执行文件。我本人自己修改的库在这里
,修改有两点:

  1. 合并了chez-exe原库没有合并的更新,这些更新是针对chez scheme10.0.0的;
  2. chez-exe原库pull request提供了一个版本的flaks.nix,这是针对chez scheme<10.0.0版本的,我做了针对性的修改。

问题

/nix/store/7v7g86ml0ri171gfcrs1d442px5bi1p3-binutils-2.41/bin/ld: 找不到 -luuid: No such file or directory
/nix/store/7v7g86ml0ri171gfcrs1d442px5bi1p3-binutils-2.41/bin/ld: 找不到 -ltinfo: No such file or directory
collect2: 错误:ld 返回 1

分析

我认为原因在于chez-exe通过调用shell命令的方式调用来ld命令,而我使用的chez-exe打包无法正确暴露LD_LIBRARY_PATH。在附录中,你可以看到我试图构建一个虚拟环境,在LD_LIBRARY_PATH中设定ld的目标包地址,可惜不行。

我甚至尝试直接在bash中

export LD_LIBRARY_PATH = ...

也不行

我正在尝试nix-ld

附录

我之前参考中文互联网写的(错误的)打包文件如下:

{
  inputs = {
    utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, utils, ... }:
    utils.lib.eachDefaultSystem (
      system: let
        pkgs = nixpkgs.legacyPackages.${system};
        bootpath = if system == "x86_64-darwin"
          then "${pkgs.chez}/lib/csv${pkgs.chez.version}/ta6osx"
          else "${pkgs.chez}/lib/csv${pkgs.chez.version}/ta6le";
        platformSpecificInputs = if system == "x86_64-darwin"
          then [ pkgs.darwin.libiconv ]
          else [ pkgs.libuuid ];
        writeShellScript = pkgs.writeShellScript;
        lib = pkgs.lib;
        libPath = lib.makeLibraryPath ([pkgs.ncurses5 pkgs.ncurses6] ++ platformSpecificInputs);
        execPath = lib.makeBinPath ([ pkgs.libtool ]);
        bubblewrap = pkgs.bubblewrap;
        pre-chez-exe = pkgs.stdenv.mkDerivation {
          name = "chez-exe";
          version = "0.0.1";
          src = ./.;

          buildInputs = with pkgs; [
            chez
            ncurses5
            ncurses6
          ] ++ platformSpecificInputs;

          buildPhase = ''
            mkdir -p $out/{bin,lib}
            scheme --script gen-config.ss \
            --prefix $out \
            --bindir $out/bin \
            --libdir $out/lib \
            --bootpath ${bootpath} \
            --scheme scheme
          '';
        };
        #   export LD_LIBRARY_PATH="${libpath}:''${LD_LIBRARY_PATH}"
        #   ${pre-chez-exe}/bin/compile-chez-program "$@"
        # '';
        # startScript = writeShellScript "SVPManager" ''
        startScript = writeShellScript "compile-chez-program" ''
          # 除了这些路径以外,其它的根目录下的路径都映射进虚拟环境
          # 这里的有些路径不是完全不映射,而是在下面有更细粒度的映射配置
          blacklist=(/nix /dev /usr /lib /lib64 /proc)

          declare -a auto_mounts
          # loop through all directories in the root
          for dir in /*; do
            # if it is a directory and it is not in the blacklist
            if [[ -d "$dir" ]] && [[ ! "''${blacklist[@]}" =~ "$dir" ]]; then
              # add it to the mount list
              auto_mounts+=(--bind "$dir" "$dir")
            fi
          done

          # Bubblewrap 启动脚本
          cmd=(
            ${bubblewrap}/bin/bwrap
            # /dev 需要特殊的映射方式
            --dev-bind /dev /dev
            # 在虚拟环境中也切换到当前文件夹
            --chdir "$(pwd)"
            # Bubblewrap 退出时杀掉虚拟环境里的所有进程
            --die-with-parent
            # /nix 目录只读
            --ro-bind /nix /nix
            # /proc 需要特殊的映射方式
            --proc /proc
            # 配置环境变量,包括查找命令和库的路径
            --setenv PATH "${execPath}:''${PATH}"
            --setenv LD_LIBRARY_PATH "${libPath}:''${LD_LIBRARY_PATH}"
            # 映射其它根目录下的路径
            "''${auto_mounts[@]}"
            # 虚拟环境启动后运行主程序
            ${pre-chez-exe}/bin/compile-chez-program "$@"
          )
          exec "''${cmd[@]}"
        '';
      in {
        packages.default = pkgs.stdenv.mkDerivation {
            pname = "chez-exe";
            inherit (pre-chez-exe) version;
            phases = [ "installPhase" ];
            installPhase = ''
                mkdir -p $out/bin
                ln -s ${startScript} $out/bin/compile-chez-program
        '';
        };
      }
    );
}

请各位指点,谢谢。

1 Like

有点巧合,我 1 月份的时候有试过给你的 language server 打包,不过后面没继续折腾,既然正主来了,晚上有空我再瞅瞅~

话外:我其实也不是很懂 scheme 的包要咋打,建议参考置顶贴加咱们 TG 群组聊下,里面大佬多。

哈哈哈,我就是看你的材料入门的。
In addition:
让我先看看怎么在nixos上翻墙+telegram……

1 Like

我已经成功打包chez-exe,并且提交到上游。
其实问题完全在于上面的flake.nix文件:
谁能想到LD_LIBRARY_PATH居然不是ld寻找库的地址,而LIBRARY_PATH是目标地址呢?
我的改变只有一个:

            --setenv LD_LIBRARY_PATH "${libPath}:''${LD_LIBRARY_PATH}"

改成

            --setenv LIBRARY_PATH "${libPath}:''${LIBRARY_PATH}"
1 Like