Makefile recompiles after cleaning objects (but not the name target) - makefile

When I call the clean rule with make clean all objects are correctly deleted. However if just after I call the all rule with make it recompiles all the objects again, even if the target is already there.
As far as I know, it should not recompile the objects beacuse the $(NAME) dependecy in the all rule is already satisfied. Indeed make clean erase just the object and not the program target too.
Somebody can explain me how to avoid recompiling after a make clean call? Thank you.
Here is the makefile:
NAME = myprogram
CC = clang++
CFLAGS = -Werror -Wextra -Wall -O3 -std=c++11
DIR_SRCS = srcs/
DIR_OBJS = objs/
DIR_INCS = incs/
FILES = main.cpp \
file1.cpp \
files2.cpp \
file3.cpp \
OBJS = $(addprefix $(DIR_OBJS), $(notdir $(addprefix $(DIR_SRCS), $(FILES:.cpp=.o))))
all: $(NAME)
$(NAME): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) -I$(DIR_INCS) -o $(NAME)
$(DIR_OBJS)%.o: $(DIR_SRCS)%.cpp
mkdir -p $(DIR_OBJS)
$(CC) $(CFLAGS) -I$(DIR_INCS) -c $< -o $#
clean:
rm -rf $(DIR_OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re

The $(NAME) dependecy in the all rule is NOT satisfied, because $(NAME) depends on $(OBJS) - and $(OBJS) does not exist (after make clean). This is how make works. If any dependencies don't exists or are newer than the target - the dependecies need to be regenerated (and in turn - the target).
For example: program --> program.o --> (program.c, program.h)
If program.c or program.h is newer than program.o : program.o needs to be regenerated (updated). This causes program.o to be newer than program - program needs to be relinked (using program.o).

Related

I dont understand why my makefile is relinking

I have the following files:
Makefile
libft.h
ft_atoi.c
ft_itoa.c
...
And the following Makefile:
SRC_FILES:=$(wildcard *.c)
NAME=libft.a
LIBSO=libft.so
CC=gcc
CFLAGS=-Wall -Wextra -Werror -g
OBJ_DIR=obj/
HDR_NAME=libft.h
SRC_NAMES=${SRC_FILES:.c=.o}
SRC_NAMES_O=$(addprefix $(OBJ_DIR), $(SRC_NAMES))
all: $(NAME)
$(NAME): $(OBJ_DIR) $(SRC_NAMES)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
$(OBJ_DIR):
mkdir $#
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $(OBJ_DIR)$#
clean:
rm -rf $(OBJ_DIR)
sclean: clean
rm -rf $(NAME) $(LIBSO)
fclean: clean
rm -f $(NAME)
re: fclean all
so:
$(CC) -nostartfiles -fPIC $(CFLAGS) $(SRC_FILES) $(BONUS_FILES)
gcc -nostartfiles -shared -o libft.so $(SRC_FILES) $(BONUS_FILES)
.PHONY: all bonus clean sclean fclean re so
But it is relinking. What did I do Wrong? I feel like it should run but it keeps recompiling everything each time I run make.
By code-review-only, I suspect that the culprit is the following line:
$(NAME): $(OBJ_DIR) $(SRC_NAMES)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
Namely, $(OBJ_DIR) is a normal prerequisite of $(NAME), so each time a file (or subdirectory) in the obj/ directory is created, renamed, or deleted, the timestamp of obj changes, and thereby triggers a rebuild of the make all target.
To avoid this, you may want to replace this target with:
$(NAME): $(SRC_NAMES) | $(OBJ_DIR)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
The underlying concept of GNU Make is called order-only prerequisite:
Occasionally (…) you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:
targets : normal-prerequisites | order-only-prerequisites
The normal prerequisites section may of course be empty. (…)

Libft bonus rule relinks

So, right now my Makefile looks like this
SRCS = (let's say there are some .c files)
BONUS_SRCS = (and there are some _bonus.c files)
OBJS = $(SRCS:.c=.o)
BONUS_OBJS = $(BONUS_SRCS:.c=.o)
HDRS = libft.h
NAME = libft.a
RM = rm -rf
GCC = gcc
AR = ar -crs
FLAGS = -Wall -Wextra -Werror
.c.o:
$(GCC) $(FLAGS) -I includes -c $< -o $(<:.c=.o)
$(NAME): $(OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS)
all: $(NAME)
bonus: $(OBJS) $(BONUS_OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS) $(BONUS_OBJS)
re: clean fclean all
clean:
$(RM) $(OBJS) $(BONUS_OBJS)
fclean: clean
$(RM) $(NAME)
.PHONY:
all clean fclean re bonus
And if I try to make bonus make compiles bonus functions at first, and every other make bonus relinks. Is there any way to tell make not to relink?
By "relink" I mean recreating the libft.a every time I call make bonus.
Example make:
$> make
gcc -Wall -Wextra -Werror -I includes -c test_a.c -o test_a.o
ar -crs libft.a test_a.o
$> make
make: `libft.a' is up to date.
$>
But make bonus:
$> make bonus
gcc -Wall -Wextra -Werror -I includes -c test_a.c -o test_a.o
gcc -Wall -Wextra -Werror -I includes -c test_b.c -o test_b.o
ar -crs libft.a test_a.o test_b.o
$> make bonus
ar -crs libft.a test_a.o test_b.o
$>
And this is confusing as hell.
It's not confusing if you remember that make doesn't have some magic database of information about what it did last time. It has your makefile, and it has the files on the filesystem (and the last modified time that the filesystem tracks).
So when you run make bonus, make looks for a rule that knows how to build the target bonus and finds this rule:
bonus: $(OBJS) $(BONUS_OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS) $(BONUS_OBJS)
This rule tells make that if it runs this recipe the target bonus will be updated. Make sees that the target bonus does not exist (there's no file named bonus on the disk) so it decides that target is out of date and needs to be updated.
But, of course, your recipe does NOT update the target bonus; bonus is not created or updated by this recipe at all.
So, the next time you run make bonus make again looks for a file named bonus, it still doesn't exist, so make again uses the recipe you told it would update that target. And on and on.
Check out Paul's Second Rule of Makefiles.
It should work to adjust your makefile as following
.PHONY: bonus
bonus: $(NAME)

Makefile ignoring included rules

I'm trying to create a makefile for a very basic c++ program. I'm trying to implement the automatic generation of dependencies by running g++ with the -M flag, storing this output in a .d file, and then including those .d files in my main makefile. The makefile content is below
CC=g++
CPPFLAGS=-Wall -Wextra -g -std=c++11
SOURCEDIR=src
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)
BUILDDIR=build
OBJDIR=$(BUILDDIR)/objs
OBJS=$(SOURCES:$(SOURCEDIR)/%.cpp=$(OBJDIR)/%.o)
DEP_FILES = $(OBJS:.o=.d)
OUTFILE=hello.out
$(OUTFILE) : $(OBJS)
$(CC) -o $# $^ $(CPPFLAGS)
include $(DEP_FILES)
$(OBJDIR)/%.d : $(SOURCEDIR)/%.cpp
$(CC) $(CPPFLAGS) $< -MM -MT $(#:.d=.o) > $#
$(DEP_FILES) : | $(OBJDIR)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
.PHONY: clean
clean:
rm -f $(BUILDDIR) -r
rm -f *~
rm -f $(OUTFILE)
When I run make, the directory build/objs/ is generated and a .d file is generated with rules in it. Here's main.d file:
build/objs/main.o: src/main.cpp src/main.h
And here's the myfunc.d file:
build/objs/myfunc.o: src/myfunc.cpp src/main.h
Here's the issue
Since I'm calling include on these .d files, I'd expect the .o files which they specify to then be created, and then the main outfile to be created as the main rule. However, make creates the .d files, and then skips directly to the main compilation step without creating any .o files:
g++ -o hello.out build/objs/myfunc.o build/objs/main.o -Wall -Wextra -g -std=c++11
This fails with the following error, since the .o files are never created:
g++: error: build/objs/myfunc.o: No such file or directory
g++: error: build/objs/main.o: No such file or directory
g++: fatal error: no input files
How can I use this makefile to generate the .o files necessary for g++? Thank you for any help in advance!
I saw you got your makefile working but I just wanted to add a few things you might want to consider for future projects. I recommend using the vpath variable rather than specifying $(OBJDIR)/%.o in your makefile recipes. I actually read somewhere that it's not "cannon" to build object files in a separate directory, but in the cursory search I conducted before posting, I couldn't find the document.
That being said, I wrote a makefile that does what you wanted; it builds the output folder, generates the dependencies, and compiles the program. I specifically included the $(COMPILE.cpp) definition so you could see what it's composed of. $(CC) is specifically the C compiler, and $(CFLAGS) is specifically flags for the C compiler. They're just variables, obviously, so you can change them like you did and it will work fine, but the main think to keep in mind is that whoever uses your programs will expect to be able to configure the compilation as they see fit. This means they will set the $(CXX) and $(CXXFLAGS) expecting to set the C++ compiler and flags. $(CPPFLAGS) stands for C/C++ Preprocessor flags.
It's not the cleanest makefile, and if I was to change something, I would just compile the object files in place and save myself that headache. That cuts down on unnecessary make hacking, but for the purposes of answering your question, here it is. Anyways I hope this helps you somewhat, let me know if you have any questions.
Oh yea, I almost forgot; notice I changed your make clean script. I used $(RM) instead of simply rm -f. When you use utilities in your makefiles, you want to use them as variables. Again, this is to allow your users as much freedom and flexibility as possible when they're compiling your program.
vpath %.cpp src
vpath %.hpp include
vpath %.o build/objs
vpath %.d build/objs
.SUFFIXES:
.SUFFIXES: .cpp .hpp .o .d
SRCDIR = src
INCLUDESDIR = include
BUILDDIR = build
OBJDIR = $(BUILDDIR)/objs
SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
DEP_FILES = $(patsubst %.o, %.d, $(OBJS))
INCLUDE_DIRS = -I $(INCLUDESDIR)
CXX = g++
CPPFLAGS =
CXXFLAGS = -Wall -Wextra -g -std=c++11
PROGRAM = hello.out
COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(TARGET_ARCH)
all: $(PROGRAM)
$(PROGRAM): %: $(OBJS)
$(LINK.cpp) $(INCLUDE_DIRS) $(addprefix $(OBJDIR)/, $^) $(LOADLIBES) $(LDLIBS) -o $#
%.o: %.cpp
$(COMPILE.cpp) -c -o $(OBJDIR)/$# $<
%.d: %.cpp
mkdir -p $(OBJDIR)
$(COMPILE.cpp) $^ -MM -MT $(addprefix $(OBJDIR)/, $(#:.d=.o)) > $(OBJDIR)/$#
include $(DEP_FILES)
.PHONY: clean
clean:
#echo $(RM)
$(RM) $(BUILDDIR) -r
$(RM) *~
$(RM) $(PROGRAM)
For anyone having a similar issue, here's the correct solution is in the comments. Here for convenience: The included .d files generate dependencies but not a recipe for making the .o files, and since I'm putting things in various directories the default rule doesn't work here, so the .o files aren't created. The solution was to add in the following rule to my main makefile.
$(OBJDIR)/%.o :
$(CC) -c -o $# $< $(CPPFLAGS)
Thanks Matt and Renaud for your answers!

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!

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