0

I have the following Makefile.

objects = foo.o bar.o all.o  -- line 1
all: $(objects)

# These files compile via implicit rules
foo.o: foo.c 
bar.o: bar.c
all.o: all.c

all.c:
    echo "int main() { return 0; }" > all.c

%.c:
    touch $@

clean:
    rm -f *.c *.o all

When i run make, i get the below output.

echo "int main() { return 0; }" > all.c
cc    -c -o all.o all.c
touch foo.c
cc    -c -o foo.o foo.c
touch bar.c
cc    -c -o bar.o bar.c
cc   all.o foo.o bar.o   -o all

Question:
Line 1 of the Makefile shows foo.o is the first dependency. So why all.o which depends on all.c are executed first?

Botje
  • 26,269
  • 3
  • 31
  • 41
yapkm01
  • 3,590
  • 7
  • 37
  • 62
  • Why do you assume that make will build dependencies in a particular order? – Botje Jul 06 '22 at 13:49
  • @Botje You mean there is no order of execution as far as dependencies is concerned? – yapkm01 Jul 06 '22 at 14:03
  • Not on purpose, no. Some implementation detail might happen to cause the same order every time, but implicit ordering between targets is a nightmare when trying to build in parallel. – Botje Jul 06 '22 at 14:14
  • Traditionally, the dependencies of a target such as `all` are updated in left-to-right sequence. If you do a parallel `make` (e.g. `make -j8`), then the parallelism means that the sequence is no longer guaranteed. What was the command line you executed — just `make` or something more complicated? Do you have the environment variable `MAKEFLAGS` set — and if so, what is it set to? Which version of `make` are you running and on which system? The tags indicate "GNU Make", which partly answers the "which version" question. – Jonathan Leffler Jul 06 '22 at 14:22
  • Note that the POSIX specification for [`make`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html) (which does not include options for parallel operation) says: _The `make` utility shall treat all prerequisites as targets themselves and recursively ensure that they are up-to-date, processing them in the order in which they appear in the rule._ – Jonathan Leffler Jul 06 '22 at 14:26
  • No, there is no sensible order possible. While some implementations of `make` promise a few things about order in certain situations like @JonathanLeffler said, in the end it makes little sense: if you have the targets `a1: b1 b2 b3` , `a2: b2 b1 b3` and `a3: b3 b1 b2`, you can't exploit any order because any of the `aX` targets could be already made so its prerequesite list isn't considered, i.e. the order of the `bX` is a function of factors external to `make` – Vroomfondel Jul 06 '22 at 14:30
  • 2
    Just to clarify the above: it is guaranteed by POSIX and by all POSIX-conforming versions of make, including GNU make, that (in the absence of `-j`) prerequisites will be considered in the order in which they are listed in the makefile. However, this is not absolute because make can permute this order (for the first prerequisite only) for implicit rules (it can't change the order for explicit rules). See Jonathan's answer for an explanation of this. – MadScientist Jul 06 '22 at 14:40
  • 1
    In general, it's bad practice to assume that a list of dependencies will be executed in order. As mentioned, someone in the future could add a `-j` to the command line, or you could have sub-dependencies, etc. If you need one target to be built before the other, then use a dependency to guarantee that order – HardcoreHenry Jul 06 '22 at 19:42
  • Interesting question, answer and comments. Stiil, I don''t understand what's going on here. `all: $(objects)` is explicit so why is `make -j1` changing the order? And why, if `all` is declared as phony, `make -j1` builds the object files in the specified order? – Renaud Pacalet Jul 07 '22 at 15:01
  • See also [Order of processing components in a makefile?](https://stackoverflow.com/q/9159960/15168) – Jonathan Leffler Jul 10 '22 at 00:44

1 Answers1

1

You are confusing things by having the file all.c (and object file all.o) and the target all. Conventionally, the all target is a pseudo-target (.PHONY in GNU Make) for 'all the things that are (normally) built by this makefile. This isn't enforced — it is merely convention.

However, here, make is trying to use all.c to build a program all. And it knows it can build all by compiling all.c, so it generates that first.

You could clarify things by either using any.c instead of all.c and building any.o and program any, and having the all: target read:

all: any

That would build the program any

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278