framos framos - 2 months ago 22
Bash Question

Lock a whole target in a Makefile

I have a Makefile with a target that executes multiple system-wide operations (e.g. installing packages), so I want to lock the target in a way that other make processes will wait on that target, thus preventing parallel execution.

I tried using flock as explained in this answer, but I think the particularities of makefiles are getting in the way.

This is what I have right now:

LOCKFILE=/var/lock/makefile.lock
LOCKFD=200

mytarget:
# make sure to release the lock in any case
eval "exec $(LOCKFD)>$(LOCKFILE)"; trap "flock -xn $(LOCKFD) && rm -f $(LOCKFILE)" EXIT
# get exclusive waiting lock
flock -x $(LOCKFD)
[regular target operations...]
# release lock and delete the lock file
flock -u $(LOCKFD); flock -xn $(LOCKFD) && rm -f $(LOCKFILE)


It fails with this error, because the file descriptor 200 is not properly set:

$ make mytarget
# make sure to release the lock in any case
eval "exec 200>/var/lock/makefile.lock"; trap "flock -xn 200 && rm -f /var/lock/makefile.lock" EXIT
# get exclusive waiting lock
flock -x 200
flock: 200: Bad file descriptor
Makefile:57: recipe for target 'mytarget' failed


There has to be something wrong with the
eval
definition, but I don't see what.

Answer

Make runs every command line in a new shell. I guess your fd is gone after eval. You have use a single command line and separate commands with ";". If you want to use split the command line for clarity you need to end all but the last line with "\". See the make manual, Splitting Recipe Lines. Or use a shell script.

Comments