I've recently picked up makefiles and am trying to automate my build process. For this makefile, I want it to find every xxx/src/xxx.c source file and build an equivalent xxx/obj/xxx.o object for each. So every obj folder mirrors the layout of a src folder.
This is working as intended but only if I clean and make. Modifying a source file and running make won't rebuild that file. I think it might have to do with my subst in the dependecy of %.o, but I don't know how to modify that and still have my automated build layout work.
CFLAGS := -std=c11 -pedantic -Wall -Wextra -O3
LIBARIES := -lm -lglut -lGL
INCDIR := include ../plib/include
SRCDIR := src ../plib/src
INC := $(foreach d, $(INCDIR),-I$d)
SRC := $(wildcard $(foreach d, $(SRCDIR),$d/*.c $d/*/*.c))
OBJ := $(subst src/,obj/, $(SRC:.c=.o))
EXE := bin/test
$(EXE): $(OBJ)
gcc -o $# $(OBJ) $(LIBARIES)
$#
%.o: $(subst obj/,src/,$(%.c))
#mkdir -p $(#D)
gcc -o $# -c $(subst obj/,src/,$(#:.o=.c)) $(CFLAGS) $(INC)
.PHONY: clean
clean:
rm $(EXE)
rm $(OBJ)
You can solve such a %/xxxx/% pattern replacement by iterating over the SRCDIR:
define genrule
_prefix := $$(subst src,obj,$1/)
$$(filter $${_prefix}%.o,$$(OBJ)):\
$${_prefix}%.o: $1/%.c
endef
$(foreach d,${SRCDIR},$(eval $(call genrule,$d)))
${OBJ}:
gcc ... -c $< -p $#
You can do it with secondary expansion. It's not elegant, but it works:
.SECONDEXPANSION:
%.o: $$(addsuffix .c,$$(basename $$(subst /obj/,/src/,$$#)))
#echo building $# from $^
#mkdir -p $(#D)
gcc -o $# -c $< $(CFLAGS) $(INC)
The posted makefile is rather 'iffy' for several different reasons
The following proposed makefile is VERY EASILY modified for other projects BUT does place the object files in the same directory as the source files. You might want to 'tweak' that feature
And now, the proposed makefile
SHELL := /bin/sh
CC := /usr/bin/gcc
RM := /usr/bin/rm
MAKE := /usr/bin/make
CFLAGS := -std=c11 -pedantic -Wall -Wextra -O3
LIBS := -lm -lglut -lGL
INC := -Iinclude/ -I../plib/
SRC := $(wildcard src/*.c) $(wildcard ../plib/src/*.c)
OBJ := $(SRC:.c=.o))
DEP := $(SRC:.c=.d)
EXE := bin/test
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ)
#
# ======= $(EXE) Link Start =========
$(CC) $(LDFLAGS) -o $# $(OBJ) $(LIBS)
# ======= $(EXE) Link Done ==========
#
#
# create dependancy files
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
(RM) -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c files into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CFLAGS) -c $< -o $# $(INC)
# ========= END $< TO $# =========
#
clean:
# ========== start clean activities ==========
rm -f *.o
rm -f $(EXE)
rm -f *.d
# ========== end clean activities ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
Related
I'm trying to create a generic Makefile to use with most of my projects. It should work as follows: only rebuild and link those .o files whose .c or .h dependency has changed. The .o and .d files are stored in a separate directory called 'build'.
With the help of the official GNU Make manual and some googling I've managed to achieve the desired behavior except for one thing: when I run make re I get the error:
Assembler messages: Fatal error: can't create build/ft_build_buffer.o: No such file or directory — the reason for this is that the 'build' directory only gets created whenever the .d files are generated, but for some reason the re rule simply skips this step and goes on to compile .o files straight away! Note: if I run make clean && make fclean && make all (which should be the exact same thing) everything works fine.
A few other things: I've tried using the -MMD option to generate dependencies on the fly but on my machine that causes the .d files to only contain .c dependencies. Of course I could just make all .c files depend on all .h files but that seems like a very sloppy solution.
Feel free to share any other advice/improvements that will make this file more clean and readable, thanks! :)
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) -c $(SRC_DIR)/$*.c -o $#
$(BUILD_DIR)/%.d: $(SRC_DIR)/%.c
#mkdir -p $(#D)
#set -e; rm -f $#; \
$(CC) $(CFLAGS) $(INCLUDE) -MM $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re: fclean all
Here is the modified working version as suggested by #M.M
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -MMD -c $(SRC_DIR)/$*.c -o $#
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re:
$(MAKE) fclean
$(MAKE) all
I am running Ubuntu 18.0.4 virtual machine using Vagrant and Virtualbox. I am writing a C program to manage virtual memory on said machine, which consists of many C and header files. Every time I run make while in my virtual machine, I get this error:
make[1]: Entering directory '/vagrant'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In
function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:45: recipe for target 'vm-sim' failed
make[1]: *** [vm-sim] Error 1
make[1]: Leaving directory '/vagrant'
Makefile:23: recipe for target 'all' failed
make: *** [all] Error 2
Here is my Makefile:
TARGET = vm-sim
CC = gcc
CFLAGS = -Wall -Wextra -Wsign-conversion -Wpointer-arith -Wcast-qual -
Wwrite-strings -Wshadow -Wmissing-prototypes -Wpedantic -Wwrite-strings -g -
std=gnu99 -lm
LFLAGS =
SRCDIR = *-src
INCDIR = $(SRCDIR)
BINDIR = .
SUBMIT_FILES = $(SRC) $(INC) Makefile
SUBMISSION_NAME = project3-vm
SRC := $(wildcard $(SRCDIR)/*.c)
INC := $(wildcard $(INCDIR)/*.h)
INCFLAGS := $(patsubst %/,-I%,$(dir $(wildcard $(INCDIR)/.)))
.PHONY: all
all:
#$(MAKE) release && \
echo "$$(tput setaf 3)$$(tput bold)Note:$$(tput sgr0) this project compiled
with release flags by default. To compile for debugging, please use $$(tput
setaf 6)$$(tput bold)make debug$$(tput sgr0)."
.PHONY: debug
debug: CFLAGS += -ggdb -g3 -DDEBUG
debug: $(BINDIR)/$(TARGET)
.PHONY: release
release: CFLAGS += -mtune=native -O2
release: $(BINDIR)/$(TARGET)
.PHONY: clean
clean:
#rm -f $(BINDIR)/$(TARGET)
#rm -rf $(BINDIR)/$(TARGET).dSYM
.PHONY: submit
submit:
#(tar zcfh $(SUBMISSION_NAME).tar.gz $(SUBMIT_FILES) && \
echo "Created submission archive $$(tput
bold)$(SUBMISSION_NAME).tar.gz$$(tput sgr0).")
$(BINDIR)/$(TARGET): $(SRC) $(INC)
#mkdir -p $(BINDIR)
#$(CC) $(CFLAGS) $(INCFLAGS) $(SRC) -o $# $(LFLAGS)
I only have one main() function defined, but previously defined a different one in another file; I think this may be the issue but don't know how to fix it.
the following makefile:
is not for your specific directory layout
shows a good (but not great) way to write the makefile
shows one method for creating dependency files (however, gcc can be used directly to produce those files
is written for a linux OS
this is a generic make file, where the when the make is invoked, needs the parameter: -D name=executablename
and now, the makefile:
SHELL = /bin/sh
BINDIR := /home/user/bin
.PHONY: all
all : $(BINDIR)/$(name)
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -Wextra -pedantic -Wconversion -std=gnu11
LIBS := -lssl -ldl -lrt -lz -lc -lm
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ)
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $# $(OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
#
# ======= $(name) Copy Start =========
sudo $(CP) $(name) $(BINDIR)/.
# ======= $(name) Copy Done ==========
#
#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I.
# ========= END $< TO $# =========
#
.PHONY: clean
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
Need help in writing a Makefile for below source tree.
I have tried out simple examples for Makefile and those worked fine. But not able to figure out how do I write a Makefile for below kind of source tree.
I am organizing my code as below
root_dir:
Makefile
component1:
dir1:
file1.c file1.h
dir2:
file2.c file2.h
dir3:
file3.c file3.h
component2:
dir4:
file4.c file4.h
dir5:
file5.c file5.h
common:
debug.c debug.h
utils.c utils.h
main.c main.h
Here, main.c uses some functions declared in debug.h, utils.h, file1.h and file4.h. These file1.c and file4.c use the debug.h and utils.h. I have started writing the Makefile rules as below.
CC=gcc
CFlags=-c -g3 -Wall
myexec: main.o
$(CC) main.o -o myexec
main.o: common/main.c common/main.h common/utils.h
$(CC) $(CFLAGS) common/main.c
This Makefile gives "undefined reference" error messages for the functions declared in utils.h. It can crib about the functions declared in debug.h, file1.h or file4.h, but shouldn't have given the error message for functions from utils.h
Please help me in finding out what is wrong with the Makefile here.
First let's fix the main.o rule:
main.o: common/main.c common/main.h common/utils.h
$(CC) $(CFLAGS) common/main.c
If, as you say main.c uses some functions declared in debug.h, utils.h, file1.h and file4.h, then those headers should be prerequisites of the rule (so that if you modify a header, Make will rebuild main.o):
main.o: common/main.c common/main.h common/debug.h common/utils.h component1/dir1/file1.h component2/dir4/file4.h
$(CC) $(CFLAGS) common/main.c
Now look at the myexec rule:
myexec: main.o
$(CC) main.o -o myexec
It's no surprise that you get "undefined reference" errors; the functions declared in debug.h, utils.h, file1.h and file4.h are defined in (I presume) debug.c, utils.c, file1.c and file4.c, which this makefile never mentions. Do not proceed until you understand this.
The way to handle this is tho have the myexec rule link all of the relevant object files:
myexec: main.o debug.o utils.o file1.o file4.o
$(CC) main.o debug.o utils.o file1.o file4.o -o myexec
Naturally you must have rules for debug.o, utils.o, file1.o and file4.o, similar to the one for main.o.
Once that is done, you have a makefile that works but is needlessly long and redundant. "Effective but crude". It can be made much shorter and more elegant, but this answer is getting long; just get it working, then we can work on making it cleaner.
here is a long example: it is for a linux embedded system, but will work with only minor changes for your application
These two makefiles will create an executable in each sub directory
it has a directory tree something like the following:
top
utility .h and .c files
makefile.top
makefile.bot
/executable1
exec1 .h and .c files
/executable2
exec2 .h and .c files
contents of makefile.mak
SHELL = /bin/sh
# note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib -L/usr/lib -L/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -Wextra -pedantic
#CPPFLAGS += =MD
LIBS := -lssl -ldl -lrt -lz -lc -lm
.PHONY: AllDirectories
AllDirectories := \
executable1 \
executable2
.PHONY: all
all: $(OBJ) $(AllDirectories)
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )
#
# create dependancy files
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I.
# ========= END $< TO $# =========
#
.PHONY: clean
#clean: $(AllDirectories)
# # ========== start clean activities ==========
# rm -f *.o
# rm -f $(name).map
# rm -f $(name)
# rm -f *.d
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end clean activities ==========
clean: $(AllDirectories)
# ========== start clean activities ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
rm -f ../bin/Tsk_*
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
# ========== end clean activities ==========
.PHONY: install
#install: $(AllDirectories)
# # ========== start install activities ==========
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end install activities ==========
install: $(AllDirectories)
# ========== start install activities ==========
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
# ========== end install activities ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
and the makefile.bot
SHELL = /bin/sh
BINDIR := /home/user/bin
.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot
#
# macro of all *.c files
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -Wextra -pedantic -std=c99
#CPPFLAGS += =MD
LIBS := -lssl -ldl -lrt -lz -lc -lm
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $# $(OBJ) $(COMMON_OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
#
# ======= $(name) Copy Start =========
sudo $(CP) $(name) $(BINDIR)/.
# ======= $(name) Copy Done ==========
#
#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I.
# ========= END $< TO $# =========
#
.PHONY: clean
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
.PHONY: install
install: all
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
I am trying to use the mongo C driver in a Trivia server program I am making to use it to track login information scores etc.
It took me a decent amount of time to figure out how to compile the stuff in a makefile but I was able to include mongoc.h so things like mongoc_client work fine. As soon as I try to actually use a function though, such as mongoc_init I get
> undefined reference to `mongoc_init'
I feel like things should be linked though since the mongoc.h include all other header files and it looks like it is linking properly. Here is my makefile - I'm not sure what to do or even what information to provide to solve this issue.
client:
make -f makefile.client
server:
make -f makefile.server
clean:
rm -f *~ *.o tserve core tclient core *.tar *.zip *.gzip *.bzip *.gz
^ Makefile
C = gcc
CFLAGS = -g -Wall
LDFLAGS = -lpthread
INFO = -L/usr/local/lib -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0 -lmongoc-1.0 -lbson-1.0
all: tserve
csapp.o: csapp.c csapp.h
$(CC) $(CFLAGS) -c csapp.c
tserve.o: tserve.c readq.h csapp.h
$(CC) $(CFLAGS) -c tserve.c $(INFO)
readq.o: readq.c readq.h csapp.h
$(CC) $(CFLAGS) -c readq.c
tserve: tserve.o readq.o csapp.o
^ makefile.server
C = gcc
CFLAGS = -g -Wall
LDFLAGS = -lpthread
all: tclient
csapp.o: csapp.c csapp.h
$(CC) $(CFLAGS) -c csapp.c
tclient.o: tclient.c csapp.h
$(CC) $(CFLAGS) -c tclient.c
tclient: tclient.o csapp.o
^ makefile.client
If it is worth noting - the system is question had the driver installed using the following code
system("wget https://github.com/mongodb/mongo-c-driver/releases/download/1.0.2/mongo-c-driver-1.0.2.tar.gz");
system("tar -xzf mongo-c-driver-1.0.2.tar.gz");
system("rm mongo-c-driver-1.0.2.tar.gz");
if (chdir("mongo-c-driver-1.0.2"))
perror("error:");
system("./configure --prefix=/usr --libdir=/usr/lib64");
system("make");
system("sudo make install");
the code is also at https://www.github.com/decix/TriviaServer
the following file is expected to be named Makefile.mak
# note: with very minor changes this should work for most C projects
# irregardless of the OS being used
SHELL := /bin/sh
.PHONY: all clean
#
# macro for all *.c files
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
CC := /usr/bin/gcc
MAKE := /usr/bin/make
name := tserve
CFLAGS := -c -g -std=c11 -Wall -Wextra -pedantic-errors
#CPPFLAGS += =MD
# when #(DEBUG) is used in the compile/link steps,
# them max info for the gdb debugger is generated
DEBUG := -ggdb3
LDFLAGS := -L/lib -L/usr/lib -L/usr/local/lib
LIBS := -lpthread -lmongoc-1.0 -lbson-1.0
INC := -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0
name := tserve
all: $(name)
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ)
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $# $(OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
#
#create dependancy files
# -- inference rule
#
%.d: %.c Makefile.mak
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I. $(INC)
# ========= END $< TO $# =========
#
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
You only use the INFO variable, which contains -lmongoc-1.0 -lbson-1.0 (which is what you need), to build tserve.o. In this build step, the linker is not involved, so the -l options are not evaluated and don't do anything. Instead, you need to specify them when you build tserve.
You could solve this by supplying a recipe for tserve that does this, such as
tserve: tserve.o readq.o csapp.o
$(CC) $(LDFLAGS) $(INFO) -o $# $+
...but it would be better, in my opinion, to split INFO and put the parts into the variables that the predefined rules use for the relevant purposes. Then your whole Makefile could be replaced with
# C compiler
CC = gcc
# C compiler flags
CFLAGS = -g -Wall
# C preprocessor flags
CPPFLAGS = -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0 -pthread
# Linker flags
LDFLAGS = -L/usr/local/lib -pthread
# Libraries
LDLIBS = -lmongoc-1.0 -lbson-1.0
all: tserve
csapp.o: csapp.c csapp.h
tserve.o: tserve.c readq.h csapp.h
readq.o: readq.c readq.h csapp.h
tserve: tserve.o readq.o csapp.o
The .o files will then be built through implicit rules that generate them from corresponding .c files and use CPPFLAGS and CFLAGS, saving you the trouble of specifying the recipes explicitly -- the rules only exist to track dependencies -- and the linking step uses an implicit rule that uses LDFLAGS and LDLIBS. Note that I supplied -pthread in both CPPFLAGS and LDFLAGS because it is relevant for both the preprocessor and the linker.
For further information, see the bit about implicit rules in the GNU make manual, and speaking of dependency tracking, you may find this article about automating it enlightening.
I have the following makefile
# project name (generate executable with this name)
TARGET = tp3
CC = gcc -std=c99 -c
# compiling flags here
CFLAGS = -Wall -I. -Werror-implicit-function-declaration
LINKER = gcc -o
# linking flags here
LFLAGS = -Wall
# debug flags here
DFLAGS = -g -DDEBUG
SOURCES := $(shell find . -type f -name '*.c')
INCLUDES := $(shell find . -type f -name '*.h')
OBJECTS := $(SOURCES:.c=.o)
rm = rm -rf
$(TARGET): obj
#$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
obj: $(SOURCES) $(INCLUDES)
#$(CC) $(CFLAGS) -DNDEBUG $(SOURCES)
#echo "Compilation complete!"
#debug:
# gcc $(DFLAGS) $(SOURCES) -o $(TARGET)
dobj: $(SOURCES) $(INCLUDES)
#$(CC) $(CFLAGS) $(DFLAGS) $(SOURCES)
#echo "dlinking complete!"
debug: dobj
#$(LINKER) $(TARGET) $(LFLAGS) $(DFLAGS) $(OBJECTS) -o $(TARGET)
#echo "dcompilation complete!"
run:
./tp3
clean:
#$(rm) $(TARGET) $(OBJECTS) *.dSYM
#echo "Cleanup complete!"
Problem is: I have files inside the folder CMM/CMM and OBJECTS assumes the objects to also be in the CMM/CMM folder, but the compiler is putting them in the root folder. How can I either get the compiler to compile the .o files in CMM/CMM or tell the pattern replacer OBJECTS := $(SOURCES:.c=.o) that everything is in the root folder?
Your real problem here is that you're not using the tools make provides you to simplify your task.
Also, your compiler is putting all the .o files in the root folder because you didn't tell him not to do so, or let make do that for you.
Here is the working Makefile:
EXE := tp3
SRC := $(shell find . -type f -name '*.c')
OBJ := $(SRC:.c=.o)
# Preprocessor flags here
CPPFLAGS := -I.
# Compiler flags here
CFLAGS := -std=c99 -Wall -Werror-implicit-function-declaration
.PHONY: all debug run clean
all: CPPFLAGS += -DNDEBUG
all: $(EXE)
debug: CPPFLAGS += -DDEBUG
debug: CFLAGS += -g
debug: $(EXE)
$(EXE): $(OBJ)
#echo "Compilation complete!"
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
#echo "Linking complete!"
run:
./$(EXE)
clean:
#$(RM) $(EXE) $(OBJ) *.dSYM
#echo "Cleanup complete!"
Make has a set of built-in variables and rules that you should use to avoid losing time and encountering simple mistakes.
Note that this Makefile does not handle dependencies well, and simply adding the list of .h files to the Makefile won't be enough. You can workaround this by letting your compiler create the dependency files on the fly along with the compilation of .o files like this:
Build the list of .d filenames: DEP := $(OBJ:.o=.d),
Tell the compiler to generate the corresponding files, add the -MMD -MP switches to the CPPFLAGS built-in variable,
Include them in the Makefile so it will parse their content: -include $(DEP),
Don't forget to clean them up, add $(DEP) to the $(RM) command in the clean target.
Result:
EXE := tp3
SRC := $(shell find . -type f -name '*.c')
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
# Preprocessor flags here
CPPFLAGS := -MMD -MP -I.
# Compiler flags here
CFLAGS := -std=c99 -Wall -Werror-implicit-function-declaration
.PHONY: all debug run clean
all: CPPFLAGS += -DNDEBUG
all: $(EXE)
debug: CPPFLAGS += -DDEBUG
debug: CFLAGS += -g
debug: $(EXE)
$(EXE): $(OBJ)
#echo "Compilation complete!"
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
#echo "Linking complete!"
-include $(DEP)
run:
./$(EXE)
clean:
#$(RM) $(EXE) $(OBJ) $(DEP) *.dSYM
#echo "Cleanup complete!"
If you have any question, go ahead.
If you use GNU make, then you may use patters rules or even static patterns:
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
if not, use old syntax
.c.o:
here are the contents of two makefile items.
a top level makefile the drives the makefile.bot
the makefile.bot handles files/executables in other directorys
these makefiles also use recursion to produce the dependency lists
so only those header files that are actually include'd in the source
are listed as dependencies for that source.
Note: there are several common .c and .h files in the top level directory
so they are compiled first, then referenced later
when performing the link activity in each of the sub directories
Note: the 'AllDirectorys' is a list of the sub directories
where source code is to be compiled/linked in individual executables
Note: this is setup to run on Linux, and uses linux shell commands
and certain utilities, like 'sed'
file: makefile.mak (the top level file)
SHELL = /bin/sh
# note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib -L/usr/lib -L/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
LIBS := -lssl -ldl -lrt -lz -lc -lm -lcrypto
.PHONY: AllDirectories
# the following statement needs to be edited as
# subdirectories are added/deleted/re-named
AllDirectories := \
CommandConfiguration \
Communication \
MainScheduler \
RetrieveCDSLog \
RetrieveEventRecorderLog \
RetrieveGPS \
QESRouter
#AllDirectories := \
# MainScheduler \
# Communication \
# RetrieveGPS \
# TestCommunicationDev
.PHONY: all
#all: $(OBJ) $(AllDirectories)
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak name=Tsk_$d all ); )
all: $(OBJ) $(AllDirectories)
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )
#
# create dependancy files
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I.
# ========= END $< TO $# =========
#
.PHONY: clean
#clean: $(AllDirectories)
# # ========== start clean activities ==========
# rm -f *.o
# rm -f $(name).map
# rm -f $(name)
# rm -f *.d
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end clean activities ==========
clean: $(AllDirectories)
# ========== start clean activities ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
rm -f ../bin/Tsk_*
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
# ========== end clean activities ==========
.PHONY: install
#install: $(AllDirectories)
# # ========== start install activities ==========
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end install activities ==========
install: $(AllDirectories)
# ========== start install activities ==========
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
# ========== end install activities ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
file: makefile.bot which only occurs once, in the top level directory
along side the above listed makefile.mak
SHELL = /bin/sh
BINDIR := /home/user/bin
.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot
#
# macro of all *.c files
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp -f
MV := mv
LDFLAGS := -L/usr/local/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
#LIBS := -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS := -lssl -ldl -lrt -lz -lc -lm -lcrypto
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $# $(OBJ) $(COMMON_OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
#
# ======= $(name) Copy Start =========
$(CP) $(name) $(BINDIR)/
# ======= $(name) Copy Done ==========
#
#
#create dependancy files -- inference rule
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I.
# ========= END $< TO $# =========
#
.PHONY: clean
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
.PHONY: install
install: all
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif