z3bra, the stripes apart

shred config.h

— 27 August, 2014

As an accomplished Linux user, you have, at some point, had to deal with softwares that are configured at compilation time.

If you never ran into those kind of programs, don't worry, you will one day. The problem is that configuring this kind of software can be really frustrating, so I'll show you a way to make these a bit more bearable.

Some background

Since the beginning, many programs running on Linux have been written in C. C is a low-level programming language, which means that the machine can almost understand it. For the machine to run the program, you have to translate the source code into an executable binary file: This is called "Compilation".

The compilation is irreversible, so you can't modify a program once it's compiled. It means that if you want to change the configuration of a software, you have two possibilities:

Most of the time, softwares include an external configuration (like ~/.bashrc) to enable on-the-fly configuration. change config file, restart software, and you're done.
But in some special cases, such a file can't be used for configuration. the reason behind that is: speed, simplicity, stability and reliability.

How does it work ?

In order to make things easier for the user, the developpers (usually) create a file named config.h where the configuration happens. You don't need programming knowledge to edit it.

I like those programs, even though it can be a pain to handle sometimes. The typical approach with these is the following:

─── cd ~/src/c/program
─── cp config.def.h config.h
─── vim config.h
─── make
CC program.c
LD program
─── ./program

And you repeat these tasks until you get the behavior you want. It does not seem hard to do. But on the long term, it can be painful... Also, if you maintain some packages, it's even harder, because you always have to switch between your own file, and the default one. Because you use your version, but you package the software with the default values. So you keep doing this all the time (on Archlinux for example) :

─── cp src/<pkgname>/config.def.h z3bra.h
─── vim z3bra.h
─── cp z3bra.h config.h
─── makepkg -si
─── vim PKGBUILD
─── cp src/<pkgname>/config.def.h config.h
─── makepkg -S

This. Over and over. You replace your config with the default one, send the package, recompile the package for you... sigh It's really boring !

Deal with it

First of all, I had to find an easy way to recompile and reinstall the software on my computer. I use source-based distributions on my computers (Archlinux, Crux, Alpine Linux), so it was not really hard. All I had to do was to create a port for the said software, and include my own files in the building process. For example, here is the typical PKGBUILD I use:

arch=('i686' 'x86_64')
source=("$pkgname::git+<gitsource>" 'config.h')
md5sums=('SKIP' 'SKIP')

build() {
    cp config.h $pkgname/config.h
    cd $pkgname
package() {
    cd $pkgname
    make DESTDIR=$pkgdir install

Now my file will be copied over before compilation, so all I have to do now is makepkg -fi, and the sources will be updated, compiled and installed.

The compilation/installation part being set up

The first problem I had is that you need to keep the sources on your computer, or at least the config.h of all the software you use. For this, I created a special directory in my $HOME to hold all the different versions of those files:

─── tree ~/.hm.d
├── 2bwm
│   ├── config.def.h
│   └── z3bra.h
└── tmenu
    ├── bright.h
    ├── config.def.h
    └── dark.h

2 directories, 5 files

Each directory is related to a software, and each file a specific configuration. Now, I can keep track of all my config files, and they are all in the same place.

PROTIP: you can even version your ~/.hm.d directory, to keep track of the changes you make !

I then wrote a small script: hm (for "Header Manager") to automate the process of saving/restoring configurations.

It will browse the ~/.hm.d directory for specific config files, or the default ones and replace them in the current folder, automating the config replacement. Now my workflow is the following:

─── cd ~/usr/ports/<pkgname>
─── vim ~/.hm.d/<pkgname>/$USER.h   # edit personnal config
─── hm -r <pkgname>/$USER.h         # restore user's file
─── makepkg -fi                     # build package for me
─── hm -r <pkgname>                 # restore default config
─── makepkg -S                      # create package for the community

As the process is always the same, one could create a wrapper script to automate all this even more, but I just don't bother.

And now you don't want to kill yourself anymore when dealing with these kind of software ;)
I hope this trick will help somebody. If not, thanks for reading it anyway !