0

When I run make, the first run always fails with Error 1, but the second run compiles as expected.

The first run produces this command:

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -ldl -o ../project42 ../project42.c -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

The second run produces this command (notice the inclusion of csvparser.c and nxjson.c):

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -ldl -o ../project42 ../csvparser.c ../nxjson.c ../project42.c -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

The Makefile looks like this:

ACEBASEDIR=../../../..
APIDIR=ctree.ctdb/multithreaded/static
GLIBINC=$(shell pkg-config --cflags glib-2.0 | xargs)
INCDIRS=-I$(ACEBASEDIR)/include -I$(ACEBASEDIR)/include/sdk/$(APIDIR) $(GLIBINC)
CFLAGS=-g $(INCDIRS) -ldl -o $@
LIBDIRS=-L$(ACEBASEDIR)/lib/$(APIDIR)
SYSLIBS=-lpthread -ldl -lm -lglib-2.0
SRCDIR=..
OUTDIR=..
$(OUTDIR)/project42: $(SRCDIR)/csvparser.c $(SRCDIR)/nxjson.c $(SRCDIR)/project42.c
    cc $(CFLAGS) $? $(LIBDIRS) -lmtclient $(SYSLIBS)
clean:
    rm -f $(OUTDIR)/project42

When I expand out the command, I get this:

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static $(shell pkg-config --cflags glib-2.0 | xargs) -ldl -o $@ $? -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

Running pkg-config --cflags glib-2.0 | xargs returns -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include.

To me, it looks like the problem is with the $? variable kindly described here. On the first run it seems to only resolve to ../project42.c and not to ../csvparser.c ../nxjson.c ../project42.c.

My suspicion is that I have something out of order, and that gets cached during the first run, but only AFTER it is needed.

What do I need to change in the Makefile for compilation to work the first time? Do I need to move the -L (LIBDIRS) portion before something else?

Adam Howell
  • 415
  • 1
  • 11
  • 24

1 Answers1

4

Don't use $?. That expands to the list of files that are newer than the target. You can't build an executable from only the changed files: you have to build it from all the files.

You want to use $^ here instead.

Really, there's no point in using make given this makefile; it always runs the same thing every time, unless there has been no change to any source file at all. What you have is barely better than a shell script.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Good answer. However, I don't see any compelling reason to switch to a shell script here. I have plenty of dinky makefiles that could be a simple shell script, but might grow in complexity later. – remcycles Dec 03 '19 at 16:52
  • That fixed the issue, thanks! Did it work the second run because the first run changed the timestamp on csvparser.c and nxjson.c? – Adam Howell Dec 03 '19 at 16:53
  • 3
    I see no way that this makefile would change the timestamps on source files. That's usually a very bad idea: source file timestamps should only be changed by the user when updates are made. Most likely what happened is that the first build failed to compile since it was missing files (you don't show that here though) and so the target `../project42` was deleted because of the errors. Then you re-ran make and now _all_ the files are newer than the (non-existing) target, so `$?` expands to all of them. – MadScientist Dec 03 '19 at 16:57