Reputation: 3465
My program comprises sharedmemory.c
sharedmemory.h
semaphore.c
semaphore.h
sumprime.c
, now I want to compile in Linux an executable file named sumprime
sumprime.c
code calls some methods that are declared in sharedmemory.h
semaphore.h
and implemented in sharedmemory.c
semaphore.c
My makefile
is like this:
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
OBJFILES = sumprime.o semaphore.o sharedmemory.o
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
DISTFOLDER = lab5
HANDIN = ${DISTFOLDER}.tar.bz2
DEST=sumprime
CCFLAG=
.PHONY: all clean pack
all: $(DEST)
$(DEST): sumprime.o
gcc sumprime.o -o $(DEST)
sumprime.o: $(HEADERFILES) $(SOURCEFILES)
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
clean:
pack:
@echo [PACK] Preparing for packaging...
@rm -fr ${DISTFOLDER} ${HANDIN}
@mkdir ${DISTFOLDER}
@echo [PACK] Copying solution files
@for file in ${DISTFILES}; do\
cp -f $$file ${DISTFOLDER};\
echo \>\>\> $$file;\
done;
@echo [PACK] Creating ${HANDIN}...
@tar cjf ${HANDIN} ${DISTFOLDER}
@rm -fr ${DISTFOLDER}
@echo [PACK] Done!
I tried multiple ways in vain after searching. Please help me with this
Upvotes: 2
Views: 426
Reputation: 44063
As gcc
should tell you, you cannot use -c
with multiple input files, so
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
does not work.
Fortunately, it also isn't necessary; in fact, you don't need special rules for the .o
files because the built-in rules work quite well. This is particularly the case because the name of the output binary corresponds with one of the object files (sumprime.o
; see "Linking a single object file" behind the link).
I would use something like
#!/usr/bin/make -f
CC = gcc
CPPFLAGS = -MD
CFLAGS = -O2 -g
LDFLAGS =
LDLIBS =
TARGET = sumprime
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
DISTFOLDER = lab5
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
HANDIN = $(DISTFOLDER).tar.bz2
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
all: $(TARGET)
$(TARGET): $(OBJFILES)
clean:
rm -f $(TARGET) $(OBJFILES)
distclean: clean
rm -f $(DEPFILES) $(HANDIN)
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
@echo [DIST] Preparing for packaging...
@rm -f $@
@tar cjf $@ --transform 's,^,$(DISTFOLDER)/,' $+
@echo [DIST] Done!
.PHONY: all clean distclean dist pack
-include $(DEPFILES)
Obviously, this requires some explanation.
I mentioned these above: make predefines a number of rules that often just Do The Right Thing™; we can make them do most of our work. In fact, the shortest Makefile you could use to build your program is
sumprime: sumprime.o semaphore.o sharedmemory.o
This uses an implicit rule to build the .o
files and an implicit recipe to build sumprime
. Note that there are variables that influence the behavior of implicit rules; behind the link above is a list of such rules that includes their recipes, and in them the names of the variables they use. Since we're compiling C code, the ones we're interested in are:
CPPFLAGS = -MD # C preprocessor flags, such as -Ipath -DMACRO=definition
CFLAGS = -O2 -g # C compiler flags
LDFLAGS = # linker flags, such as -Lpath
LDLIBS = # linked libraries, such as -lpthread (Alternatively:
# LOADLIBES, but this is less usual)
The lines
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
use pattern substitution to generate a list of .o
files from a list of .c
files, and .d
from .o
. We'll use .d
files for dependency tracking.
This is perhaps the most complex part, but it's not that bad.
One of the practical problems with the minimal Makefile is that it doesn't know about #include
s. If sumprime.c
includes semaphore.h
and semaphore.h
is changed, we would really like sumprime.c
to be rebuilt. Fortunately, gcc has a mechanism to facilitate this that we invoke with
CPPFLAGS = -MD
When given this option, the preprocessor generates a .d
file corresponding to the input .c
it was given (i.e., if sumprime.c
is compiled, sumprime.d
is generated) that contains a make-compatible list of dependencies of the source file. For example, I expect a sumprime.d
that looks something like
sumprime.c: semaphore.h sharedmemory.h
Then, with
-include $(DEPFILES)
make is instructed to include these files into its code if they exist. This means that make always knows the dependencies of source files as they were during the last build (!). That it lags one behind is not a problem because a change in the dependencies requires a change in one of the files that a target depended on last time, and that no dependencies are pulled in the first time is not a problem because the first time everything has to be built anyway.
And so we get dependency tracking with a minimum of fuss.
The
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
@echo [DIST] Preparing for distaging...
@rm -f $@
@tar cjf $@ --transform 's,^,$(DISTFOLDER)/,' $+
@echo [DIST] Done!
rule requires GNU tar, but if it is available, its --transform
option makes for a much nicer dist
rule, as you can see. I took the liberty of changing it to that. Of course, if you prefer, you can still use your old way.
Side note: It is more usual to call what you called the pack
rule dist
. There is no technical reason for this, it's just a convention; people expect make dist
. With this code, both names work.
Upvotes: 1