Makefile : fclean gives error if program is not yet built - makefile

I have 2 makefiles that crash when I use the command make re if the program (or library) is not yet previously built, because make re calls fclean, which should remove the file and crashes if the file is not found. Here is one of the makefiles for a library
NAME = lib.a
CC = cc
CFLAGS = -Wall -Wextra -Werror
SRC = *.c
OBJ = $(SRC:.c=.o)
INC = Includes
all: $(NAME)
$(NAME):
#$(CC) -I $(INC) $(CFLAGS) -c $? $(SRC)
#ar rc $(NAME) $? $(OBJ)
#ranlib $(NAME)
clean:
#/bin/rm -f $(OBJ)
fclean: clean
#/bin/rm $(NAME)
re: fclean all
.PHONY: all clean fclean re
when I call make re and lib.a still doesnt exist I get
rm: lib.a: No such file or directory
make: *** [fclean] Error 1
Is there anyway to get it to just ignore the fclean command if lib.a is not found?
thanks

See the Errors in Recipes section of the GNU make manual for how to deal with this at the make level.
In this instance, however, you can also deal with this at the rm level. The -f flag to rm will cause it ignore non-existent files (as well as not prompting for deletion and in basically all other ways not stopping or returning a failure... ever).
That being said it shouldn't, in general, ever be necessary to clean before a new build. That generally seems necessary when a makefile is incorrectly written (as yours is) to not properly teach make what the dependencies between sources and targets are (and/or by not using targets essentially at all and always just building from scratch as you are).

Related

GNU make: how prevent '-include file.ext' from executing a rule the target of which is 'file.ext'?

Just to review the terminology, this is the structure of a makefile 'rule':
target: dependencies ...
commands
...
This is the makefile I've written:
CC = mpicc
SHAREDLIB = libfmd.so
CFLAGS = -fPIC -Wall -Wno-unused-result -O3 -fopenmp
LFLAGS = -lm -fopenmp -lgsl -lgslcblas
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
.PHONY: all shared clean
all: shared
shared: $(SHAREDLIB)
$(SHAREDLIB): depend.mk $(OBJS)
$(CC) $(OBJS) -shared -o $# $(LFLAGS)
depend.mk: *.c *.h
$(CC) -MM *.c > depend.mk
-include depend.mk
clean:
rm -f *.o libfmd.so depend.mk
When the folder is clean, and I enter make clean, the following lines are shown:
mpicc -MM *.c > depend.mk
rm -f *.o libfmd.so depend.mk
It seems to me that -include depend.mk in addition to including depend.mk, executes the rule that depend.mk is its target. I'd like to stop this behavior.
You are correct. See How Makefiles are Remade in the documentation.
There is no way to prevent this behavior: if there's a rule that creates an included makefile, make will always rebuild it if it's out of date, then re-invoke itself to read the latest version.
The question is, why do you want to avoid it? Maybe if you explained the behavior you are actually looking for at a higher level we could help. As you have it here it's possible for .o files to be created without any depend.mk file created, then a compile fails, you modify a header file to fix it, but since the depend.mk file doesn't exist when you re-run make the source files are not rebuilt properly.
If you want to get accurate handling of C/C++ dependencies with GCC you might take a look at Auto-Dependency Generation.
depend.mk: *.c *.h
$(CC) -MM *.c > depend.mk
FYI, this is wrong, as make doesn't support shell wildcards in a rule string. Although on a recipe line that could work as it gets expanded by the shell itself.
I'd like to stop this behavior
depend.mk is a prerequisite of the default target, so it is a target anyway.
Also, preprocessing into depend.mk is slow for large projects, so it totally makes sense either to switch to manually written dependencies, or use a recommended way to generate them, as #MadScientist suggested.

Confused on how to create a Makefile

I am trying to create a Makefile and I am a bit stuck.
So far I have been compiling my 3 files (2 headers and one main program) as such:
gcc -c phypages.c -o phypages.o
gcc -c pagetable.c -o pagetable.o
gcc -c analysis.c -o analysis.o
gcc analysis.o phypages.o pagetable.o -o analysis
I would like to make a Makefile to help me out with this. When I compile and link the files without a Makefile everything works fine, however when I try to make a Makefile I get a bunch of errors. Could you give me some tips on how to go about making a basic Makefile?
This is a good start:
# Binary name
NAME = analysis
# Compiler settings
CC = gcc
CFLAGS += -Wall -Wextra
CFLAGS += -Werror
# Source files
SRCS = phypages.c \
pagetable.c \
analysis.c
# Object files
OBJS = $(SRCS:.c=.o)
RM = rm -f
# Default rule, it should call all your rules that create
# an executable, or build a library...
# Here, it calls only the $(NAME) rule, that builds `analysis`
all: $(NAME)
# Rule to build your object files and link them into a binary
$(NAME): $(OBJS)
$(CC) -o $(NAME) $(OBJS)
# Rule to remove object files
clean:
$(RM) $(OBJS)
# Rule to remove binary, calls the 'clean' rule first
fclean: clean
$(RM) $(NAME)
# Rule to remove object files and binary, then re-build everything
re: fclean all
# Rules that are not linked with a filename should be listed here
.PHONY: all clean fclean re
You can then run make analysis or simply make to build your program.
Next time you change a file, run make again and only the file you changed will be re-compiled, instead of the whole project.

VPATH target failure

I have no idea how to express this little problem other than by "VPATH Failure", and searching for that brought me nowhere, so now I'm giving it a go, throwing my issue into the pool.
I'm working on a simple makefile here and I ran into a problem, that I am completely stumped by.
I made a first original version, that I got working all fine and dandy:
// Variable pre-processing stuff up here
VPATH = ./src/ ./include/
// Usual phony targets in here
$(OBJF)Utilities$(R).o: Utilities.cpp Utilities.hpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
$(OBJF)Settings$(R).o: Settings.cpp Settings.hpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
// More file targets down here
As proven by the make output
lex#Lex-Laptop:~/Dev/LHArch$ make RELEASE=STATIC rebuild
Removing object files and outputs...
Cleaning done.
Building objs/Release/Static/Utilities.o
./src/Utilities.cpp
Building objs/Release/Static/Settings.o
./src/Settings.cpp
That's nice.
For the sake of removing some redundancy with the dependencies, I thought it to be a good idea to put the code into their own targets, in this manner:
$(OBJF)Utilities$(R).o: Utilities.cpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
Utilities.cpp: Utilities.hpp
$(OBJF)Settings$(R).o: Settings.cpp
#echo Building $#
#echo $<
#$(CXX) $(FLAGS) -Iinclude -c $< -o $#
Settings.cpp: Settings.hpp
That is all I changed. I expected it to work as perfectly as it did before, but it only partially did:
lex#Lex-Laptop:~/Dev/LHArch$ make RELEASE=STATIC rebuild
Removing object files and outputs...
Cleaning done.
Building objs/Release/Static/Utilities.o
./src/Utilities.cpp
Building objs/Release/Static/Settings.o
Settings.cpp
g++: error: Settings.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:101: recipe for target 'objs/Release/Static/Settings.o' failed
make: *** [objs/Release/Static/Settings.o] Error 1
It found and replaced the path of Utilities, but not for Settings apparently. They are in the same folder, the commands are the same for the both of them. I honestly have no clue what is wrong and it sort of ruins my plan.
Have you guys for any wise words on this?
Did I stumble upon something genuine here, or am I just a dumbbutt who hasn't read up on his homework?
There's this rule (link provided by Etan Reisner) that VPATH and vpath should only be used for prerequisites, not for targets.
In your case, VPATH behaves "unpredictably" as soon as you put your .cpp files both as targets and prerequisites. The good news is that there's no redundancy in your first version. You do want the .o to be rebuilt if either of the .cpp and .hpp is updated. In fact, you don't want
Utilities.cpp: Utilities.hpp
since this will try to rebuild the .cpp if you update the .hpp, for which there's no recipe.
I would therefore stick with your first version and, instead, consider using vpath for ease of maintenance
vpath %.cpp ./src/
vpath %.hpp ./include/

How to avoid this recursive Makefile to relink?

today I'm requesting your help about a Makefile that's driving me crazy. There it is:
# Executable name
NAME = libft.a
# Compiler and archive linker settings
CC = gcc
AR = ar
CFLAGS = -Wall -Wextra -Werror -O3 -g3
ARFLAGS = -rsc
IFLAGS = -I./includes/
# Project layout
SRC_DIR = ./src/
INC_DIR = ./inc/
OBJ_DIR = ./obj/
OBJ = $(shell grep -r .o ./obj | awk '{print $$3}' | tr '\n' ' ')
.PHONY: all clean fclean re
#------------------------------------------------------------------------------#
all: $(OBJ_DIR) $(NAME)
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
$(NAME): compile $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $(NAME) $(OBJ)
#echo " ✧ $(AR) $(ARFLAGS) $(NAME) object files: OK! √\n"
compile:
make -C src/io
make -C src/lists
make -C src/memory
make -C src/strings
make -C src/tests
I've tried multiple combination of dependencies, rules, etc but I just don't get it. Sometimes I got it to stop relinking but in thoses cases it wouldn't re-compile object files because $(OBJ) was empty and wasn't updated after I ran compile.
This version is close to be good, but everytime I run make it executes the recipe $(NAME) and does the ar -rsc %(OBJ) .. How can I put them in dependencies to $(NAME) ?
Well, basically your entire approach here cannot succeed. Just for one example: you are trying to find the object files using grep (honestly I don't understand that shell command at all; what does printing the $3 word from the output of grep -r do??? Don't you just mean find $(OBJ_DIR) -name \*.o here?) This will expand to all the object files found in your subdirectories. But, that shell command runs when your top-level makefile is parsed, and that parsing happens before make runs any rules... so, no object files have been built yet! So, this target doesn't depend on anything. Even after some object files have been built, it only depends on object files that already exist, not on object files that are created during the build.
Really if I were you I'd do this completely differently. However, the simplest way to make your makefile work properly as written is to build $(NAME) using a recursive make as well; change your makefile like this:
all: compile
$(NAME): $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $# $^
#echo " ✧ $(AR) $(ARFLAGS) $# object files: OK! √\n"
compile:
mkdir -p $(OBJ_DIR)
$(MAKE) -C src/io
$(MAKE) -C src/lists
$(MAKE) -C src/memory
$(MAKE) -C src/strings
$(MAKE) -C src/tests
$(MAKE) $(NAME)
Here all doesn't depend on $(NAME); instead, the compile step first builds everything then at the end it recursively invokes itself to build $(NAME); at this point we know everything is up to date and we can depend on the object files existing.
Other things: note I used the automatic variable $^ here not $(OBJ); that variable is a simple variable that runs a shell script: it's expensive! Every time you expand the $(OBJ) variable you pay that cost, so you only ever want to do it one time. Alternatively, you can use := to set OBJS instead so it's only invoked once per make instance. That's still one more time than you need but avoiding this will be painful.
I also moved the mkdir into the compile rule. It's cleaner there than as a prerequisite of all.
Finally, you should never invoke sub-makes using the make command directly. Always use the $(MAKE) variable, or various things will not work correctly.
The question was obvioulsy solved by the previous post.
You need to use the $(MAKE) variable to call recursively your make file with the $(NAME) rule instead of putting $(NAME) as a all dependency, after subsequent calls to your underlying Makefiles using the $(MAKE) variable again.

Makefile with Fortran - src and bin directories

I'm having some trouble understanding how to design my makefile to build my project the way I want to. Specifically, I can't figure out how to keep all source files in a src directory, while putting all binaries in a bin directory except the linked executable, which goes in the project root.
This is my makefile:
# Compiler options
FC := mpif90
FFLAGS := -O3 -g -Wall -Warray-bounds -ffixed-line-length-none -fbounds-check
VPATH := src
BINDIR := bin
# Define file extensions
.SUFFIXES:
.SUFFIXES: .f .o .mod
# All modules
OBJS := $(BINDIR)/ratecoeffs.o $(BINDIR)/interpolation.o $(BINDIR)/io.o $(BINDIR)/eedf.o $(BINDIR)/single_particle.o $(BINDIR)/physics.o $(BINDIR)/random.o $(BINDIR)/mpi.o $(BINDIR)/precision.o $(BINDIR)/populations.o
# Build rules
all: runner | $(BINDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(BINDIR)/%.o: $(VPATH)/%.f | $(BINDIR)
$(FC) $(FFLAGS) -c $^ -o $#
runner: $(OBJS)
clean:
#rm -rf $(BINDIR)
Running make builds everything allright - it finds all source files in src and puts all .o files in bin - but the module files (.mod) that are generated by the compiler are put in the project root instead of in the bin directory. I realize I could just specify a rule to place them there, but that messes with the build order, and will sometimes break the build.
What is the "correct" way to get this behavior?
And yes, I've looked at autotools and automake, but I've never used them before and they seem to be overkill for this project. As I couldn't find any good tutorials on how they work (no, I didn't like the tutorial on gnu.org) I'd prefer if I could avoid having to learn this tool just to get this work...
Assuming your underlying Fortran compiler is gfortran, use the -J command line option.
$(FC) $(FFLAGS) -c $^ -o $# -J$(BINDIR)
With an eye to the future, you may be better off creating a MODDIR or similar variable, that you use instead of BINDIR. Object code (*.o) and mod files have different roles to play in later compilation and linking steps - in larger projects they are often kept separate.
It would be probably more in the sense of the make system to change into the obj-directory and do the compilation from there. Via the VPATH option you can let make to find your source files automatically. You could easily call your makefile recursively from the right directory. Below you find a trivial example which would be straightforward to adapt to your case. Please note, that it only works with GNU make.
ifeq (1,$(RECURSED))
VPATH = $(SRCDIR)
########################################################################
# Project specific makefile
########################################################################
FC = gfortran
FCOPTS =
LN = $(FC)
LNOPTS =
OBJS = accuracy.o eqsolver.o io.o linsolve.o
linsolve: $(OBJS)
$(LN) $(LNOPTS) -o $# $^
%.o: %.f90
$(FC) $(FCOPTS) -c $<
.PHONY: clean realclean
clean:
rm -f *.mod *.o
realclean: clean
rm -f linsolve
accuracy.o:
eqsolver.o: accuracy.o
io.o: accuracy.o
linsolve.o: accuracy.o eqsolver.o io.o
else
########################################################################
# Recusive invokation
########################################################################
BUILDDIR = _build
LOCALGOALS = $(BUILDDIR) distclean
RECURSIVEGOALS = $(filter-out $(LOCALGOALS), $(MAKECMDGOALS))
.PHONY: all $(RECURSIVE_GOALS) distclean
all $(RECURSIVEGOALS): $(BUILDDIR)
+$(MAKE) -C $(BUILDDIR) -f $(CURDIR)/GNUmakefile SRCDIR=$(CURDIR) \
RECURSED=1 $(RECURSIVEGOALS)
$(BUILDDIR):
mkdir $(BUILDDIR)
distclean:
rm -rf $(BUILDDIR)
endif
The principle is simple:
In the first part you write your normal makefile, as if you would create the object files in the source directory. However, additionally you add the VPATH option to make sure the source files are found (as make will be in the directory BUILDDIR when this part of the makefile is processed).
In the second part (which is executed first, when the variable RECURSED is not set yet), you change to the BUILDIR directory and invoke your makefile from there. You pass some helper variables (e.g. the current directory) and all make goals, apart of those, which must be executed from outside BUILDDIR (e.g. distclean and the one creating BUILDDIR itself). The rules for those goals you specify also in the second part.

Resources