4

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.

Community
  • 1
  • 1
framos
  • 43
  • 6
  • @shellter All that is explained in the answered I linked to in the question. EXIT is the name of the signal to trap, and looks like `eval` is necessary otherwise `exec` will interpret the fd as a command. – framos Sep 20 '16 at 16:41
  • For future reference, this is why links to external sites are not a good idea. Questions should be standalone. If there is an external source for your information, you can include that, but you should edit your Q to include the relevant facts. Answer below looks good. Good luck. – shellter Sep 20 '16 at 16:46
  • Locking makes thinks difficult, and a target doesn't execute anything. I think you're trying to enforce a non-make way of doing things to which make was designed to provide an alternative. Do you really need locking here? When process A should "wait on" process B, make B create a target after it finishes and make that target a dependency of A. – reinierpost Jun 02 '17 at 10:50

1 Answers1

3

Make runs every command line in a new shell. I guess your fd is gone after eval. You can use a single command line and separate commands with ";". If you want to 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.

rveerd
  • 3,620
  • 1
  • 14
  • 30
  • Thank you for your answer and the link to the make manual! I think your idea of extracting everything into a shell script is going to work best, I will give it a try and report back. – framos Sep 20 '16 at 16:43
  • Extracting everything to a script worked, thanks @rveerd! – framos Sep 21 '16 at 20:46