automake-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: gettext-0.14.2 fails on parallel build


From: Bruno Haible
Subject: Re: gettext-0.14.2 fails on parallel build
Date: Thu, 17 Mar 2005 18:37:16 +0100
User-agent: KMail/1.5

Alexandre Duret-Lutz wrote:
> Make starts only one command per target, and wait for this
> target to be completed before building any other dependent
> targets.
> 
> The only way to have the same target built several times is to
> explicitly start separate make processes yourself.  (That was
> what was happening.)
>
> When make encounters the following fragment
>
> all: one.elc two.elc three.elc
>
> one.elc two.elc three.elc: elc-stamp
>         ...
>
> it first has to build the dependency: elc-stamp.  Only one
> process does this.  Then, and only after elc-stamp has been
> built, make can run the three "..." commands in parallel.  It
> won't start the "..." commands their dependencies (here elc-stamp)
> are built.
>
> In Greg's output this is clearly apparent.  The elc-stamp is run
> a first time alone.  After it has finished, three `make
> elc-stamp' are explicitly started by the three parallel instance
> of the "..." rule.

You are right with your analysis, answering the question "*why* are there
three processes in parallel, executing the elc-stamp simultaneously".

And now that they are executing in parallel, what happens is:

        Process 1 creates elc-temp.
        Process 2 re-creates elc-temp.
        Then process 1 and process 2 perform the "..." task.
        Process 1 moves elc-temp to elc-stemp.
        Process 2 attempts to do so as well, but elc-temp was already gone.

Your fix replaced a line inside the $(am__ELCFILES) actions, so that it does
nothing if $(EMACS) = no. So it will fix the problem for Greg - until
he installs an Emacs, does "make", "rm -f *.elc" and "make" again. Then the
same problem will occur again.

Please look again at the Makefile.in. It contains

am__ELFILES = po-compat.el po-mode.el start-po.el
am__ELCFILES = $(am__ELFILES:.el=.elc)

$(am__ELCFILES): elc-stamp
        @if test ! -f $@; then \
          rm -f elc-stamp; \
          $(MAKE) $(AM_MAKEFLAGS) elc-stamp; \
        else : ; fi

elc-stamp: $(LISP)
        @echo 'WARNING: Warnings can be ignored. :-)'
        @rm -f elc-temp && touch elc-temp
        if test "$(EMACS)" != no; then \
          set x; \
          list='$(LISP)'; for p in $$list; do \
            if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
            set x "$$@" "$$d$$p"; shift; \
          done; \
          shift; \
          EMACS="$(EMACS)" $(SHELL) $(elisp_comp) "$$@" || exit 1; \
        else : ; fi
        @mv -f elc-temp $@

The $(am__ELCFILES) is, as you say, responsible for spawning three
'make' processes trying to create elc-stamp.

What is the purpose of this rule? It could mean: "If you just remade
elc-stamp, but it didn't produce all required *.elc files, then remake
elc-stamp again." But that is not useful since executing the same commands
a second time will not produce a better result.

So it must mean: "If the user has removed *.elc but elc-stamp is still
there, then remake elc-stamp." This scenario can still occur, and will
still lead to multiple parallel processes [except if only one .elc file
was missing], and will still fail the same way.

> The automake's aux scripts use mkdir as atomic test-and-set.

Ah, right. Thanks. So here is an updated fix proposal:

elc-stamp: $(LISP)
    trap 'rm -rf elc-temp elc-stamp' 1 2 3 15; \
    if mkdir elc-temp 2>/dev/null; then \
      # Comment: This code is being executed by the first process.
      if test "$(EMACS)" != no; then \
        [compile the *.lisp files] \
      else : ; fi; \
      touch $@; \
      rmdir elc-temp; \
    else \
      # Comment: This code is being executed by the follower processes.
      # Comment: Wait until the first process is done.
      while test -d elc-temp; do sleep 1; done; \
      # Comment: Succeed if and only if the first process succeeded.
      test -f $@; exit $$?; \
    fi

Bruno





reply via email to

[Prev in Thread] Current Thread [Next in Thread]