Cannot find X11/Xlib.h when compiling a custom package

I’m trying to install a custom package ds9.

I wrote following nix file:

let
  pkgs = import <nixpkgs> {};
  mkDerivation = import ./autotools.nix pkgs;
in mkDerivation rec {
  name = "ds9.7.6";
  buildInputs = with pkgs; [xorg.libX11 xorg.libX11.dev openssl gnutar binutils-unwrapped busybox gnumake gcc];
  src = ./ds9.7.6.tar.gz;
}

along with the autotools.nex copied from nix-pills and the builder.sh:

set -e
unset PATH

for p in $buildInputs; do
    export PATH=$p/bin${PATH:+:}$PATH
done

tar xvzf $src

cd SAOImageDS9
unix/configure
CC=gcc make

```,

(in this file I only stoped after make, for the make install is not available and need more operations).

though I have included xorg.libX11.dev in the buildInput set, the make still complained that:

fatal error: X11/Xlib.h: No such file or directory


So could anyone tell me how to tell the gcc where to find extra headers?

Thanks.

Is there a reason why you don’t use stdenv.mkDerivation? It does lots of magic.

Thank you for your reply and I found it seems to be my fault. I updated my nix file and this error disappeared. However, it still cannot be compiled, because in the configure it assumed the openssl file to exist in some hardcoded position, i.e., /usr/…

Anyway I downloaded the binary and solved the shared lib problem, and it can run now.

Thank you again.

Sorry I return to this problem again.

I try to fight with problem again. I still cannot make find the header files.
followings are my defaults.nix and builder.sh:

let
  pkgs = import <nixpkgs> {};
  stdenv = pkgs.stdenv;
  fetchurl = pkgs.fetchurl;
  in
pkgs.stdenv.mkDerivation {
    name="ds9";
    src = ./ds9.7.6.tar.gz;
    libPath = stdenv.lib.makeLibraryPath (with pkgs; [ stdenv.cc.cc xorg.libX11 xorg.libX11.dev xorg.libX11.dev.out  openssl fontconfig xorg.libXft libxml2 xorg.libXScrnSaver]);
    builder=./builder.sh;
}

and builder.sh:

source $stdenv/setup
mkdir -p $out/bin
echo "unpacking $src..."
tar xzvf $src
cd SAOImageDS9
unix/configure
CC=gcc make

This time I use the stdenv.mkDerivation, and try to use nix-build to build it. The header still cannot be found

The error message is

/build/SAOImageDS9/tk8.6/unix/../generic/tk.h:96:13: fatal error: X11/Xlib.h: No such file or directory

The source file is downloaded from:
http://ds9.si.edu/download/source/ds9.7.6.tar.gz

Could any give me some hints? I guess I missed something about how to assign the include path.

Thanks.

“hints” are a lot more complicated if you don’t use the common tools :wink:
By setting the option builder, you’re throwing away all of the nice goodies that nixpkgs gives you.
I suggest you have a look at the nixpkgs manual: Nixpkgs 23.11 manual | Nix & NixOS

I suggest you also have a look at https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/hello/default.nix to get an idea of how an “ideal” build looks like.
Admittedly, programs with more complex build systems need additional arguments. And DS9 and the included dependencies seems to be a pretty bad one.

Here’s a partial work in progress, where I’ve managed to compile a lot, but it’s not completed yet:

{ stdenv, fetchurl,
  xorg,  openssl, fontconfig, libxml2, libxslt, perl,
  gnumake, pkgconfig, autoconf,
 } :
stdenv.mkDerivation rec {
  version = "9.7.6";
  name = "ds9-${version}";
  src = ./ds9.7.6.tar.gz;
  buildInputs = [ autoconf pkgconfig gnumake xorg.libX11 xorg.libX11.dev xorg.libX11.dev.out openssl openssl.dev fontconfig xorg.libXft libxml2.dev libxml2 xorg.libXScrnSaver libxslt perl ];
  preConfigurePhases = [ "preconfigure" ];
  preconfigure = ''
    patchShebangs .
  '';
  configureScript = "unix/configure";
  hardeningDisable = [ "all" ];
  # Work around broken configure scripts by setting some environment variables to the exact paths...
  with_ssldir = openssl.dev;
  # especially tclxml should be ashamed...
  with_xml2_config = "${libxml2.dev}/bin/xml2-config";
  with_xslt_config = "${libxslt.dev}/bin/xslt-config";
}

Options are transformed into environment variables. I’m using that to set some variables that various broken configure scripts use to find things in fixed paths.

To build it, you can run the following command:

nix-build -E 'with import <nixpkgs> {}; callPackage ./default.nix {}'
2 Likes

And here’s a version that finishes to build. I’ve got no idea if the application is actually working.

{ stdenv, fetchurl,
  xorg,  openssl, fontconfig, libxml2, libxslt, perl,
  gnumake, pkgconfig, autoconf, gnused, tcl, zip
 } :
stdenv.mkDerivation rec {
  version = "9.7.6";
  name = "ds9-${version}";
  src = ./ds9.7.6.tar.gz;
  buildInputs = [ zip tcl gnused autoconf pkgconfig gnumake xorg.libX11 xorg.libX11.dev xorg.libX11.dev.out openssl openssl.dev fontconfig xorg.libXft libxml2.dev libxml2 xorg.libXScrnSaver libxslt perl ];
  preConfigurePhases = [ "preconfigure" ];
  preconfigure = ''
    patchShebangs .
    sed -i -e 's_I/usr/include/libxml2_I${libxml2.dev}/include/libxml2_g' tksao/configure
  '';
  installPhase = ''
    mkdir -p $out/bin
    cp bin/ds9 $out/bin/ds9
  '';
  configureScript = "unix/configure";
  hardeningDisable = [ "all" ];
  # Work around broken configure scripts by setting some environment variables to the exact paths...
  with_ssldir = openssl.dev;
  # especially tclxml should be ashamed...
  with_xml2_config = "${libxml2.dev}/bin/xml2-config";
  with_xslt_config = "${libxslt.dev}/bin/xslt-config";
}
4 Likes

@astrojhgu did you test the application? Is it working?

Hi, @tokudan, and thank you for your help.

Yes, I tested. It can compile, but when running the ds9 command, it complains

application-specific initialization failed: Can't find a usable init.tcl in the following directories: 
    ./zvfsmntpt/tcl8.6 /build/SAOImageDS9/lib/tcl8.6 /home/astrojhgu/ds91/result/lib/tcl8.6 /home/astrojhgu/ds91/lib/tcl8.6 /home/astrojhgu/ds91/result/library /home/astrojhgu/ds91/library /home/astrojhgu/ds91/tcl8.6.8/library /home/astrojhgu/tcl8.6.8/library



This probably means that Tcl wasn't installed properly.

Error in startup script: couldn't read file "./zvfsmntpt/library/ds9.tcl": no such file or directory

I tried to findout the reason, but no progress yet.

However, I find that if I run the building in a nix-shell:

nix-shell -E 'with import <nixpkgs> {}; callPackage ./default.nix {}' --verbose 

and run the obtained ds9 executive file in the SAOImageDS9/bin/, it runs successfully.

That sounds like the application needs some wrappers to change it’s path or other dirty tricks to work around issues in the build process.
I’m only using the following two commands as “make install” complains that there is no rule to make install.

  installPhase = ''
    mkdir -p $out/bin
    cp bin/ds9 $out/bin/ds9
  '';

It’s quite possible that something else needs to be done, but it wasn’t obvious to me.

Thanks, I will try to dig deeper later when I have time, and if I get any progress, I will post them here.

There are several problems with this program. It needs some bundled files installed in a relative nonstandard location. The following expression installs the program. Due to the hardcoded nonstandard relative path, the program works only when called from the package prefix. So I wrote a simple wrapper that changes to the store prefix and passes the arguments to the program there. If you need NixOS for astronomy, this works.

with import <nixpkgs> {};

stdenv.mkDerivation rec {
  version = "8.0.1";
  name = "ds9-${version}";
  src = ./ds9.8.0.1.tar.gz;
  buildInputs = [ zip tcl gnused autoconf pkgconfig gnumake xorg.libX11 xorg.libX11.dev xorg.libX11.dev.out openssl_1_0_2 openssl_1_0_2.dev fontconfig xorg.libXft libxml2.dev libxml2 xorg.libXScrnSaver libxslt perl ];
  preConfigurePhases = [ "preconfigure" ];
  preconfigure = ''
    patchShebangs .
    sed -i -e 's_I/usr/include/libxml2_I${libxml2.dev}/include/libxml2_g' tksao/configure
  '';
  # Right now we use the bundled libraries. DS9 is not security critical and is reliable as is, so it 's ok
  # However, it does clutter your profile with that last dir.
  
  # Install wrapper script:
  ds9 = 
    ''
       #!/usr/bin/env bash
       declare -a ARGS
       COUNT=$#
       for ((INDEX=0; INDEX<COUNT; ++INDEX))
       do
         ARG="$(realpath $(printf "%q" "$1"))"
         ARGS[INDEX]="$(printf "%q" "$ARG")"
       shift
       done
       $(cd @out@; ds9_bin $ARGS)
     '';
  passAsFile = [ "ds9" ];

  installPhase = ''
    mkdir -p $out/bin
    cp -r bin/ $out/
    mv $out/bin/ds9 $out/bin/ds9_bin
    mkdir -p $out/lib
    cp -r lib/ $out/
    cp -r ds9/unix/zvfsmntpt $out/
    cp "$ds9Path" $out/bin/ds9
    chmod +x $out/bin/ds9
    substituteAll $ds9Path $out/bin/ds9
  '';

  configureScript = "unix/configure";
  hardeningDisable = [ "all" ];
  # Work around broken configure scripts by setting some environment variables to the exact paths...
  with_ssldir = openssl_1_0_2.dev;
  # especially tclxml should be ashamed...
  with_xml2_config = "${libxml2.dev}/bin/xml2-config";
  with_xslt_config = "${libxslt.dev}/bin/xslt-config";
}

Thanks for the reply.

I have now solved this problem and made ds9 to run on my nixos.

Here is my default.nix

{ fetchzip
, xorg
, gcc
, fontconfig
,libxml2
, stdenv
, lib
}:

let

  libPath = lib.makeLibraryPath [
  xorg.libX11.out
  xorg.libXScrnSaver
  xorg.libXft.out
  (lib.getLib gcc.cc)
  fontconfig.lib
  libxml2.out
  ];
in

stdenv.mkDerivation {
  name = "ds9";

  src = fetchzip {
    url = "http://ds9.si.edu/download/ubuntu18/ds9.ubuntu18.8.2.1.tar.gz";
    sha256 = "1yhq07xrcjk2fpxkhvdqg80cf35a106cmdpj2ixym8vwamissm65";
  };

  phases = [ "unpackPhase" "installPhase" "fixupPhase" ];

  buildInputs = [
    xorg.libX11.out
    xorg.libXScrnSaver
    xorg.libXft.out
    (lib.getLib gcc.cc)
    fontconfig.lib
    libxml2.out
  ];

  installPhase = ''
    mkdir -p $out/bin
    cp -p * $out/bin
  '';

  fixupPhase = ''
    chmod 755 $out/bin/ds9
    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
      --set-rpath ${libPath}   $out/bin/ds9
  '';
}