Makefile in C with multiple sources - c

I am currently learning C and now I am upto the tutorial where I need to write the Makefile but I am difficulty writing a Makefile for multiple sources. Can someone tell me how I can correct my code for the Makefile for multiple sources? All of the files are in the same directory and there are a total of 3 C source files as indicated by filename1/2/3 etc. I am trying to build 3 separate programs with 3 source files in a single makefile
OPT = -O4
all: filename1
filename1: filename1.o
gcc $(OPT) -o filename1 filename1.o
filename1.o: filename1.c
gcc $(OPT) -c filename1.c
filename2: filename2.o
gcc $(OPT) -o filename2 filename2.o
filename2.o: filename2.c
gcc $(OPT) -c filename2.c
filename3: filename3.o
gcc $(OPT) -o filename3 filename3.o
filename3.o: filename3.c
gcc $(OPT) -c filename3.c
clean:
rm -f *.o
rm -f filename1
rm -f filename2
rm -f filename3
Or is my code fine for what I want it to do?

Okay, so there doesn't appear to be anything wrong with the makefile, given that you're making three different programs. It should work.
Some suggestions for making it a little more usable:
1) Declare the "all" and "clean" targets to be phony. This will prevent Make from trying to make files called "all" and "clean".
.PHONY: all clean
2) You probably want your "all" target to build all three of your programs, not just one, so change that to:
all: filename1 filename2 filename3
3) If you end up using this to make more than three programs, and they all share similar build procedures, you can collapse your rules into a smaller set using pattern matches. See Martin Beckett's answer for an example. But, that's not necessary.

Your makefile should work, but it could be simplified.
The make utility supports implicit rules. This can simplify common operations, such as compiling a C source code file into an object file and compiling an object file into an executable.
CC=gcc
CFLAGS=-O4
all: filename1 filename2 filename3
%.o: %.c
$(CC) $(CFLAGS) -c $<
%: %.o
$(CC) $(CFLAGS) -o $* $<
clean:
rm -f *.o
rm -f filename1
rm -f filename2
rm -f filename3

For three separate programs built from three files like that, you could simply use:
PROGRAMS = filename1 filename2 filename3
all: ${PROGRAMS}
clean:
rm -f ${PROGRAMS} ${PROGRAMS:=.o}
You might add:
CFLAGS = -O4
to get that level of optimization. You might use a macro instead of the rm command; generally, mature makefiles use a lot of macros:
RM_F = rm -f
If you're targeting GNU Make, you could add:
.PHONY: all clean
And the list goes on.
The key point is that make knows how to build single-file programs already, and it knows how to compile C source into an object file, so you don't have to train it to do that.

Use pattern matching:
PROGS = filename1 filename2 filename3
all: $(PROGS)
# cancel implicit program rule
%: %.c
%: %.o
$(CC) $(LDFLAGS) $^ -o $#
%.o: %.c
$(CC) $(OPT) $(CFLAGS) $^ -c -o $#
clean:
rm -f $(PROGS) *.o
.PHONY: all clean

FWIW,
HTH
'A Generic Makefile for Building Multiple main() Targets in $PWD'
Makefile to compile multiple c programs?

Related

How to set up make to find the dependencies of autogenerated files that need to be compiled

I have a python script that needs to run before any other rule because it generates a few .c files that I want to compile. But there lies the problems.
In my make file I have a rule to make the depends
SRC = autogenerated_file1.c autogenerated_file2.c
depend dep: .depend
include .depend
But the problem is the files dont exist when the make file is run to make the depends, I need the python script to run first, how would I set up a rule to run before the include of the depends.
Any help would be greatly appreciated.
I simplified my makefile and provided it here:
SUBDIRS = ../modules/mod1 \
../modules/mod2 \
../modules/mod3
CFLAGS=-g -Wall
ARFLAGS=rs
CFLAGS:=$(CFLAGS) -I.
APPLICATION_FILES = main.c autogen1.c autogen2.c
APPLICATION_OBJ=$(APPLICATION_FILES:.c=.o)
-include $(APPLICATION_FILES:.c=.d)
.PHONY: dummy
dummy:
cd ../scripts && \
python autgen_files.py
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
clean :
rm -f *.o *.elf *.d
-for d in $(SUBDIRS); do (cd $$d; $(MAKE) clean ); done
%.fin: dummy $(SUBDIRS) %.elf
$(SUBDIRS):
$(MAKE) -C $#
%.d : %.c
$(CC) -MM $(CFLAGS) $*.c > $*.d
%.elf: $(APPLICATION_OBJ)
$(CC) -Tapp.ld $(CFLAGS) -o $# $^
The problem here is the autogen1.c and autogen2.c are not available at the start of make. And if I do what I provided above I get caught it a loop of recursive make.
I should say the way I start the build is "make test.fin"
If the python script generates the file .depend (that's my understanding but I'm not entirely sure), then add this rule:
.depend: script.py
$<
This way make will know that .depend is also a target that needs to be made, and will run script.py if it's newer than .depend or if .depend does not exist. Tweak to taste.
Note that this might only work with GNU Make.

Adding a library to my makefile

I have set up a makefile that takes the sources main.c, word.c, and trim.c
I also used a library which is called linkedList.a, however even after adding it it does not build as I keep getting undefined references to functions within linkedlist.
The following is my makefile code:
SHELL = /bin/sh
SRCDIR = .
CC = gcc
YACC = bison -y
CDEBUG = -g
COMPLIANCE_FLAGS =
CFLAGS = $(COMPLIANCE_FLAGS) $(CDEBUG) -I. -I$(SRCDIR)
LDFLAGS = -g
LIBRARY_FILES = linkedList.a
linkedList.a: $(LIBRARY_FILES).o
$(RM) -f $(output)
$(AR) cr $(output) $(inputs)
ranlib $(output)
############################################################################################################
# List your sources here.
SOURCES = main.c word.c trim.c
############################################################################################################
############################################################################################################
# list the name of your output program here.
EXECUTABLE = wordCounter
############################################################################################################
# Create the names of the object files (each .c file becomes a .o file)
OBJS = $(patsubst %.c, %.o, $(SOURCES))
include $(SOURCES:.c=.d)
all : $(OBJS) $(EXECUTABLE)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS)
%.o : %.c #Defines how to translate a single c file into an object file.
echo compiling $<
echo $(CC) $(CFLAGS) -c $<
$(CC) $(CFLAGS) -E $< > $<.preout
$(CC) $(CFLAGS) -S $<
$(CC) $(CFLAGS) -c $<
echo done compiling $<
%.d : %.c #Defines how to generate the dependencies for the given files. -M gcc option generates dependencies.
#set -e; rm -f $#; \
$(CC) $(COMPLIANCE_FLAGS ) -M $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
clean : # Delete any and all artifacts from the build. The only thing which is kept is the source code.
rm -f *.o
rm -f *.preout
rm -f *.s
rm -f *.S
rm -f *d
rm -f $(EXECUTABLE)
I feel I added the proper items in the proper places. My best guess is that my library_files is somehow wrong?
Your $(EXECUTABLE) rule doesn't mention the library, it just tries to link main.o, word.o and trim.o. So we must rewrite that rule.
First try this from the command line (because we can't do something with Make until we know how to do it without Make):
gcc -o wordCounter main.o word.o trim.o -L. -llinkedList
If this works, then we can write the rule:
$(EXECUTABLE) : $(OBJS) linkedList.a
$(CC) -o $# $(OBJS) -L. -llinkedList
If it doesn't, we'll have to tweak it a little. And some further refinements are possible, once we have the makefile working.
The "all:" line needs enhancement and, yes, LIBRARY_FILES needs changing/splitting. You have an OBJS variable for the executable, but nothing similar for the library. Actually, a bit more to do, as follows ...
(1) Currently, you have one library, but let's go for two:
LIBRARY_FILES += lib1.a
LIBRARY_FILES += lib2.a
(2) We now need two variables, similar to your OBJS, but one for each library:
LIBOBJS1 += abc.o def.o
LIBOBJS2 += ghi.o jkl.o
(3) We now need two rules, one for each library, similar to your rule for your library, but different [Note that most modern "ar" programs do their own ranlib--YMMV]:
lib1.a: $(LIBOBJS1)
ar crv $# $(LIBOBJS1)
lib2.a: $(LIBOBJS2)
ar crv $# $(LIBOBJS2)
(4) Now, change the rule for the executable itself:$(EXECUTABLE): $(OBJS) $(LIBRARY_FILES)
$(CC) -o $(EXECUTABLE) $(OBJS) $(LIBRARY_FILES)
(5) Now, we need to change the "all:" line. With the other rule changes, this can be simplified to:all: $(EXECUTABLE)
(6) Now add a command to the "clean:" target, either: rm -f *.a
Or: rm -f $(LIBRARY_FILES)
(7) Note that care must be taken so that LIBOBJS1/LIBOBJS2 don't overlap with SOURCES/OBJS. That is, you have to decide which sources build the libraries and which ones are strictly for the executable. I think you'll be fine on this, but I didn't see anything that spelled which .c/.o files you wanted to build your library from.
(8) All the build rules should probably be moved down the file after all the symbol definitions

Improving Makefile so it only creates and cleans programs that have been changed/specifically requested

Based on this stackoverflow response, I've created a Makefile that compiles all .c files into separate executables. I've added a clean section that removes all programs. It now looks like:
CFLAGS=-Wall -g
SRCS = $(wildcard *.c)
PROGS = $(patsubst %.c,%,$(SRCS))
all: $(PROGS)
clean:
rm -f $(PROGS)
%: %.c
$(CC) $(CFLAGS) -o $# $<
My questions are:
How would you have Makefile read additional command line arguments so that it can clean just the programs specified?
You could add a clean-% target that only cleaned specific binaries or other such games but why? Your "clean" recipe is just rm so just run rm yourself.
As to building only specific binaries just run make $binary instead of make or make all.
All make/make all is doing is running the target for each listed binary by name.

Makefiles - ar: *.a: No such file or directory.... but there is... it's right there

Trying to compile a friend's code - but he has included no Makefile, I build my own and am perplexed by an issue I've run into.
I think it's best I post the full contents of the Makefile below... I tried to keep it short!
CFLAGS = -Wall -pedantic
LFLAGS =
CC = gcc
RM = /bin/rm -rf
AR = ar rc
RANLIB = ranlib
LIBRARY = const.a read.a descr.a
LIB_SRC = read.c futex.c testy.c
LIB_OBJ = $(patsubst %.c,%.o,$(LIB_SRC))
# pattern rule for object files
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
all: $(LIBRARY)
$(LIBRARY): $(LIB_OBJ)
$(AR) $(LIBRARY) $(LIB_OBJ)
$(RANLIB) $(LIBRARY)
clean:
$(RM) $(LIBRARY) $(LIB_OBJ)
.PHONY: depend
depend:
$(CFLAGS) -- $(LIB_SRC) 2>/dev/null
All of the files, const.h, read.h, and descr.h are in the directory in which I call make. Likewise for read.c, futex.c, and testy.c.
The files are entangled in various ways - if I need to show exactly the nature of these entanglements, I will do so.
I 'make' and the compiler alledges:
ar: read.a: No such file or directory
Is it not the case that read.a is supposed to be being produced? Of course it isn't there yet.
I've stared a while now and I feel like this must be something simple I am missing.
This command:
$(AR) $(LIBRARY) $(LIB_OBJ)
expands to this:
ar rc const.a read.a descr.a read.o futex.o testy.o
So when Make tries to build const.a, it tells ar to combine several files into const.a, starting with read.a, and ar complains that there's no such file. (Whether ar could do anything useful with read.a if it did exist is immaterial.)
It's not clear how you want Make to build those libraries, but this might be a step in the right direction:
$(LIBRARY): $(LIB_OBJ)
$(AR) $# $(LIB_OBJ)
$(RANLIB) $#
The automatic variable $# expands to the name of the target. You can use another one for the list of prerequisites ($(LIB_OBJ)), but let's try one new thing at a time.

How do I make a simple makefile for gcc on Linux?

I have three files: program.c, program.h and headers.h.
program.c includes program.h and headers.h.
I need to compile this on Linux using gcc compiler. I'm not sure how to do this. Netbeans created one for me, but it's empty.
Interesting, I didn't know make would default to using the C compiler given rules regarding source files.
Anyway, a simple solution that demonstrates simple Makefile concepts would be:
HEADERS = program.h headers.h
default: program
program.o: program.c $(HEADERS)
gcc -c program.c -o program.o
program: program.o
gcc program.o -o program
clean:
-rm -f program.o
-rm -f program
(bear in mind that make requires tab instead of space indentation, so be sure to fix that when copying)
However, to support more C files, you'd have to make new rules for each of them. Thus, to improve:
HEADERS = program.h headers.h
OBJECTS = program.o
default: program
%.o: %.c $(HEADERS)
gcc -c $< -o $#
program: $(OBJECTS)
gcc $(OBJECTS) -o $#
clean:
-rm -f $(OBJECTS)
-rm -f program
I tried to make this as simple as possible by omitting variables like $(CC) and $(CFLAGS) that are usually seen in makefiles. If you're interested in figuring that out, I hope I've given you a good start on that.
Here's the Makefile I like to use for C source. Feel free to use it:
TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
It uses the wildcard and patsubst features of the make utility to automatically include .c and .h files in the current directory, meaning when you add new code files to your directory, you won't have to update the Makefile. However, if you want to change the name of the generated executable, libraries, or compiler flags, you can just modify the variables.
In either case, don't use autoconf, please. I'm begging you! :)
For example this simple Makefile should be sufficient:
CC=gcc
CFLAGS=-Wall
all: program
program: program.o
program.o: program.c program.h headers.h
clean:
rm -f program program.o
run: program
./program
Note there must be <tab> on the next line after clean and run, not spaces.
UPDATE Comments below applied
all: program
program.o: program.h headers.h
is enough. the rest is implicit
The simplest make file can be
all : test
test : test.o
gcc -o test test.o
test.o : test.c
gcc -c test.c
clean :
rm test *.o
Depending on the number of headers and your development habits, you may want to investigate gccmakedep. This program examines your current directory and adds to the end of the makefile the header dependencies for each .c/cpp file. This is overkill when you have 2 headers and one program file. However, if you have 5+ little test programs and you are editing one of 10 headers, you can then trust make to rebuild exactly those programs which were changed by your modifications.

Resources