Unexpected prerequisite skip in GNU Make 4.2.1 - c

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

Related

Makefile Stops Building Files After First .o In Out-of-Source Build

I have a bit of a huge Makefile that basically works as I want it to.
Issue: The problem I'm having is that the makefile only checks if the first .o needs updating and not if any others do. I'm not sure what part of my makefile is in error.
Context: I have project structure like this:
quendor
src
main.c
options.c
quendor.h
Makefile
When my Makefile builds, it constructs a build directory and things look as follows:
quendor
build
src
main.d
main.o
options.d
options.o
src
main.c
options.c
quendor.h
Makefile
To See the Problem: Now let's say I don't change my main.c but I do change my options.c file. In that case, when I run make again I get this:
make: 'build/./src/main.o' is up to date.
I'm not sure if this is because it's building into a build/src directory rather than just build as I intended.
Here is the full Makefile and I'm including all of it just because I'm not sure what might be a problem and I don't want to make unwarranted assumptions.
.PHONY : all clean
NAME := quendor
PLATFORM := windows
CC := gcc
LINK := gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
ifeq ($(PLATFORM), windows)
TARGET ?= quendor.exe
else
TARGET ?= quendor
endif
ifeq ($(CC), gcc)
CFLAGS += -std=c11 -Wall -Wextra -Wpedantic -Wconversion -Wmissing-prototypes -Wshadow -MMD -MP
LDFLAGS +=
OPT +=
endif
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
MKDIR_P ?= #mkdir -p $(dir $#)
-include $(DEPS)
all : $(TARGET)
#echo "Building $(TARGET)"
$(TARGET) : $(OBJS)
$(LINK) $(OPT) -o $# $^ $(LDFLAGS)
$(BUILD_DIR)/%.o : %.c
$(MKDIR_P)
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(TARGET) -r $(BUILD_DIR)
This may be an artifact of how StackOverflow is parsing my Makfile but I do notice that it's showing different syntax highlighting after this line:
SRCS := $(wildcard $(SRC_DIR)/*.c)
The problem is that you are including the dependencies before you define the all rule:
-include $(DEPS)
all : $(TARGET)
If you don't specify a particular target to build on the command line (e.g., if you don't run make all) then make chooses the first explicit target in the makefile (and any included makefiles!!) as the target to build.
I assume that the dependency definitions in the $(DEPS) variable define main.o as a target and since that comes before all, it's the only thing that's run by default.
Move the -include statement later in the makefile (I typically put these all at the end of the makefile) and it will work.

Makefile error when including dependency files generated from another Makefile

I have the current structures of directories:
./myFolder/
Makefile
main.c
./common/
Makefile
error.c
error.h
./build/
/common/
/myFolder/
/build/common contains the object and dependency files obtained from the compilation of the folder common and the equivalent for build/myFolder.
Basically /myFolder/ contains a programme that requires some function contained in common. Thus, the /myFolder/Makefile calls also the /common/Makefile to compile.
./common/Makefile is the following:
CC = gcc
CURRENT_DIR := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := ../build/$(CURRENT_DIR)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
all: $(OBJECTS)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
-include $(DEPENDS)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)
and ./myFolder/Makefile is the following:
CC = gcc
INC_PATH := -I../common/
BUILD_DIR_NAME := build
BUILDDIR := ../$(BUILD_DIR_NAME)
CURR_DIR_NAME := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := $(BUILDDIR)/$(CURR_DIR_NAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR_NAME := common
COMMONDIR := ../$(COMMONDIR_NAME)
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(BUILDDIR)/$(COMMONDIR_NAME)
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
EXECUTABLE := ../out_file
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
+$(MAKE) -C $(COMMONDIR) clean
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(OBJECTSCOMMON)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS) $(DEPENDSCOMMON)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(OBJDIRCOMMON):
mkdir -p $(OBJDIRCOMMON)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile| $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
If I step into the folder myFolder and compile with make for the first time, everything is ok.
If then I try again I get the following error:
make: *** No rule to make target `error.c', needed by `../build/common/error.o'. Stop.
If I do make clean and then make it works.
The line causing the problem is the following:
-include $(DEPENDS) $(DEPENDSCOMMON)
particularly $(DEPENDSCOMMON). With -include $(DEPENDS) instead of it, it works perfectly.
Now, - tells the Makefile not to complain if the files do not exist. If they exist they will be included and recompile your sources properly according to the dependencies. For this reason I would expect not to compile at the first attempt, but if it compiles at the first attempt, also to not generate such error (since all files exist).
Can someone please tell me what I am missing?
For completeness here are the other files which are just examples:
main.c
#include "../common/error.h"
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc<1) err_sys("some error");
printf("Hello world\n");
return 0;
}
error.c
#include <stdio.h>
void err_sys(const char *fmt, ...)
{
printf("some err\n");
}
error.h
#ifndef _ERROR_H_
#define _ERROR_H_
#endif
/*Fatal error related to a system cal1.
* Print a message and terminate*/
void err_sys(const char *fmt,...);
The error is related to your Makefile structure.
The main problem is that you generate the dependencies in common/Makefile and use it in myFolder/Makefile. The dependencies are generated for $(SOURCEDIR)/%.c, e.g. ./somefile.c which is valid only in common, not in myFolder
A related problem is that you duplicate many parts from common/Makefile in myFolder/Makefile. It doesn't make much sense to have a separate Makefile in this situation.
One way to solve this would be to build a library from the files in common and reference only the library from myFolder/Makefile. This avoids duplicating information from common/Makefile to myFolder/Makefile.
I changed your Makefiles to work this way. (There might be room for improvement, I only wanted to make it work.)
common/Makefile:
CC = gcc
CURRENT_DIR := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := ../build/$(CURRENT_DIR)
LIBNAME=libcommon.a
COMMONLIB = $(OBJDIR)/$(LIBNAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
.PHONY: all clean
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
all: $(COMMONLIB)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(COMMONLIB)
-include $(DEPENDS)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)
$(COMMONLIB): $(OBJECTS)
$(AR) $(ARFLAGS) $# $^
myFolder/Makefile:
CC = gcc
INC_PATH := -I../common/
BUILD_DIR_NAME := build
BUILDDIR := ../$(BUILD_DIR_NAME)
CURR_DIR_NAME := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := $(BUILDDIR)/$(CURR_DIR_NAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR_NAME := common
COMMONDIR := ../$(COMMONDIR_NAME)
OBJDIRCOMMON := $(BUILDDIR)/$(COMMONDIR_NAME)
LIBNAME=libcommon.a
COMMONLIB = $(OBJDIRCOMMON)/$(LIBNAME)
.PHONY: buildlib clean all
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
EXECUTABLE := ../out_file
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
+$(MAKE) -C $(COMMONDIR) clean
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(COMMONLIB)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(COMMONLIB): FORCE
+$(MAKE) -C $(COMMONDIR)
FORCE:
Note: I used the target FORCE with no rule as a dependency instead of declaring $(COMMONLIB) as .PHONY to force running the recursive make. When I tried with .PHONY, the executable was re-built every time without checking the time stamp of the library file.
Another option would be to throw away the Makefile in common and replace the recursive make call in myFolder/Makefile with the corresponding compile command.
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c Makefile| $(OBJDIRCOMMON)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
Notes
You don't need to use the relative path ../common in the #include directive when you specify this as an include directory with option -I.
I added .PHONY to declare your phony targets as such.
For automatic dependency generation and general recommendations about Makefiles I recommend to read the papers at http://make.mad-scientist.net/papers/.
You might also consider using a Makefile generator like cmake.
If you copy&paste the Makefile code from here, make sure to replace the spaces at the beginning of the lines with a tab.

Makefile not building when updating source

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

mongoc_init undefined reference

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.

Makefile: How to create both static and shared libraries in C?

Ladies, gentlemen, hello.
I'm trying to create a Makefile in C which will create two libraries
One static,one shared.So far my Makefile works for the static part.
Projet file structure:
//root
//root/src
An other point to mention, this Makefile also creates *.o in my root project directory and the /src dir.
What to do so it only creates object files inside the /src directory ?
Makefile:
SNAME = libmy_printf_`uname -m`-`uname -s`.a
DNAME = libmy_printf_`uname -m`-`uname -s`.so
SRC = $(wildcard src/*.c)
OBJ = $(SRC:.c=.o)
CC = gcc
RM = rm -f
CFLAGS = -W -Wall -ansi -pedantic -Werror -g3 -fPIC
LDFLAGS = -L. -l$(NAME)
STATIC: $(OBJ)
$(CC) -c $(SRC)
ar r $(SNAME) $(OBJ)
ranlib $(SNAME)
DYNAMIC: $(OBJ)
$(CC) -c $(SRC)
$(CC) -shared -o $(DNAME) $(OBJ)
.PHONY: my_printf_static
my_printf_static: $(STATIC)
.PHONY: my_printf_dynamic
my_printf_dynamic: $(DYNAMIC)
.PHONY: all
all: my_printf_static my_printf_dynamic
.PHONY: clean
clean:
$(RM) $(OBJ)
.PHONY: fclean
fclean: clean
$(RM) $(SNAME) $(DNAME)
.PHONY: re
re: fclean all
Thanks!
Your makefile can be boiled down to this:
NAME := libmy_printf_$(shell uname -m)-$(shell uname -s)
SNAME := $(NAME).a
DNAME := $(NAME).so
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
CFLAGS := -ansi -pedantic -Wall -W -Werror -g3 -fPIC
LDFLAGS := -L.
LDLIBS := -l$(...)
.PHONY: all clean fclean re
all: $(SNAME) $(DNAME)
$(SNAME): $(OBJ)
$(AR) $(ARFLAGS) $# $^
$(DNAME): LDFLAGS += -shared
$(DNAME): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(OBJ)
fclean: clean
$(RM) $(SNAME) $(DNAME)
re: fclean all
There are multiple things that you should know:
Don't use back-quotes commands, use the $(shell) built-in function in conjunction with the := assignment operator to prevent commands being re-run multiple times (unless this is the desired behavior).
Use only one .PHONY special rule, placed above all rules, and list them there.
Redefining $(CC) or $(RM) variables like you did is pointless since they already contain what you wanted here.
You wrote -l$(NAME) but you didn't define a NAME variable. I change it to $(...) since I couldn't guess what you really wanted here, don't forget to handle this.
Use the name of the targets to be created as the name of the related rules. That way Make won't recreate the targets unless you really want it (by calling the clean, fclean or re rules explicitly).
-L flags and -l flags should not be mixed in the same variable, unless placed at the right place in the linking command. Actually you didn't even used them. I explicitly separated them in the LDFLAGS and LDLIBS built-in variables, as per Make implicit rules.
If you have any questions, go ahead.
As discussed in the comments, if you need to remove the -fPIC flag from the compilation flags for the static library, you should consider building object files in different directories:
EDIT: I added your my_printf_static and my_printf_dynamic rules:
NAME := libmy_printf_$(shell uname -m)-$(shell uname -s)
SNAME := $(NAME).a
DNAME := $(NAME).so
SRC := $(wildcard src/*.c)
SDIR := build-static
SOBJ := $(SRC:src/%.c=$(SDIR)/%.o)
DDIR := build-shared
DOBJ := $(SRC:src/%.c=$(DDIR)/%.o)
CFLAGS := -ansi -pedantic -Wall -Werror -W -g3
LDFLAGS := -L.
LDLIBS := -l$(...)
.PHONY: all clean fclean re my_printf_static my_printf_dynamic
all: my_printf_static my_printf_dynamic
my_printf_static: $(SNAME)
my_printf_dynamic: $(DNAME)
$(SNAME): $(SOBJ)
$(AR) $(ARFLAGS) $# $^
$(DNAME): CFLAGS += -fPIC
$(DNAME): LDFLAGS += -shared
$(DNAME): $(DOBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(SDIR)/%.o: src/%.c | $(SDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
$(DDIR)/%.o: src/%.c | $(DDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
$(SDIR) $(DDIR):
#mkdir $#
clean:
$(RM) -r $(SDIR) $(DDIR)
fclean: clean
$(RM) $(SNAME) $(DNAME)
re: fclean all
What to do so it only creates object files inside the /src directory ?
Don't run the compiler twice. Your STATIC and DYNAMIC rules both depend on $(OBJ), which will cause those files to be built by make's implicit rules. Then, immediately after that you run the compiler again within those rules. Just take those lines out. make normally prints the commands it's going to run, so you should see why it's happening in your build log.

Resources