My GNU make Makefile:
# TODOs so I don't forget:
# - make debugging an option
# - make 64 below an actual option
# - figure out why make test seems to rebuild the DLL [note: this TODO is this question]
# - __declspec(dllimport)
ifeq ($(MAKECMDGOALS),64)
CC = x86_64-w64-mingw32-gcc
RC = x86_64-w64-mingw32-windres
mflag = -m64
else
CC = i686-w64-mingw32-gcc
RC = i686-w64-mingw32-windres
mflag = -m32
endif
OBJDIR = .objs
OUTDIR = out
BASENAME = wintable
DLLFILE = $(OUTDIR)/$(BASENAME).dll
LIBFILE = $(OUTDIR)/$(BASENAME).lib
TESTEXEFILE = $(OUTDIR)/$(BASENAME).exe
CFILES = \
alloc.c \
api.c \
checkboxdraw.c \
checkboxevents.c \
children.c \
coord.c \
debug.c \
draw.c \
enablefocus.c \
events.c \
header.c \
hscroll.c \
main.c \
metrics.c \
modelhelpers.c \
modelnotify.c \
nullmodel.c \
resize.c \
scroll.c \
select.c \
tooltips.c \
update.c \
util.c \
visibility.c \
vscroll.c
HFILES = \
table.h \
tablepriv.h
TESTCFILES = \
test.c
OFILES = $(CFILES:%.c=$(OBJDIR)/%.o)
TESTOFILES = $(TESTCFILES:%.c=$(OBJDIR)/%.o)
xCFLAGS = \
--std=c99 \
-Wall \
-Wextra \
-Wno-unused-parameter \
$(mflag) \
$(CFLAGS)
xLDFLAGS = \
-static-libgcc \
-luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 \
$(mflag) \
$(LDFLAGS)
default:
$(MAKE) clean
$(MAKE) it
$(MAKE) test
it: $(DLLFILE)
$(DLLFILE): $(OFILES)
$(CC) -g -o $(DLLFILE) -shared -Wl,--out-implib,$(LIBFILE) $(OFILES) $(xLDFLAGS)
test: $(TESTEXEFILE)
# see https://stackoverflow.com/a/29021641/3408572
.PHONY: test
$(TESTEXEFILE): $(DLLFILE) $(TESTOFILES)
$(CC) -g -o $(TESTEXEFILE) $(TESTOFILES) $(LIBFILE) $(xLDFLAGS)
$(OBJDIR)/%.o: %.c $(HFILES) dirs
$(CC) -g -o $@ -c $< $(xCFLAGS)
dirs:
mkdir -p $(OBJDIR) $(OUTDIR)
clean:
rm -rf $(OBJDIR) $(OUTDIR)
I build with make
and wanted to make cleaning and testing, which I do often, convenient, so for the moment my default
cleans ($(MAKE) clean
), builds the DLL ($(MAKE) it
), and builds the test program ($(MAKE) test
).
However, make
does
make clean
make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable'
rm -rf .objs out
make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable'
make it
make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable'
mkdir -p .objs out
i686-w64-mingw32-gcc -g -o .objs/alloc.o -c alloc.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/api.o -c api.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/checkboxdraw.o -c checkboxdraw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/checkboxevents.o -c checkboxevents.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/children.o -c children.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/coord.o -c coord.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/debug.o -c debug.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/draw.o -c draw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/enablefocus.o -c enablefocus.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/events.o -c events.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/header.o -c header.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/hscroll.o -c hscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/main.o -c main.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/metrics.o -c metrics.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/modelhelpers.o -c modelhelpers.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/modelnotify.o -c modelnotify.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/nullmodel.o -c nullmodel.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/resize.o -c resize.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/scroll.o -c scroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/select.o -c select.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/tooltips.o -c tooltips.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/update.o -c update.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/util.o -c util.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/visibility.o -c visibility.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/vscroll.o -c vscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o out/wintable.dll -shared -Wl,--out-implib,out/wintable.lib .objs/alloc.o .objs/api.o .objs/checkboxdraw.o .objs/checkboxevents.o .objs/children.o .objs/coord.o .objs/debug.o .objs/draw.o .objs/enablefocus.o .objs/events.o .objs/header.o .objs/hscroll.o .objs/main.o .objs/metrics.o .objs/modelhelpers.o .objs/modelnotify.o .objs/nullmodel.o .objs/resize.o .objs/scroll.o .objs/select.o .objs/tooltips.o .objs/update.o .objs/util.o .objs/visibility.o .objs/vscroll.o -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32
make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable'
make test
make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable'
mkdir -p .objs out
i686-w64-mingw32-gcc -g -o .objs/alloc.o -c alloc.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/api.o -c api.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/checkboxdraw.o -c checkboxdraw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/checkboxevents.o -c checkboxevents.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/children.o -c children.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/coord.o -c coord.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/debug.o -c debug.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/draw.o -c draw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/enablefocus.o -c enablefocus.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/events.o -c events.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/header.o -c header.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/hscroll.o -c hscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/main.o -c main.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/metrics.o -c metrics.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/modelhelpers.o -c modelhelpers.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/modelnotify.o -c modelnotify.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/nullmodel.o -c nullmodel.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/resize.o -c resize.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/scroll.o -c scroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/select.o -c select.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/tooltips.o -c tooltips.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/update.o -c update.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/util.o -c util.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/visibility.o -c visibility.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o .objs/vscroll.o -c vscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o out/wintable.dll -shared -Wl,--out-implib,out/wintable.lib .objs/alloc.o .objs/api.o .objs/checkboxdraw.o .objs/checkboxevents.o .objs/children.o .objs/coord.o .objs/debug.o .objs/draw.o .objs/enablefocus.o .objs/events.o .objs/header.o .objs/hscroll.o .objs/main.o .objs/metrics.o .objs/modelhelpers.o .objs/modelnotify.o .objs/nullmodel.o .objs/resize.o .objs/scroll.o .objs/select.o .objs/tooltips.o .objs/update.o .objs/util.o .objs/visibility.o .objs/vscroll.o -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32
i686-w64-mingw32-gcc -g -o .objs/test.o -c test.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32
i686-w64-mingw32-gcc -g -o out/wintable.exe .objs/test.o out/wintable.lib -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32
make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable'
Notice how the $(MAKE) test
step of that rebuilds the DLL as if the $(MAKE) it
step didn't happen! There's no cleaning in between steps, and no other changes happen, so I don't know why the DLL is being rebuilt.
I thought making the default
, it
, clean
, and dirs
targets phony would fix it (as per one of my previous questions), but that didn't work. Google is only telling me how to tell make to build my target twice, not how to stop it from doing so.
This is GNU make 4.0 on Ubuntu GNOME 14.10.
What's going on? Thanks.
UPDATE 22 April 2015
I'm starting to think the problem is actually the one outlined here since I'm seeing similar rebuilding issues on other projects I have that don't do the make test
thing I'm doing here:
This works well for this simple example, but there\'s a major problem. Since the timestamp on a directory is typically updated when any of the files inside the directory are updated this Makefile does too much work.
For example, just touching a random file inside /out/ forces a rebuild of /out/foo.o. In a complex example this could mean that many object files are rebuilt for no good reason, just because other files were rebuilt in the same directory.
I'll confirm that this is actually the case and provide an answer when appropriate.
make clean
every time you build thedefault
target, andmake clean
deletes all the object files, so the fact that those object files are gone means that the DLLFILE target is out of date because they all have to get rebuilt. Why are you runningmake clean
between every build? – MadScientistmake
; the output above is formake -n
, as the question states. I know I'm cleaning before each build, but the$(MAKE) it
should rebuild $DLLFILE; my question is why the$(MAKE) test
step disregards that (despite not cleaning). I'll reword the question shortly. (I'm cleaning and building the tests indefault
for now as a convenience; the final version of the Makefile won't have that step. I'd still like to fix this issue for future reference.) – andlabs