Generate object files in subdirectory using a Makefile - makefile

I am trying to create a Makefile in order to generate object files in a subdirectory rather than let them in the src/ folder.
Here is the structure of the project:
Trunk
- Server
- src/
- include/
- Common
- src/
- include/
The Makefile is located in Trunk/Server. Source files are located both in Server/src and Common/src, so the Makefile currently has something like this:
SRC = src/main.cpp \
src/Network.cpp \
../Common/src/SQLManager.cpp \
../Common/src/Utils.cpp
I woud like to put generated object files in respective obj folders, so Trunk/Server/obj and Trunk/Common/obj. How can I achieve this? I've found many ways to generate object files in subdirectories (vpath, patsubst and many more) but I can't make any of them work for this folder organization.
Edit: If there is a way to put all object files in Server/obj/, that would be ok too.
Here's the complete Makefile (minus some source files and linked libraries):
Edit2: Updated with Didier Trosset's changes
CXX = g++
RM = rm -vf
NAME = Server
SRC = src/main.cpp \
src/Network.cpp \
../Common/src/SQLManager.cpp \
../Common/src/Utils.cpp
OBJ = $(subst src/,obj/, $(subst .cpp,.o, $(SRC)))
LDFLAGS = -lpthread -lm
CPPFLAGS = -std=c++0x -pedantic -Wextra -Wall -Wconversion -Iinclude -I../Common/include
all: Server
%.o: %.cpp
$(CXX) $< -o $#
Server: $(OBJ)
$(CXX) -o $(NAME) $(OBJ) $(LDFLAGS)
clean:
$(RM) $(OBJ) *~
fclean: clean
$(RM) $(NAME)
re: fclean Server
.PHONY: all clean fclean Server

Given these definitions, subst should be used to substitute the src part of the directory, and the file extension.
OBJ = $(subst src/,bin/,$(subst .cpp,.o,$(SRC)))
Then, you have to add new pattern rules to compile your source files. (You have to write one pattern rule per directory where your source files are.)
obj/%.o: src/%.cpp
$(CXX) -c $< -o $#
../Common/obj/%.o: ../Common/src/%.cpp
$(CXX) -c $< -o $#

I'm not sure that this will work, but I would try something like:
OBJ := $(join $(addsuffix ../obj/,$(dir $(SRC))),$(notdir $(SRC))
# or, as Didier suggested:
# OBJ := $(subst src/,obj/,$(SRC))
%.o: ../src/%.cpp
$(CXX) $< -o $#

It's not clear exactly what you're trying to do, but this should come close:
OBJ = $(subst src/,obj/,$(SRC:.cpp=.o))
obj/%.o : src/%.cpp
$(CXX) $< -o $#
../Common/obj/%.o : ../Common/src/%.cpp
$(CXX) $< -o $#

Related

No rule to make target (make project in different directories)

Excuse me for asking simple questions, but I can't find where the problem is.
I have an src directory, contains makefile and obj folder. An include folder and a lib one. The codes have provided here.
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~
it gives me the following error:
gcc -c -o obj/hellomake.o hellomake.c -I../include
make: *** No rule to make target 'obj/hellofunc.o', needed by 'hellomake'. Stop.
It uses the same rule for creating .o files and hellomake file. but the last one does not work.
Thanks for any comment or guide.
You have a src directory, but you don't tell Make about it. Make is complaining that there is no hellofunc.c. (There is asrc/hellofunc.c, but Make didn't know to look there.) Try this:
SRC := src
$(ODIR)/%.o: $(SRC)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)

How to avoid my makefile to relink

My Makefile is relinking and I can't find why.
I'm not sure why malloc assume that $(NAME) have to be executed. Is the $(SRC:.c=.o) macro changing the timestamps of the .o files or something like that ?
CC = gcc
NAME = app
#
CFLAGS = -Wall -Werror -Wextra -pedantic -pedantic-errors
INCLUDES = -I ./includes
#
DIRSRC = srcs/
DIROBJ = objs/
SRC += main.c
SRC += malloc.c
OBJ = $(SRC:.c=.o)
DIROBJS = $(addprefix $(DIROBJ), $(OBJ))
#
LIBS_PATH = ./libs
LIBFT_PATH = $(LIBS_PATH)/libft
LIBFT_INCLUDES = -I $(LIBFT_PATH)
LIBFT = -L $(LIBFT_PATH) -lft
#
COMPILE = $(CC) $(CFLAGS) $(INCLUDES)
#
all: $(NAME)
$(NAME): configure libs $(DIROBJS)
$(COMPILE) $(LIBFT) $(DIROBJS) -o $(NAME)
$(DIROBJ)%.o: $(DIRSRC)%.c
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
clean:
#rm -rf $(DIROBJ)
fclean: clean
#rm -rf $(NAME)
re: fclean all
#
configure:
#mkdir -p $(DIROBJ)
#
libs:
#$(MAKE) -C $(LIBS)
.PHONY: all configure clean fclean re libs cleanlibs fcleanlibs relibs
It always relink because the configure rule will always run. So Make believes one of the dependencies changed, and it reevaluates the rule.
The way I would solve this would be to get rid of the configure rule and to move the #mkdir -p $(DIROBJS) in the rule that builds your object files:
$(DIROBJ)%.o: $(DIRSRC)%.c
#mkdir -p $(DIROBJS)
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
There might be more reasons (that could be related to the library you're also building), I don't know. Let us know if this solves it entirely.
#rtur's answer works, however I should mention another alternative. You could do:
$(DIROBJ):
mkdir $#
$(DIROBJ)/%.o: $(DIRSRC)/%.c | $(DIROBJ)
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
That way, it only makes the directory if it doesn't already exist. One thing to notice is the | symbol. This makes $(DIROBJ) an order-only prerequisite. This means if it's newer than the target, it will not cause the the target to rebuild. This is really important for directories, as the timestamp of a directory is the date the last item in it was added/deleted/modified, and your target would always be out of date without that symbol. This is considered cleaner, as you have less invocations of mkdir this way.
Also, as a style note, you usually, you don't include the trailing / at the end of directory names. $(OBJ_DIR)/%.o looks nicer than $(OBJ_DIR)%.o. Of course, that could just be my opinion :-)
I'm 42 network student.
I had this problem quite often as well.
Moving the .o files into a folder usually causes the Makefile to relink since that directory is not a 'dependency'.
Here's an example:
NAME = lib.a
INC = lib.h
FLAGS = -Wall -Wextra -Werror
LIB = function1.c function2.c function3.c function4.c
OBJ = $(SRC:%.c=%.o)
all: $(NAME) clear
$(NAME): $(OBJ)
#$(AR) rcs $# $^
#ranlib $(NAME)
%.o: %.c
#$(CC) $(FLAGS) -I $(INC) -c $< -o $#
clear:
#mkdir -p obj
#mv $(OBJ) obj
clean:
#$(RM) $(OBJ)
fclean: clean
#$(RM) $(NAME)
re: fclean all
The existence $(OBJ) are going to be checked when making $(NAME), not the 'obj' folder.
Solution:
NAME = lib.a
INC = lib.h
FLAGS = -Wall -Wextra -Werror
SRC = function1.c function2.c function3.c function4.c
DIR_OBJ = obj/
OBJ = $(SRC:%.c=$(DIR_OBJ)%.o)
all: $(NAME)
$(NAME): $(OBJ)
#$(AR) rcs $# $^
#ranlib $(NAME)
$(DIR_OBJ)%.o:%.c
#mkdir -p $(dir $#)
#$(CC) $(FLAGS) -I $(INC) -c $< -o $#
clean:
#$(RM) -rf $(DIR_OBJ)
fclean: clean
#$(RM) $(NAME)
re: fclean all
I think I covered it with this example, let me know if I missed a detail.
Good luck with your projects!

Makefile doesn't find source files

I have tried to make a makefile. I have the following folder structure.
Source
- include
- My headerfiles
- objects
- The object files
- src
- My source files
My problem is that the source files in the src directory isn't found.
My make file looks as the following.
# gcc for C
# g++ for c++
CC = gcc
#compiler flags
# -g adds debugging information to the executebells
# -Wall
CFLAGS = -g -Wall
#target
TARGET = gabe_the_dog_server
#directory for the object files
OBJDIR = ./objects
SRCDIR = ./src
default: $(TARGET)
all: default
HEADERS = $(wildcard include/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) $(CFLAGS) $(LIBS) -o $(OBJDIR)/$#
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
Here:
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
You use the variable SOURCES, but you never define it. You need one more line:
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
Instead of using the path to your source files, it's recommended that you put this path in the special variable named VPATH. Then you just mention your source file, like this:
OBJDIR = ./obj
SRCDIR = ./src
VPATH = $(SRCDIR)
OBJECTS = $(addprefix $(OBJDIR)/, foo.o bar.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(cc) ...
GNU make will look in the folders present in VPATH for the files that are prerequisites of a target. Note that this could be a problem if you have multiple folders where you can find multiple times the same file name.
See GNU make VPATH manual. If you need additional examples of VPATH good practices, see this link as well: Mad Scientist: How not to use VPATH

Makefile does not work properly

I've this folder structure
project
|_src
| |_test
| |_main.cpp
|_Makefile
This is my makefile (trying to adapt from this link):
CC = g++
RM = rm
WFLAGS = -c -Wall -W
LDFLAGS =
SRCTESTD = src/test
EXECUTABLE = test
OBJD = .obj
DEPD = .dep
SRCSTEST = $(SRCTESTD)/main.cpp
OBJECTSTEST = $(patsubst %.cpp, $(OBJD)/test/%.o, $(notdir $(SRCSTEST)))
DEPDSTEST = $(patsubst %.cpp, $(DEPD)/test/%.d, $(notdir $(SRCSTEST)))
all: $(SRCSTEST) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTSTEST)
$(CC) $(LDFLAGS) $(OBJECTSTEST) -o $#
.cpp.o:
$(CC) $(WFLAGS) $< -o $#
It does not work, and I've this error
make: *** No rule to make target `.obj/test/main.o', needed by `test'. Stop.
What I'm doing wrong? Sorry for trivial question, but I'm a make newbie.
The link shows outdated methods, such as suffix rules. Making dependencies can also be done during compilation by gcc/g++.
As for the rest, here is it :
EXE := test
SRCDIR := src
OBJDIR := .obj
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
LDLIBS := # -l flags
LDFLAGS := # -L flags
CPPFLAGS := -MMD -MP # -I flags also
CXXFLAGS := -W -Wall # no -c flag here
.PHONY: all clean fclean re
all: $(EXE)
clean:
$(RM) -r $(OBJDIR)
fclean: clean
$(RM) $(EXE)
re: fclean all
-include $(DEP)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
No redefinition of internally defined variables, no suffix rules, correct linking step and dependencies generation.
Update: To avoid calling mkdir for every source file, one should use order-only prerequisites and the special target .SECONDEXPANSION.
Change this block:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
To this:
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir $*
The error means make can't find a correct rule to build your object files. Your tree structure lacks some informations: only one file ? Where are the others ? Anyway, here are some hints:
In the last two lines, you are using an obsolete feature of make: suffix rules. I suggest you switch to a pattern rule, which is functionaly equivalent.
Say something like:
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
Another thing (that shouldn't be a problem here): you are using the variable CC which is internally defined as the default C compiler. It's okay because you redefine it, but as your sources seem to be C++ files, why not use the variable CXX, that is internally defined as the C++ compiler ?
Lastly, to make sure your set of files are correctly defined, you can print them with a dummy show target, see here.
show:
#echo "OBJECTSTEST=$(OBJECTSTEST)"
...

Why is makefile recompiling entire set of files if I only change one?

Here is my makefile... Why does it recompile all sources even if only one changes??
CC = g++
CFLAGS = -w -g -c
LIBS = -lm
EXEC = DFMS_PDS_L2_to_L3
.PHONY : clean tgz wdtgz
HOMEDIR = ../
BIN = bin
SRC = src
OBJ = obj
SRCFILES := $(wildcard $(SRC)/*.cc)
OBJFILES := $(patsubst %.cc, $(OBJ)/%.o, $(notdir $(SRCFILES)))
OBJS := $(patsubst %.cc, %.o, $(notdir $(SRCFILES)))
# Executable Targets
all: $(EXEC)
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
# Dependencies
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
# Miscellaneous Targets
clean:
rm -rf $(BIN)/$(EXEC) obj/*.o *~
tgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild --exclude=data
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
wdtgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
I'm running on Linux 3.0 with gnu make
Is it in the $(EXEC) definition?
My guess is that this recompiles all of the sources even if none changes.
Look at these two rules:
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
Suppose foo.cc is the only source file. The first rule says that the target depends on foo.o, but actually builds it from obj/foo.o. The second can be invoked to build foo.o (which the first rule demands), but it actually builds obj/foo.o. So the first time you run Make it will build the executable correctly (and obj/foo.o). But every time thereafter, Make sees that foo.o does not exist and attempts to build it and rebuild the executable.
The solution is to rewrite the rules so that they build -- and depend on -- what they claim:
all: $(BIN)/$(EXEC)
$(BIN)/$(EXEC) : $(OBJFILES)
$(CC) $(LIBS) $^ -o $#
$(OBJ)/%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $#

Resources