27.5.13

Colons in make targets

I learned something interesting about GNU make recently. It's possible to write rules for targets which contain colons (:). This doesn't work very well for filenames, even though Linux/UNIX filesystems could support it in theory—from the evidence on stackoverflow, it seems to break make's handing of dependencies internally.
But there is one potential situation where the colon could be of use, in pattern rules. Consider the following makefile1:
SOME_VAR:=some_value
OTHER_VAR=other_value

all: ; @echo "Just a vanilla rule to show the 'cut & paste'-friendly rule syntax."

show\:%: ; @echo $(@:show:%=%)="$($(@:show:%=%))"
This creates a target pattern show:%, where % operates as a wildcard. Notice that we need to escape the colon in the target's definition, as an unescaped colon would be interpreted as part of the rule's target: deps syntax. However, when it comes to making substitution references, a colon can be used without needing to be escaped, despite being part of the syntax. (In fact, the substitution will actually fail if the colon is escaped in this case—this is probably due to this being a syntactical edge-case.)
The formulation $(@:show:%=%) in the rule's recipe takes the name of the target (e.g. show:something) and strips off the initial show:, leaving the rest of the target name as a result (e.g. something). We can then use this value as we'd use any data in make—in this case, we're using it to show the value of a makefile variable, which could be useful when debugging makefiles, as the examples show:
$ make show:SOME_VAR
SOME_VAR=some_value

$ make show:OTHER_VAR
OTHER_VAR=other_value
So we can see that this show: pattern rule handles both flavours of make variable (i.e. = and :=). It can even be used to inspect some of make's built-in special variables:
$ make show:MAKEFILE_LIST
MAKEFILE_LIST= makefile

$ make show:.FEATURES
.FEATURES=target-specific order-only second-expansion else-if archives jobserver check-symlink

$ make show:.VARIABLES
.VARIABLES=<D ?F DESKTOP_SESSION CWEAVE ?D @D XAUTHORITY GDMSESSION CURDIR SHELL RM CO _ [...]

$ make show:DESKTOP_SESSION
DESKTOP_SESSION=ubuntu
So now we have a fairly natural-looking syntax for building make targets which take a single variable 'parameter'. I can see other uses for this: a rule to write a version number or string into a header file, for example.
There's a minor refactoring which could be made: if the repetition of $(@:show:%=%) in the rule is unacceptably offensive, we can hoist out the substitution logic into its own variable (which needs to be a recursive (=) flavour), although we then have to use $(patsubst) to make the substitution work:
_showtarget=$(patsubst show:%,%,$@)
show\:%: ; @echo $(_showtarget)="$($(_showtarget))"
One final note—when I say make above, I specifically mean GNU make v3.81.
$ make -v
GNU Make 3.81
This trick might work in older versions of GNU make (and it could possibly break in future versions, but hopefully with enough publicity, it won't). I doubt it will work with any other variant of make. (But I believe the first rule of Makefiles, so other versions of make are irrelevant to me.)


1 Note that I'm using the inline rule syntax to work around the 'tabs' issue—using a semicolon after a rule's target, so the recipe does not need to be indented. This should allow you to copy the code out of the blog and have it work as intended when it's pasted into a makefile.

21.5.13

Running with pointers I

(This is the first in an occasional series of explorations of some of the stranger areas of C++ syntax.)

Consider the following code. What does it output? Will it run without crashing?
#include <stdio.h>

struct TypeA {
    TypeA() { printf("::TypeA() {}\n"); }
    ~TypeA() { printf("::~TypeA() {}\n"); }
};

struct TypeB {
    TypeB() { printf("::TypeB() {}\n"); }
    ~TypeB() { printf("::~TypeB() {}\n"); }
};

int main() {
    TypeA *a = new TypeA;
    TypeB *b = new TypeB;

    printf(" %p %p\n", a, b);

    delete a, b;
    delete (a, b); // I really want these deleted.

    return 0;
}
You may be relieved to learn that the program does actually release its resources correctly. But the two delete lines should probably be rewritten and the utterly misleading comment removed. Both a and b are deleted once each, although the appearance of the comma operator in the delete expressions introduces some confusion. In the first delete, delete a is evaluated first, then the expression as a whole evaluates to b. On the next line, the expression (a, b) is evaluated, and then the result of that (b) is deleted.
The output you'll see is something like the following (pointer values may settle in transit; dramatization, do not attempt, etc):
$ ./a.out
::TypeA() {}
::TypeB() {}
 0x10a2010 0x10a2030
::~TypeA() {}
::~TypeB() {}
Slightly alarming is that the code compiles without a peep using GCC's default settings (on Ubuntu 12.04.2):
$ g++ main.cpp
[ compiler says nothing... ]
Although we do get some (slightly cryptic) warnings when compiling with -Wall:
$ g++ main.cpp -Wall
main.cpp: In function ‘int main()’:
main.cpp:19:16: warning: right operand of comma operator has no effect [-Wunused-value]
main.cpp:20:16: warning: left operand of comma operator has no effect [-Wunused-value]
So, uh, -Wunused-value is your friend, I guess... (If you compile this on a different compiler/OS, let me know what results you get.)