Search code examples
clinuxmakefilecc

Linux make fails on first run, succeeds on second run


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?


Solution

  • 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.