5May/090
Revenge of the Super-Makefile
So today I found some more things that the old Makefile was lacking. An "install" target, a ".PHONY" target to prevent breakage down the line, and the ability to recursively build subprojects. A few hours later, I have this:
PROJECT=foo
VERSION=0.0.1
SOURCES=bar.c baz.c
SUBPROJECTS=xyzzy fnord
LIBRARY=-lm
INCPATHS=xyzzy fnord
LIBPATHS=fnord
PREFIX=/usr/local
LDFLAGS=
CFLAGS=-c -Wall -g
CC=gcc
# ------------ MAGIC BEGINS HERE -------------
# We want subprojects to use these variables
export CC
export PREFIX
# Automatic generation of some important lists
OBJECTS=$(SOURCES:.c=.o)
INCFLAGS=$(foreach TMP,$(INCPATHS),-I$(TMP))
LIBFLAGS=$(foreach TMP,$(LIBPATHS),-L$(TMP))
# Set up the output file names for the different output types
ifeq "$(LIBRARY)" "shared"
BINARY=lib$(PROJECT).so
else ifeq "$(LIBRARY)" "static"
BINARY=lib$(PROJECT).a
else
BINARY=$(PROJECT)
endif
all: $(SOURCES) $(SUBPROJECTS) $(BINARY)
$(BINARY): $(OBJECTS)
ifdef SOURCES
# Assemble the object files into the right type of binary
ifeq "$(LIBRARY)" "static"
ar rcs $(BINARY) $(OBJECTS)
else ifeq "$(LIBRARY)" "shared"
$(CC) -shared $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
else
$(CC) $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
endif
endif
$(SUBPROJECTS):
make -e -C $@
.c.o:
$(CC) $(INCFLAGS) $(CFLAGS) -fPIC $< -o $@
install:
@ for i in $(SUBPROJECTS); do make -e -C $${i} install; done
ifdef SOURCES
ifeq "$(LIBRARY)" "static"
install $(BINARY) $(PREFIX)/lib
else ifeq "$(LIBRARY)" "shared"
install $(BINARY) $(PREFIX)/lib
else
install $(BINARY) $(PREFIX)/bin
endif
endif
distclean:
rm -f $(BINARY) $(OBJECTS)
@ for i in $(SUBPROJECTS); do make -C $${i} distclean; done
clean:
rm -f $(OBJECTS)
@ for i in $(SUBPROJECTS); do make -C $${i} clean; done
.PHONY: all clean distclean install $(SUBPROJECTS)
VERSION=0.0.1
SOURCES=bar.c baz.c
SUBPROJECTS=xyzzy fnord
LIBRARY=-lm
INCPATHS=xyzzy fnord
LIBPATHS=fnord
PREFIX=/usr/local
LDFLAGS=
CFLAGS=-c -Wall -g
CC=gcc
# ------------ MAGIC BEGINS HERE -------------
# We want subprojects to use these variables
export CC
export PREFIX
# Automatic generation of some important lists
OBJECTS=$(SOURCES:.c=.o)
INCFLAGS=$(foreach TMP,$(INCPATHS),-I$(TMP))
LIBFLAGS=$(foreach TMP,$(LIBPATHS),-L$(TMP))
# Set up the output file names for the different output types
ifeq "$(LIBRARY)" "shared"
BINARY=lib$(PROJECT).so
else ifeq "$(LIBRARY)" "static"
BINARY=lib$(PROJECT).a
else
BINARY=$(PROJECT)
endif
all: $(SOURCES) $(SUBPROJECTS) $(BINARY)
$(BINARY): $(OBJECTS)
ifdef SOURCES
# Assemble the object files into the right type of binary
ifeq "$(LIBRARY)" "static"
ar rcs $(BINARY) $(OBJECTS)
else ifeq "$(LIBRARY)" "shared"
$(CC) -shared $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
else
$(CC) $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
endif
endif
$(SUBPROJECTS):
make -e -C $@
.c.o:
$(CC) $(INCFLAGS) $(CFLAGS) -fPIC $< -o $@
install:
@ for i in $(SUBPROJECTS); do make -e -C $${i} install; done
ifdef SOURCES
ifeq "$(LIBRARY)" "static"
install $(BINARY) $(PREFIX)/lib
else ifeq "$(LIBRARY)" "shared"
install $(BINARY) $(PREFIX)/lib
else
install $(BINARY) $(PREFIX)/bin
endif
endif
distclean:
rm -f $(BINARY) $(OBJECTS)
@ for i in $(SUBPROJECTS); do make -C $${i} distclean; done
clean:
rm -f $(OBJECTS)
@ for i in $(SUBPROJECTS); do make -C $${i} clean; done
.PHONY: all clean distclean install $(SUBPROJECTS)
It's longer, but not by too much, and now I can safely say it has everything I have ever needed in a fancy build system. It would be nice if I could get pretty colourized output, but this Makefile reliably builds, cleans, and installs the projects I have tested it on.












