views:

241

answers:

2

For starters, this exercise in GNU make was admittedly just that: an exercise rather than a practicality, since a simple bash script would have sufficed. However, it brought up interesting behavior I don't quite understand.

I've written a seemingly simple Makefile to handle generation of SSL key/cert pairs as necessary for MySQL. My goal was for make <name> to result in <name>-key.pem, <name>-cert.pem, and any other necessary files (specifically, the CA pair if any of it is missing or needs updating, which leads into another interesting follow-up exercise of handling reverse deps to reissue any certs that had been signed by a missing/updated CA cert).

After executing all rules as expected, make seems to be too aggressive at identifying intermediate files for removal; it removes a file I thought would be "safe" since it should have been generated as a prereq to the main rule I'm invoking. (Humbly translated, I likely have misinterpreted make's documented behavior to suit my expectation, but don't understand how. ;-)

Edited (thanks, Chris!) Adding %-cert.pem to .PRECIOUS does, of course, prevent the deletion. (I had been using the wrong syntax.)

Makefile:

OPENSSL = /usr/bin/openssl

# Corrected, thanks Chris!
.PHONY: clean

default: ca

clean:
        rm -I *.pem

%: %-key.pem %-cert.pem
        @# Placeholder (to make this implicit create a rule and not cancel one)

Makefile:
        @# Prevent the catch-all from matching Makefile

ca-cert.pem: ca-key.pem
        $(OPENSSL) req -new -x509 -nodes -days 1000 -key ca-key.pem > $@

%-key.pem:
        $(OPENSSL) genrsa 2048 > $@

%-cert.pem: %-csr.pem ca-cert.pem ca-key.pem
        $(OPENSSL) x509 -req -in $ $@

Output:

$ make host1
/usr/bin/openssl genrsa 2048 > ca-key.pem
/usr/bin/openssl req -new -x509 -nodes -days 1000 -key ca-key.pem > ca-cert.pem
/usr/bin/openssl genrsa 2048 > host1-key.pem
/usr/bin/openssl req -new -days 1000 -nodes -key host1-key.pem > host1-csr.pem
/usr/bin/openssl x509 -req -in host1-csr.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > host1-cert.pem
rm host1-csr.pem host1-cert.pem  

This is driving me crazy, and I'll happily try any suggestions and post results. If I'm just totally noobing out on this one, feel free to jibe away. You can't possibly hurt my feelings. :)

+1  A: 

The first thing i noticed is that your line:

.PHONY = clean

should be:

.PHONY : clean

See: http://www.gnu.org/software/automake/manual/make/Phony-Targets.html

Chris
That, of course, was how I failed at using .PRECIOUS as well. Thanks for catching that!
James
A: 

http://www.gnu.org/software/automake/manual/make/Chained-Rules.html#Chained-Rules

You can prevent automatic deletion of an intermediate file by marking it as a secondary file. To do this, list it as a prerequisite of the special target .SECONDARY. When a file is secondary, make will not create the file merely because it does not already exist, but make does not automatically delete the file. Marking a file as secondary also marks it as intermediate.

http://www.gnu.org/software/automake/manual/make/Special-Targets.html

The targets which .PRECIOUS depends on are given the following special treatment: if make is killed or interrupted during the execution of their commands, the target is not deleted. See Interrupting or Killing make. Also, if the target is an intermediate file, it will not be deleted after it is no longer needed, as is normally done. See Chains of Implicit Rules. In this latter respect it overlaps with the .SECONDARY special target.

You can also list the target pattern of an implicit rule (such as `%.o') as a prerequisite file of the special target .PRECIOUS to preserve intermediate files created by rules whose target patterns match that file's name.

Casey