bug-make
[Top][All Lists]
Advanced

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

Re: "make -jN" requires mechanical changes to a Makefile [SOLVED]


From: Bruno Haible
Subject: Re: "make -jN" requires mechanical changes to a Makefile [SOLVED]
Date: Sun, 13 Sep 2020 20:55:07 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-189-generic; KDE/5.18.0; x86_64; ; )

Continuing this thread from May 2019
<https://lists.gnu.org/archive/html/bug-make/2019-05/msg00022.html>:
The problem was:

  How can a rule that generates multiple files be formulated so
  that it works with parallel make?

For example, a rule that invokes bison, or a rule that invokes
a different Makefile. For simplicity, here, use a rule that
creates 4 files copy1, copy2, copy3, copy4.

===========================================
all : copy1 copy2 copy3 copy4

copy1 copy2 copy3 copy4: Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4
===========================================

Unfortunately, with "make -j8", it invokes the rule multiple times.

It is possible to change this Makefile so that
  (A) "rm -f copy?; make" executes the rule once.
  (B) "rm -f copy?; make -j8" executes the rule once as well.
  (C) After "make", another "make" just prints "Nothing to be done for 'all'."
  (D) After removing one of the files copy?, "make" executes the rule once.
      (This covers also the case of pressing Ctrl-C during "make", then
      doing "make" again.)
  (E) After replacing one of the files copy? with a file that is older than
      Makefile, "make" executes the rule once.

There are three possibilities:


(I) Assuming GNU make >= 4.3, the "Grouped explicit target" syntax does it.
Thanks to Kaz Kylheku and Paul Smith for having added this.

===========================================
all : copy1 copy2 copy3 copy4

copy1 copy2 copy3 copy4 &: Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4
===========================================

But it will take a number of years until we can assume that all 'make'
programs that we care about support this syntax.


(II) It is possible to turn off parallel make. This does it:

===========================================
all : copy1 copy2 copy3 copy4

copy1 copy2 copy3 copy4 : Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4

# This Makefile contains rules which don't work with parallel make.
# So, turn off parallel execution in this Makefile.
.NOTPARALLEL:
===========================================

But some people who want to minimize wall-clock execution time of
their builds may not like it.


(III) Use portable make syntax and still allow parallel make.

This is a bit harder. My solution is to first analyze in which order
the rule will generate the various files and thus what the expected
timestamp order is. In this case, it is:
  Makefile <= copy1 <= copy2 <= copy3 <= copy4

First some attempts that don't work:

===========================================
all : copy1 copy2 copy3 copy4

copy1: Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4

copy2 copy3 copy4: copy1
===========================================

Fails (E).

===========================================
all : copy1 copy2 copy3 copy4

copy4: Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4

copy1 copy2 copy3: copy4
===========================================

Fails (E) as well.

===========================================
all : copy1 copy2 copy3 copy4

copy4: Makefile
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4

copy1: copy4
        test -f copy1 || { rm -f copy4; $(MAKE) copy4; }
copy2: copy4
        test -f copy2 || { rm -f copy4; $(MAKE) copy4; }
copy3: copy4
        test -f copy3 || { rm -f copy4; $(MAKE) copy4; }
===========================================

Fails (E) for copy1, ..., copy3.
And fails (C), i.e. clutters the "make" output.

===========================================
all : copy1 copy2 copy3 copy4

copy1: Makefile
        { test -f copy1 && test ! copy1 -ot Makefile; } || { rm -f copy4; 
$(MAKE) copies; }
copy2: copy1
        { test -f copy2 && test ! copy2 -ot copy1; } || { rm -f copy4; $(MAKE) 
copies; }
copy3: copy2
        { test -f copy3 && test ! copy3 -ot copy2; } || { rm -f copy4; $(MAKE) 
copies; }
copy4: copy3
        { test -f copy4 && test ! copy4 -ot copy3; } || { rm -f copy4; $(MAKE) 
copies; }

copies:
        install -c -m 644 Makefile copy1
        install -c -m 644 Makefile copy2
        install -c -m 644 Makefile copy3
        install -c -m 644 Makefile copy4
.PHONY: copies
===========================================

This solution fulfils all the requirements.

Can we use 'test FILE1 -ot FILE2'?
- POSIX 'test' does not support this option.
  See <https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html>
- But all test programs in all current operating systems (Linux, macOS,
  FreeBSD, NetBSD, OpenBSD, AIX, Solaris, Haiku, Minix, Cygwin, even Busybox)
  support it. Except for /bin/sh on Solaris 10 — but in packages that use the
  GNU Build System, Autoconf sets SHELL = @CONFIG_SHELL@ = /bin/bash on such
  systems.

Bruno




reply via email to

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