Sunday, December 20, 2015

Dynamic PATH in GNU Make

Sometimes you may have several targets, where the 1st one creates a new directory, puts some files in it & the 2nd target expects newly created directory to be added to PATH. For example:

$ make -v | head -1
GNU Make 4.0

$ cat
PATH := toolchain:$(PATH)

src/.configure: | toolchain src
        cd src && ./
        touch $@

        mkdir $@
        printf "#!/bin/sh\necho foo" > $@/
        chmod +x $@/

        mkdir $@
        cp $@

toolchain target here creates the directory w/ new executables. src target emulates unpacking a tarball w/ script in it that runs, expecting it to be in PATH:

$ cat

echo PATH: $PATH

If we run this example, will unfortunately fail:

$ make -f 2>&1 | cut -c -72
mkdir toolchain
printf "#!/bin/sh\necho foo" > toolchain/
chmod +x toolchain/
mkdir src
cp src
cd src && ./
PATH: toolchain:/home/alex/.rvm/gems/ruby-2.1.3/bin:/home/alex/.rvm/gems

./ line 5: command not found recipe for target 'src/.configure' failed
make: *** [src/.configure] Error 127

The error is in the line where is invoked:

cd src && ./

As soon as we chdir to src, toolchain directory in the PATH becomes unreachable. If we try in use $(realpath) it won't help because when PATH variable is set there is no toolchain directory yet & $(realpath) will expand to an empty string.

What if PATH was an old school macro that was reevaluated every time it was accessed? If we change PATH := to:

path.orig := $(PATH)
PATH = $(warning $(shell echo PWD=`pwd`))$(realpath toolchain):$(path.orig)

Then PATH becomes a recursively expanded variable & a handy $(warning) function will print to the stderr the current working directory exactly in the moment PATH is being evaluated (it won't mangle the PATH value because $(warning) always expands to an empty string).

$ rm -rf toolchain src ; make -f 2>&1 | cut -c -100
mkdir toolchain PWD=/home/alex/lib/writing/
printf "#!/bin/sh\necho foo" > toolchain/
chmod +x toolchain/
mkdir src PWD=/home/alex/lib/writing/
cp src
cd src && ./ PWD=/home/alex/lib/writing/
PATH: /home/alex/lib/writing/

touch src/.configure

As we see, PATH was accessed 3 times: before printf/cp invocations & after ./ (because for ./ there is no need to consult PATH).

Saturday, December 12, 2015


While upgrading to Fedora 23, I've discovered New Horizons of Awesomeness in gtk3. (I think it should be the official slogan for all the new gtk apps in general.)

If you don't use a compositor & select ubuntu-style theme:

  $ grep theme-name ~/.config/gtk-3.0/settings.ini
  gtk-theme-name = Ambiance  

modern apps start looking very indie in fvwm:

Granted, it's not 1997 anymore, we all have big displays w/ a lot of lilliputian pixels, but such a waste of a screen estate seems a little unnecessary to me.

Turns out it's an old problem that has no solution, except for the "use Gnome" handy advice. There is a hack but I don't think I'm in a such a desparate position to employ it. A quote from the README:

  I use $LD_PRELOAD to override several gdk and glib/gobject APIs to
  intercept related calls gtk+ 3 uses to setup CSD.  

I have no words. All we can do to disable the gtk3 decoration is to preload a custom library that mocks some rather useful part of gtk3 api. All praise Gnome!

In seeking of a theme that has contrast (e.g. !gray text on gray backgrounds) I've found that (a) an old default theme looks worse than Motif apps from 1990s:

  $ GTK_THEME=Raleigh gtk3-demo

Which is a pity because gtk2 Raleigh theme was much prettier:

& (b) my favourite GtkPaned widget renders equaly horrific everywhere. Even a highly voted Clearlooks-Phenix theme manages to make it practically imperceptible by the eye:

A moral of the story: don't write desktop apps (but all kids know this already), ditch gtk apps you run today for they all will become unusable tomorrow (but what do I know? I still use xv as a photo viewer).