28 jan 2011
as i’ve been experimenting with nix [1] (cross platform, cross distribution package manager) i hit a lot of issues in the automake based buildsystem. this post is about what motivated me to replace automake with cmake. it also coveres issues i had to solve. the nix-0.16-cmake project can be found at [2].
i’ve found quite many issues in the autotools build script of nix. i don’t know if they are specific to nix or to autotools. however: i don’t like autotools because:
they are very complex to maintain
complicated in usage, what parameters do what? you are literally ‘flooded’ by typing: ./configure –help
there are a million differnt versions of automake probably all are installed on my gentoo system! why?
all your directories get filled with these strange files: config.status, configure.ac, Makefile.am, Makefile.in, …
does autotools support “out of source” builds? never seen it yet.
in contrast cmake:
cmake has a very easy to lern syntax
i like the colored build system
some may say i might a bit biased towards cmake, so let’s consider nix-specific issues only:
prefix installation does not work (as normal user) if not passing –localstatedir=path/state this is not listed in any** docu,** nor ./configure –help update: (it is actually listed in the documentation, see section: Quick Start, point 1)
the build system does not warn, when not using –with-store-dir=/nix/store, that all software has to be recompiled it is listed in the documentation tough but this screwed some of my first builds
when using –with-store-dir=/nix/ it will chmod /nix/ to mode 1777 instead of adding /nix/store
running ./configure is slow
if you forget to run ./bootstrap.sh you still can build & install nix but it does not work properly
–with-store-dir= and –localstatedir= will always overwrite –prefix by default this implies they need to be always used in a ‘pure prefix’ installation
i might very likely hit some other issues but i don’t remember them. if this list is not enough for you, just read why the kde developers use cmake instead of autools/scons today.
NOTE: this is not a criticism about upstream (the nix developers). i do like their work very much. in case they do not want to use cmake, i’m fine with that. they can use my changelog to fix issues associated with the automake issues i pointed out.
one of the first things was to install nix 0.16 with autotools:
cd nix
rm -Rf nix-0.16
tar xf nix-0.16.tar
cd nix-0.16/
./bootstrap.sh
./configure –prefix=mPREFIX − − localstatedir=mPREFIX/state –with-store-dir=/nix/store
make
make install
i copied the shell output to a text file to have an idea what to do when. next i started from scratch with a top-level ‘CMakeLists.txt’.
as** cmake is hierarchical**, start small with an ever increasing directory coverage
make only small changes
start with a build environment, later create the installer and** finally do QA**
install into the same prefix, say /tmp/nix-prefix, move the fils apart and check both directories for differences
#!/bin/bash
DIRA=/tmp/nix-unified
DIRB=/tmp/nix-autotools
find $DIRA | sed "s%${DIRA}%%g" | sort > /tmp/fileA
find $DIRB | sed "s%${DIRB}%%g" | sort > /tmp/fileB
echo "files in both dirs are filtered by -3"
echo "--------------------------------------------"
echo "$DIRA"
echo " $DIRB"
echo "--------------------------------------------"
comm <(cat /tmp/fileA) <(cat /tmp/fileB) -3
i’ve also created scripts to automate various installation scenarios for automated testing.
automake/cmake supports RPATH build of binaries, see [3] that helps to make** binaries find their associated libraries** (libfoo.so) without having to alter the LD_LIBRARY_PATH. this way you can execute the program either while it is in your ‘out of source’ build directory (interesting for developers) or after you typed ‘make install’.
use DEFINES instead of CONFIGURE_FILE where possible especially to** pass the version number variable** from the CMakeLists.txt to your c/c++ code
DESTDIR builds, see [4]. this is a very nice feature for ‘downstream’ (distributions) to integrate software into their system
always check your variable names, i had a bug which cost me a few hours where a cmake variable was wrong: CMAKE_TR_PATH was CMAKE_TR_PATh this resulted in a silent fail. in c/c++ one would get a error of using an undefined variable, why not here?
when trying to add ‘broken’ symlinks (which won’t work as you passed the wrong directories) cmake tends to pass silently
when adding PERMISSIONS to a file, cmake might break when the file is not readable (anymore). i don’t know the cause for this, maybe a cmake issue. so instead of PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE better do: PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
the result of using the wrong PERMISSONS was:
CMake Error at scripts/cmake_install.cmake:40 (FILE): file INSTALL cannot set permissions on “/tmp/nix-cmake/bin/nix-collect-garbage” Call Stack (most recent call first): cmake_install.cmake:175 (INCLUDE)
CMAKE_INSTALL_RPATH must match your library-directory (where your libraries are)! i forgot to add the subdirectory once and the effect was that the binaries were not executable, moking about not finding libmain.
check that all scripts/program which should be executable are actually ‘installed’ as executable ls -la –color=auto helps a lot here
check file modes in general, use this: find . -name *.pl -exec ls -la –color=auto {} +
i’ve invested quite some time now and still the project isn’t finished. it’s usually very small issues as discussed in the pitfalls section already. since this is my first major cmake integration i expected this. see [5] for further details.