Reputation: 28695
I don't know much about creating Makefiles, but I've been reading the make manual and I have made some progress. My Makefile works and does what I want.
My situation usually involves between 1 and 3 different program needed to be compiled and sent to my TA for marking and such via a webform. The structure of each application is 'prog.c', 'prog_lib.h', and 'prog_lib.c'. In the past, I have been creating separate directories for each program and creating separate Makefiles for each directory to build the program contained within. I then tar each folder and submit them separately.
Recently, the TAs have been asking for all source files to be in one directory and one Makefile with the various targets to be built so their marking applications can work without any human intervention.
I was wondering how someone more experienced would improve this Makefile and how my situation in general is usually solved? I would like to reduce the amount of typing I need to do when I move on to my next assignment and have to update several places.
Here is my Makefile:
ASSIGNMENT = 3
TARNAME = Assignment$(ASSIGNMENT).tar.bz2
CC = gcc
CFLAGS = -O2 -Wall -ansi -pedantic -W # I like warnings
LDFLAGS = -lm
DEBUG = -g # to resolve symbols in GDB and valgrind
FREQ_OUT = frequency_table
FREQ_SOURCES = frequency_table.c frequency_table_lib.c
FREQ_OBJECTS = frequency_table.o frequency_table_lib.o
DECODE_OUT = decode
DECODE_SOURCES = decode.c decode_lib.c
DECODE_OBJECTS = decode.o decode_lib.o
SOURCES = $(FREQ_SOURCES) $(DECODE_SOURCES)
OBJECTS = $(FREQ_OBJECTS) $(DECODE_OBJECTS)
OUT = $(FREQ_OUT) $(DECODE_OUT)
.PHONY: info
info:
@echo -e "make info\n" \
"\tmake all \t\t\tMake all targets\n" \
"\tmake frequency_table \t\tMakes frequency table\n" \
"\tmake decode \t\t\tMakes decode\n" \
"\tmake dist \t\t\tMakes tar archive of sources and Makefile\n" \
"\tmake clean \t\t\tRemoves all the object files and executables\n" \
"\tmake distclean \t\t\tPerforms clean and removes tar archive"
.PHONY: all
all: $(OUT)
$(FREQ_OUT): $(FREQ_OBJECTS)
$(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@
$(DECODE_OUT): $(DECODE_OBJECTS)
$(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(DECODE_OBJECTS) -o $@
.o:
$(CC) -c $(CFLAGS) -o $@ $<
.PHONY: dist
dist: $(SOURCES)
@echo "Creating tar archive. See $(TARNAME)"
tar cvjf $(TARNAME) $(SOURCES) $(wildcard *_lib.h) Makefile
.PHONY: clean
clean:
rm -f $(OUT) $(OBJECTS)
.PHONY: distclean
distclean: clean
rm -f $(TARNAME)
Upvotes: 1
Views: 1326
Reputation: 113370
You really don't need the $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@
lines. make already knows how to build binaries.
If your filenames are constant for different binaries (binary.c and binary_lib.c), you can also create a general rule for that:
FOO := $(shell ls *_lib.c)
BIN = $(FOO:%_lib.c=%)
$(BIN) : % : %.o %_lib.o
EDIT: Here's how it works:
Upvotes: 3
Reputation: 754480
Make the 'all' target the first one, unless you are really sure your users should have to type something after 'make' to get the project to build. The 'info' target is nice but aconventional.
(I do have one makefile where the default target is not all - in a directory with source code for 100+ commands. I do not want 'make all' to be the default; I expect to build just the one or two that I want to build. There is an 'all'. But that is very unusual. Normally, the default should be 'all'.)
Also, neither '$(FREQ_OUT)' nor '$(DECODE_OUT)' is a PHONY target; they are real programs, aren't they? The 'all', 'info', 'dist', 'clean', 'realclean' etc targets - those are phony. But the programs you build are not.
Upvotes: 3
Reputation: 7445
Example:
# CC, CFLAGS, etc. go here
# Object variables go here
MYPROG_OBJECTS = main.o someother.o
# all, info, etc. targets go here
# first actual target:
myprog: $(MYPROG_OBJECTS)
<Do the linking stuff>
# This will take care of the objects, sources are placed in src directory:
%.o: src/%.c
<The usual compilation commands>
# Automatic dependency magic:
%.d: src/%.c
$(CC) -MM -o$@ $<
-include (MYPROG_OBJECTS:%.o=%.d)
Upvotes: 1
Reputation: 339917
In my experience, you shouldn't need the .o
target in there, that's implicit.
Also, the implicit version normally includes the value of $(CPPFLAGS)
, which is where you should put any -I
path or -D
macro options that you might require.
I'd also include the $(DEBUG)
in $(CFLAGS)
, rather than list it explicitly in any of the build targets.
Upvotes: 2