Compile multiple .c files with makefile - c

I would like to compile multiple .c files at once using a makefile.
I already made this:
CC= gcc
CPPFLAGS = -I.
CFLAGS = -W -Wall -ansi -pedantic
TARGET = test
RM = rm
OBJECTS = xxx.o yyy.o zzz.o
SOURCES = $(OBJECTS:.o =.c)
.PHONY: all clean
all: $(TAREGT)
clean:
$(RM) $(TARGET) $(OBJECTS)
$(TAREGT) : $(OBJECTS)
$(CC) $^ -o $#
$(OBJECTS) : $(SOURCES)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $^
I have no Idea why this does not work("nothing to be done for "all"). Someone has an idea?

This line is creating a circular dependency:
SOURCES = $(OBJECTS:.o =.c)
Try replacing it with this:
SOURCES = $(patsubst %.o,%.c,$(OBJECTS))

You forgot -o $# in your 'sources to objects' rule. Thus it doesn't create anything.
You have also spelling error - your $(TARGET) is 'test', but your 'all' rule depends on $(TAREGT) which is empty. You are also using $(TAREGT) as input to compile 'test'.
You don't need to specify $(SOURCES) or "sources to objects" rule - implicit rules will do the trick.
In fact your "sources to objects" rule is incorrect - it says that each object depends on all sources. If you want each object to depend on one source you should use either suffix rule, pattern rule or static pattern rule. Or just implicit rule.

$(OBJECTS) : $(SOURCES)
The above tells Make that every .o file depends on all sources, i.e. if you change one of your .c files Make will recompile all .o files. Not something what you really want, I guess. I'd rework this rule as follows:
$(foreach s,$(SOURCES),$(eval $(filter %$(basename $(notdir $s)).o,$(OBJECTS)): $s))
This will iterate every source in SOURCES, find corresponding .o file in OBJECTS and create correct rule: <obj>: <source>. It is that complicated to work in case of more complex mapping between source and object files. Say, when building object files in separate directory.
This cryptic code will work even for the following weird source to object file mapping:
SOURCES := a.cpp boo/b.c c.C
OBJECTS := foo/a.o bar/b.o c.o
$(foreach s,$(SOURCES),$(eval $(filter %$(basename $(notdir $s)).o,$(OBJECTS)): $s))
It will generate the following rules:
foo/a.o: a.cpp
bar/b.o: boo/b.c
c.o: c.C

Thank you guys for you help, it is working now
I just added some rules:
CC= gcc
CPPFLAGS = -I.
CFLAGS = -W -Wall -ansi -pedantic
TARGET = test
RM = rm
SOURCES = xxx.c yyy.c zzz.c
OBJECTS = $(SOURCES:.c=.o)
.PHONY: all clean
all: $(TARGET)
clean:
$(RM) $(TARGET) $(OBJECTS)
$(TARGET) : $(OBJECTS)
$(CC) $^ -o $#
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<

Related

How can I improve this Makefile to optimize the usage of the SRC and BIN folders?

This is my first attempt at making a Makefile after having gone through several tutorials and the gnu make manual. The Makefile works and creates the .o, .a and .exe files in the BIN folder. However, I have have added src\ and bin\ prefixes to all files. I know there must be a better way of addressing folder issues while using Makefiles. Only problem is, I am unable to figure it out after hours of editing and trying out different things, based on the tutorials. I find GNU make manual too overwhelming at this stage of my learning curve.
I am using MinGW GCC toolchain on Windows 7. I have copied mingw32-make.exe to make.exe for the purpose of trying out the tutorials and exampples I have been going through.
I would really appreciate any help on the subject. Thank you.
My Makefile is as follows:
CC = gcc
CFLAGS = -O3 -Wall -c
BIN = bin/
LDFLAGS = -L$(BIN) -lmyLib
all: test.exe
test.exe: test.o libmyLib.a
gcc bin\test.o -o bin\test.exe $(LDFLAGS)
test.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\test.o src\test.c
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
clean:
del bin\*.* /Q
First, there are some issues with your Makefile, even if it apparently works. When you write:
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
you are lying to make:
You tell it that the result of the rule is myLib.o while it is bin\myLib.o, that is, a different file.
You tell make that myLib.o depends on src\test.c while it in fact depends on src\myLib.c.
Same with your other rules as in:
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
You tell make that the rule shall be executed if myLib.o is newer than libmyLib.a while the real prerequisite is bin\myLib.o and the real target is bin\libmyLib.a.
By doing so you totally prevent make from doing what it is supposed to do: decide if a recipe must be executed or not, depending on the last modification times of target files and prerequisite files. Give it a try: run make twice and you'll see that it uselessly redoes what it did already. Never, never lie to make.
Second, you can improve your Makefile by using several advanced features like automatic ($#, $<, $^), standard (LDLIBS, AR, ARFLAGS) and regular (BIN, SRC) make variables. Here is an example of what you could try, after fixing the above mentioned issues and better using variables (plus adding the missing -I gcc option, and declaring all and clean as phony because these targets are not real files and we do not want to lie to make):
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/test.o: $(SRC)/test.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
$(BIN)/myLib.o: $(SRC)/myLib.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
clean:
del $(BIN)\*.* /Q
Now, all non-phony targets and prerequisites are regular files, the ones that are really involved in the rules. Again, give it a try and you'll see that make rebuilds only what is out of date and thus needs to be rebuilt.
If you want to get rid of the $(SRC)/ prefix you can use the vpath directive that tells make where to look for source files (I insist on source, many people try to use it for target files, this is not what it is intended for):
vpath %.h $(SRC)
vpath %.c $(SRC)
And then:
$(BIN)/test.o: test.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/myLib.o: myLib.c myLib.h
$(CC) $(CFLAGS) -o $# $<
Note: you could also use the VPATH variable instead of the vpath directive.
Pattern rules are used to factor similar rules, like, for instance, your compilation rules that differ only by the names of the source file and object file:
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
All in all:
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
clean:
del $(BIN)\*.* /Q
Finally, if you really want to avoid the $(BIN)/ prefix in your rules you will have to move to the $(BIN) directory and call make from there. You can leave the Makefile in the main directory and use the -f ../Makefile option, if you wish.
But of course this is less convenient that just typing make [goals] from the main directory. There are ways to let make test from where it has been called, and if it is not from the build directory, re-call itself with the -C and -f options such that it does its job from the build directory. But it is probably a bit too complicated if you are new to make.
If you are however interested have a look at this post that covers this topic (and more). If we simplify as much as possible what the post suggests and specialize it for your case, the final Makefile could be something like:
# here starts the black magic that makes it possible
.SUFFIXES:
BIN := bin
SRC := src
ifneq ($(notdir $(CURDIR)),$(BIN))
.PHONY: $(BIN) clean
$(BIN):
#$(MAKE) --no-print-directory -C $# -f ../Makefile SRC=$(CURDIR)/$(SRC) $(MAKECMDGOALS)
Makefile: ;
% :: $(BIN) ; :
clean:
del $(BIN)\*.* /Q
else
# here ends the black magic that makes it possible
# here starts the Makefile you would really like to write
CC := gcc
CFLAGS := -O3 -Wall -c -I$(SRC)
LDFLAGS := -L.
LDLIBS := -lmyLib
AR := ar
ARFLAGS := rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all
all: test.exe
test.exe: test.o libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
libmyLib.a: myLib.o
$(AR) $(ARFLAGS) $# $^
# here ends the Makefile you would really like to write
# a last bit of black magic
endif
The Makefile you would really like to write is what you would write if your source files and target files were all in the source directory. No prefixes any more; vpath takes care of the $(SRC)/ prefix and $(BIN)/ is useless because when this part of the Makefile is used we are already inside $(BIN).
Note: I know nothing about Windows and its various command line interfaces so there are probably some things to adapt (backslashes instead of slashes for instance).

Makefile executes the command only once

I am using the Makefile of MinGW (Windows 8.1, GCC 7.3.0) to build a medium-sized project automatically detecting all source files under the folder src and compiling all object files into the obj folder, but unfortunately it is only executing the command over the first detected file and stops there.
This is the first time I write a Makefile script for anything beyond one source file and maybe I am getting some rule wrongly. Thanks in advance!
CC := gcc
SRC := src
OBJ := obj
MAIN := main
PACK := libbundle
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o, $(SOURCES))
CFLAGS := -I$(SRC)
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
# build:
# ar rcs $(PACK).a $(OBJECTS)
# $(CC) -shared -o $(PACK).so $(OBJECTS)
# $(CC) -o $(MAIN).c $(PACK).so
Output:
gcc -Isrc -c src/firstsource.c -o obj/firstsource.o
...and stops there!
Problem - rule with multiple targets
Your rule
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
has multiple targets. I don't believe this is appropriate here. See discussion here of where rules with multiple targets are useful.
Also, this rule specifies multiple prerequisites - but $< represents only the first prerequisite. You can use $+ to capture all prerequisites - but then you lose the ability to use the -o option. See below if you want to use multiple prerequisites.
What $(OBJECTS): $(SOURCES) means in detail
Suppose, for example, that your src/ directory contains firstsource.c and secondsource.c. Then your variables become
$(SOURCES) -> src/firstsource.c src/secondsource.c
$(OBJECTS) -> obj/firstsource.o obj/secondsource.o
(Actually - and somewhat non-intuitively - firstsource will be placed after secondsource, but let's ignore that for simplicity's sake.)
So the rule
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
is equivalent to
obj/firstsource.o obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
This rule, in turn, is equivalent to two rules (since it has multiple targets) - each with the same prerequisites:
obj/firstsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
Can you see the problem here?
Since $< represents only the first prerequisite, the recipe for the first rule becomes
gcc -Isrc -c src/firstsource.c -o obj/firstsource.o
which is fine for the first rule, but for the second rule it won't work
gcc -Isrc -c src/firstsource.c -o obj/secondsource.o
because you are using the wrong input file.
By the way ... You mentioned that
unfortunately it [i.e. make] is only executing the command over the first detected file and stops there.
This is because - when you invoke make without any arguments - it calls the first rule in the file and no more.
Option 1: Use multiple rules
What is more suitable here are multiple rules - each with only a single target. So try replacing the above with the following.
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -c $< -o $#
compile-only: $(OBJECTS)
You could invoke make on this modified Makefile as
make -B compile-only
Option 2: Single target with multiple prerequisites
If you have multiple prerequisites in your target, you can refer to them in your recipe using the special variable $+. However, you can not use the -o option in this case - so will not be able to specify the output directory for the object files. (To work around this, you could cd to the obj directory before compiling - but then you will need to tweak the SOURCES variable.)
CC := gcc
CFLAGS := -Isrc
SRC := src
SOURCES := $(wildcard $(SRC)/*.c)
myobjs: $(SOURCES)
$(CC) $(CFLAGS) -c $+
This will place all the object files in the top-level directory. As mentioned, you can tweak SOURCES and cd the obj directory if you must place the object files in a separate directory.
Aside - pre-defined recipes for pattern rules
I understand the rationale in placing the build output in a separate directory as you have done, but - if you were willing to place the build output in the same directory as the source files - you could simplify your Makefile using make's predefined pattern rules.
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(SOURCES:.c=.o)
compile: $(OBJECTS)
You should use standard targets in your Makefile, the most important one being "all". And it should be the first target in the Makefile so that make and make all do the same thing.
all: $(OBJECTS)
With $(OBJECTS): $(SOURCES) you are telling make that each file in $(OBJECTS) depends on every file in $(SOURCES) and will execute the commands below as any of the objects fails the test of being newer than any of the sources. The command will be executed only once and stop.
What you need is to specify that each object file depends on its correspondient source file. As I see you are using GMAKE syntax, I'll show you the GNU make syntax for such a rule:
$(OBJECTS): obj/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $#
this is as if you had a rule for each .o file that says how to compile it from its proper source file.
you will also need to say which files are your default targets, with something like:
.PHONY: all
all: $(OBJECTS)
clean:
$(RM) $(TOCLEAN)
put that rule the first one, so it will be selected by default.
This will make all your default target. It will explode into all your object files, and for each object you have a rule that says how to compile it (not neccessary, as gnu make already know how to compile a C program, but repeating it here doesn't hurt)
your final Makefile is:
CC := gcc
SRC := src
OBJ := obj
MAIN := main
PACK := libbundle
CFLAGS := -I$(SRC)
PICFLAGS := -fPIC
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
TOCLEAN += $(OBJECTS)
PICOBJECTS := $(patsubst $(OBJ)/%.o, $(OBJ)/%.pic, $(OBJECTS))
TOCLEAN += $(PICOBJECTS)
.PHONY: all
.SUFFIXES: .c .o .pic
all: $(PACK).a $(MAIN)
clean:
$(RM) $(TOCLEAN)
$(MAIN): $(MAIN).o $(PACK).so
$(CC) $(LDFLAGS) -o $# $+
TOCLEAN += $(MAIN)
$(PACK).a: $(OBJECTS)
ar r $(PACK).a $(OBJECTS)
TOCLEAN += $(PACK).a
$(PACK).so: $(PICOBJECTS)
$(LD) $(LDFLAGS) -shared -o $(PACK).so $(PICOBJECTS)
TOCLEAN += $(PACK).so
# this to create a normal .o file in $(OBJ) directory.
$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -o $# -c $<
# this to create a PIC (Position Independent Code) .pic object in $(OBJ) directory.
# (REQUIRED FOR .so SHARED OBJECT)
$(PICOBJECTS): $(OBJ)/%.pic: $(SRC)/%.c
$(CC) $(CFLAGS) $(PICFLAGS) -o $# -c $<

How to create reference to an .o file in Makefile

I was given two .o files with corresponding .h files to use for an assignment, but I do not know how to get the compiler to use the .o files. This is the Makefile I am currently using:
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)
I believe I need to add the file1.o and file2.o at the end, but I am not sure if that is right. I do have the .h files in the C source files when appropriate, so the only reason that I can think of for the compilation error is that the .o files are not being compiled with my code.
Add a define for the provided .o's (e.g.):
PREBUILT_O = fludger.o ramble.o plexor.o
Change your target rule to:
$(TARGET): $(OBJECTS) $(PREBUILT_O)
$(CC) $(OBJECTS) $(PREBUILT_O) $(LIBS) -o $#
The compiler doesn't use your .o files. The linker does.
Your link step needs to be
$(TARGET) : $(OBJECTS)
$(LD) $(OBJECTS) $(LIBS) -o $#
(Very possibly missing some other linker flags, but that's the crux of your problem)
Also, you probably don't want the clean step to delete all the .o files since you're provided with at least two of them.

I need some assistance with Makefile in my project

I'm trying to make a Makefile but I'm having some problems
first I have
2 source files: ~/main.c ~/lib/library.c
1 header file: ~/include/library.h
main.c and library.c both share the same header file library.h
# Compiler options
CC = gcc
INC = -I../include
CFLAGS = -Wall -g -c $(INC)
LIB = -L../lib
LFLAGS = -Wall -g $(LIB)
# Dependencies
LIBS = -libmylib
OBJS = main.o
SRCS = $(OBJS:.o=.c)
EXEC = a.out
# Other rules
RM = rm -rf
TAGS = tags
BAK = Makefile.bak
all: $(EXEC)
#echo ------------------------ Compile Complete ----------------------------
.PHONY: clean depend
$(EXEC): $(OBJS)
$(CC) $(LFLAGS) -o $# $^ $(LIBS)
.c.o:
$(CC) $(INC) -M $^
$(CC) $(CFLAGS) -o $# $<
clean:
$(RM) *.o *~ $(EXEC) $(TAGS) $(BAK)
depend: $(SRCS)
makedepend $(INC) $^
it keeps saying that I it can't make a rule out of library.o
plus I have another question
I acknowledge the fact that when Makefile comes in to action after calling 'make',
and subsequently go to the line .c.o or %c: %o(in GNU enhanced version) and make
.o files. but why doesn't it also call clean and depend automatically?
I've edited some things from the previous version of Makefile
this time, (well pretty similar to the previous problem) even though I
clarified the library path(-I../lib),
the Makefile cannot find the archive file (which I created as libmylib.a in ../lib dir)
now it's driving me crazy
but why doesn't it also call clean and depend automatically?
Because make only builds the target you tell it. If you don't specify one, the first target is built, which in many cases, such as yours, is the 'all' target.

How to use makefile to compile all sources (some only to object files)?

I'm getting an "undefined reference to main" error on one of my files when trying to compile. I know this is because this file doesn't have a main method. This is just an implementation file for some helper methods, so I only want it compiled to an object file not an executable. I know how to do this if I explicitly tell the makefile what to do for each file, but I'm trying to write a makefile that will compile all of my sources at once. I tried using the -c flag, but then it compiled all of my files to only object files rather than executables. How in the world do I do this?
Here it is:
CC = gcc
CFLAGS = -g -Wall
SRCS = ./src/server.c ./src/client_slave.c ./src/sockaddrAL.c
EXECS = ./bin/server ./bin/client_slave
OBJS = $(SRCS:.c=.o)
all: clean $(SRCS) server client
server: $(OBJS)
$(CC) $(CFLAGS) ./src/server.o -o ./bin/server
client: $(OBJS)
$(CC) $(CFLAGS) ./src/client_slave.o -o ./bin/client_slave
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You should add the -c flag to the rule that builds .o files (your .c.o suffix rule) and not add it to the rule that builds the executables (the $(EXECS) rule).
CC = gcc
CFLAGS = -g -Wall
EXECS = ./bin/server ./bin/client_slave
all: $(EXECS)
./bin/%: ./src/%.o ./src/sockaddrAL.o
$(CC) $(CFLAGS) -o $# $^
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You didn't show sockAddrAL at all in your question so I assumed it belonged in both executables. Also note that the above syntax assumes GNU make. If you want to use only features available in POSIX standard make you pretty much have to write it all out.
Let implicit rules be your friend. Your entire Makfefile should just be:
CC = clang
CFLAGS = -O0 -g -Wall
SRCS = server.c client_slave.c sockaddrAL.c
OBJS = $(SRCS:.c=.o)
EXECS = server
server: $(OBJS)
clean:
#rm -f $(EXECS) $(OBJS)
Invoke it from the src directory.

Resources