How to understand linking issues

Hello everyone!

I am trying to build cryptominisat-rs for a pet project of mine. I try to use this shell.nix

let
    pkgs = import <nixpkgs> {};
in
pkgs.mkShell {
  name = "cryptominisat-rs";
  propagatedBuildInputs = with pkgs; [
    gmp
    zlib
    boost
    python3
    rustup
    cargo-make
    cargo
    which gccStdenv
    cmake xxd
    pkg-config
  ];
  src = null;
  shellHook = with pkgs; ''
    export LD_LIBRARY_PATH=${boost.out}/lib:${openssl.out}/lib:${gmp}/lib:${zlib}/lib:${ncurses}/lib
  '';
}

as you might guess, I just added packages the more desperate I became, since the error just never really changed:

 Compiling cryptominisat v5.6.6 (/home/munin/Documents/rust/cryptominisat-rs)
error: failed to run custom build command for `cryptominisat v5.6.6 (/home/munin/Documents/rust/cryptominisat-rs)`

Caused by:
  process didn't exit successfully: `/home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-a38ea13b46b7e179/build-script-build` (exit code: 101)
  --- stdout
  running: "cmake" "/home/munin/Documents/rust/cryptominisat-rs/cryptominisat" "-DCMAKE_BUILD_TYPE=Release" "-DSTATICCOMPILE=ON" "-DENABLE_PYTHON_INTERFACE=OFF" "-DONLY_SIMPLE=ON" "-DNOZLIB=ON" "-DNOM4RI=ON" "-DSTATS=OFF" "-DNOVALGRIND=ON" "-DENABLE_TESTING=OFF" "-DCMAKE_INSTALL_PREFIX=/home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out" "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_C_COMPILER=/nix/store/q289knj5k3j6mgbqq40ajgvlqnd46mi8-gcc-wrapper-9.3.0/bin/gcc" "-DCMAKE_CXX_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_CXX_COMPILER=/nix/store/q289knj5k3j6mgbqq40ajgvlqnd46mi8-gcc-wrapper-9.3.0/bin/g++" "-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_ASM_COMPILER=/nix/store/q289knj5k3j6mgbqq40ajgvlqnd46mi8-gcc-wrapper-9.3.0/bin/gcc"
  -- LIB directory is 'lib'
  -- BIN directory is 'bin'
  -- Doing a Release build
  -- build type is Release
  -- Compiling for static library use
  -- GIT hash found: 
  -- PROJECT_VERSION: 5.6.8
  -- PROJECT_VERSION_MAJOR: 5
  -- PROJECT_VERSION_MINOR: 6
  -- PROJECT_VERSION_PATCH: 8
  -- Not compiling detailed statistics. The system is faster without them
  -- Cannot find help2man, not creating manpage
  -- All defines at startup:  -DNDEBUG -D_FORTIFY_SOURCE=0
  -- In case your Python interpreter is not found, or a wrong one is found, please set it with '-DPYTHON_EXECUTABLE:FILEPATH=your path here'
  -- Python 3 -- PYTHON_EXECUTABLE=/nix/store/0yhk4sk4x9s9hsrf3p1skbfy1pwd1rbf-python3-3.8.5/bin/python
  -- Python 3 -- PYTHON_LIBRARIES=/nix/store/0yhk4sk4x9s9hsrf3p1skbfy1pwd1rbf-python3-3.8.5/lib/libpython3.8.so
  -- Python 3 -- PYTHON_INCLUDE_DIRS=/nix/store/0yhk4sk4x9s9hsrf3p1skbfy1pwd1rbf-python3-3.8.5/include/python3.8
  -- Python 3 -- PYTHONLIBS_VERSION_STRING=3.8.5
  -- Only building executable with few command-line options because the boost program_options library were not available
  -- Performing Test HAVE_FLAG_-Wformat=2
  -- Performing Test HAVE_FLAG_-Wformat=2 - Failed
  -- Configuring done
  -- Generating done
  -- Build files have been written to: /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build
  running: "cmake" "--build" "." "--target" "install" "--config" "Release" "--"
  Copying cryptominisat_c.h to /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build/include/cryptominisat5
  [ 93%] Built target cryptominisat5
  Copying cryptominisat.h to /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build/include/cryptominisat5
  [ 95%] Linking CXX executable ../cryptominisat5_simple
  Copying solvertypesmini.h to /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build/include/cryptominisat5
  Copying dimacsparser.h to /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build/include/cryptominisat5
  Copying streambuffer.h to /home/munin/Documents/rust/cryptominisat-rs/target/release/build/cryptominisat-605884bbc1bc72de/out/build/include/cryptominisat5
  [ 95%] Built target CopyPublicHeaders

  --- stderr
  CMake Warning at CMakeLists.txt:753 (message):
    Testing is disabled


  /nix/store/10nmk0mlhy9nf3lfrq8q07k0510bgnnf-binutils-2.31.1/bin/ld: cannot find -ldl
  /nix/store/10nmk0mlhy9nf3lfrq8q07k0510bgnnf-binutils-2.31.1/bin/ld: cannot find -lpthread
  /nix/store/10nmk0mlhy9nf3lfrq8q07k0510bgnnf-binutils-2.31.1/bin/ld: cannot find -lm
  /nix/store/10nmk0mlhy9nf3lfrq8q07k0510bgnnf-binutils-2.31.1/bin/ld: cannot find -lpthread
  /nix/store/10nmk0mlhy9nf3lfrq8q07k0510bgnnf-binutils-2.31.1/bin/ld: cannot find -lc
  collect2: error: ld returned 1 exit status
  make[2]: *** [cmsat5-src/CMakeFiles/cryptominisat5_simple-bin.dir/build.make:119: cryptominisat5_simple] Error 1
  make[1]: *** [CMakeFiles/Makefile2:199: cmsat5-src/CMakeFiles/cryptominisat5_simple-bin.dir/all] Error 2
  make[1]: *** Waiting for unfinished jobs....
  make: *** [Makefile:149: all] Error 2
  thread 'main' panicked at '
  command did not execute successfully, got: exit code: 2

  build script failed, must exit now', /home/munin/.cargo/registry/src/github.com-1ecc6299db9ec823/cmake-0.1.45/src/lib.rs:894:5
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

So the issue seemingly is, something is not linked correctly, and I dont have any idea what I could do to debug, fix or work-around with. However, the offending cryptominisat can be compiled just fine in a shell such as nix-shell -p gcc boost zlib python3 cmake pkg-config.

Any tips on how to learn to fix such issues?

I’m afraid I can’t say much about rust packaging, but maybe there still a couple of points that can help you:

  • Try to avoid LD_LIBRARY_PATH most of the time. Ideally library searching in nixpkgs works by encoding RUNPATHs in the binaries. If you need to use LD_LIBRARY_PATH this most often means that there is something wrong with the RUNPATH encoding. What often really is the variable you want to set is LIBRARY_PATH, which the build-time linker is meant to search. (In your case you will most likely not have to set anything manually but rely on these variables automatically being set by making your tools part of the correct *buildInputs* list.)
  • It’s usually a good idea to package each library individually. In this case I guess that it will probably make sense to write a separate stdenv.mkDerivation for cryptominisat itself and then use that in the buildInputs of your cryptominisat-rs (Something like let cryptominisat = pkgs.stdenv.mkDerivation {...}; in pkgs.rustPlatform.buildRustPackage { buildInputs = [ cryptominisat ]; })
  • Not everything belongs in propagatedBuildInputs You can read up in NixOS - Nixpkgs 21.05 manual about this. From quickly looking over it gmp zlib boost are most likely runtime deps of cryptominisat so they probably belong in the buildInputs (will populate CMAKE_PREFIX_PATH and LIBRARY_PATH and similar) of cryptominisat, cmake, pkg-config are most likely nativeBuildInputs (will populate PATH) of cryptominisat. The deps rustup, cargo-make are most likely nativeBuildInputs of your wrapper cryptominisat-rs.
  • Most of the time you won’t need mkShell. Instead you should try to write your nix code in a way so that a nix-build will successfully work and then you will get the nix-shell environment for free.
  • I have never packaged a rust program, so I cannot say much about it, but I imagine that following NixOS - Nixpkgs 21.05 manual would work

I added a WIP PR to point you in the right direction: WIP: Nixify project by knedlsepp · Pull Request #5 · Storyyeller/cryptominisat-rs · GitHub

Edit: I just realized it’s not your project. So the PR there is not a good idea. You will most likely want something similar in your project, but instead of specifying src = builtins.fetchGit ./.; you’ll want to fetch the src for cryptominisat-rs from Github.

2 Likes

I’m not entirely sure, but most rust projects use pkg-config to locate dependencies. I guess you can use cmake’s findPkgConfig module to find them.

However, after poking around, I’m going to assume that the cmake crate isn’t compatible with nix for some reason.

Another possibility is that you have a static build, but there’s only dynamic librarires available in your NIX_LDFLAGS

Thank you all for your replies and helpful comments!

However, after 2 hours today, and 2 hours yesterday, I’ll just give up.
After 2 years of NixOS, my knowledge of nix is not enough for writing a relatively simple derivation, and the frustration is just too high. The documentation is insanely hard to find, all examples I could find are outdated and the error messages just get worse and worse.

1 Like

I don’t have any pragmatic advice to offer. (I very recently had to abort an attempt to improve my Nix-Rust process, precisely because of frustration, lack of time and an exponential explosion of (to me) unfathomable errors. When your original post appeared I was tempted to dig into it, but I just couldn’t muster the time or energy.)

So I offer you my sympathy.

Part of the problem is that the challenges that Nix takes on are insanely difficult. But this shouldn’t blind us to the fact that the documentation and user-friendliness could be much, much better.

There is so much to document, and it’s very difficult to do it well, especially in a way that makes solutions to challenges easily discoverable; but that shouldn’t make us insensitive to the need.

Posts like yours make me very sad because I think that Nix brings some vitally important ideas to the table, and yet too many people are being put off by such experiences, and thus the spread of these crucial ideas is being stifled.

But I also want to express my gratitude to all the experts who roam these forums offering much wisdom and patience. It’s a great shame that all their sterling effort is but a drop in the ocean of pain.

2 Likes

Unlike pkg-config, the cmake crate currently does not support using installed libraries. I opened an issue about it

In the meanwhile, I would use the following patch on cryptominisat-rs’s build.rs to use cryptominisat built by Nix:

--- a/build.rs
+++ b/build.rs
@@ -11,20 +11,8 @@ extern crate cmake;
 use cmake::Config;
 
 fn main() {
-  let dst = Config::new("cryptominisat")
-                   .define("CMAKE_BUILD_TYPE", "Release")
-                   .define("STATICCOMPILE", "ON")
-                   .define("ENABLE_PYTHON_INTERFACE", "OFF")
-                   .define("ONLY_SIMPLE", "ON")
-                   .define("NOZLIB", "ON")
-                   .define("NOM4RI", "ON")
-                   .define("STATS", "OFF")
-                   .define("NOVALGRIND", "ON")
-                   .define("ENABLE_TESTING", "OFF")
-                   .build();
   //println!("cargo:rustc-flags=-L {}/lib", dst.display());
-  println!("cargo:rustc-link-search=native={}/lib", dst.display());
-  println!("cargo:rustc-link-lib=static=cryptominisat5");
+  println!("cargo:rustc-link-lib=dylib=cryptominisat5");
   
   #[cfg(target_os = "macos")]
   println!("cargo:rustc-flags=-l dylib=c++");
let
  pkgs = import <nixpkgs> {};
  cryptominisat = pkgs.stdenv.mkDerivation {
    name = "cryptominisat";
    src = ./cryptominisat;
    nativeBuildInputs = with pkgs; [
      cmake
      pkg-config
    ];
    buildInputs = with pkgs; [
      gmp
      zlib
      boost
      python3
      m4ri
    ];
  };
in
pkgs.mkShell {
  src = builtins.fetchGit ./.;
  buildInputs = with pkgs; [
    cryptominisat
  ];
  nativeBuildInputs = with pkgs; [
    rustc
    cargo
  ];
}