Delete targets with recipes failed in Makefile - makefile

I tried to use .DELETE_ON_ERROR target in makefile in order to delete both $(OBJ)
and executable files if the recipe fails, but it doesn't work. If I put an error inside any object file than while compiling the pattern rule an error occurs and it stops. The old object file is still on its place but I expect .DELETE_ON_ERROR to remove it.
Can anyone test the code? Can -include $(DEP) or flag -DDBG influence? The goal is to delete both the .o file that failed and the executable.
OUTPUT = executable
CPP := $(shell find $(SRC) -type f -name "*.cpp")
OBJ := $(CPP:.cpp=.o)
DEP := $(OBJ:.o=.d)
CXX := g++
CXXFLAGS =-MMD -MP -DDBG
INCLUDES = -I.
.DELETE_ON_ERROR :
$(OUTPUT): $(OBJ)
$(CXX) $^ -o $#
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
-include $(DEP)
.PHONY : clean
clean:
rm -rf $(OBJ) $(DEP)
EDIT: According to the Ondrej K. solution to fix this problem you need to add #touch command before compilator in order to make the object files changed (the docs read "delete the target of a rule if it has changed".). So, the code should look like this:
%.o: %.cpp
#touch $#
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#

Not sure what failure you're seeing, but I am afraid there really isn't a good way for you to do that. .o files and executable ($(OUTPUT)) are separate rules. If the latter fails, former is already out of consideration. See the documentation:
.DELETE_ON_ERROR:
If .DELETE_ON_ERROR is mentioned as a target anywhere in the makefile, then make will delete the target of a rule if it has changed and its recipe exits with a nonzero exit status, just as it does when it receives a signal. See Errors in Recipes.
In other words, if your the target producing a binary object failed after .o target itself got updated, make would prune the changed file. But if your executable did not link, it won't go back and delete object files.
Not sure it'd be nice, but if you really needed to, you could probably achieve this by refactoring your makefile to basically have direct exec + objs from source prerequisites rule with a single recipe. Obvious downside, such rule would mean single .c file change causing all files being recompiled (basically negating substantial benefit of using make).
EDIT: I'll expand on the comment a bit to clarify. What you seem to want is: in case there is a broken .c file and compilation fails, remove the old .o file. That is quite clearly not how .DELETE_ON_ERROR works though. If the .o file already got updated, and then the rule failed, it would remove it ("delete the target of a rule if it has changed"), but in case of a mentioned syntactical problem, the compiler would fail before it would produced an .o file.
So, if for instance you updated your (pattern) rule for compilation so that it first touches (effectively updates timestamp) on the .o file and then tries to compile. After the compiler call and rule failed make would consider the target of the failed root to have been updated and remove it. Alternatively you could also change to rule to first try to rm the expected '.o' file in which case you actually wouldn't need to use .DELETE_ON_ERROR (and if there is no change in the relevant sources, the rule does not get used, so it's actually not as terrible as it sounds). Either way is not exactly very clean, but leads towards the behavior I understand you're describing.

It is possible that the Compiler crashes while writing the Output file. In this case, there is a corrupt output file that is newer than its sources. Make will stop due to the error, but on next run, it won't recompile the output file as it is newer than ist sources - and the make will fail again and again in the build step.
With the .DELETE_ON_ERROR rule, make will delete the Output file if the compiler (or whatever build step failed) exits with an error after touching (and corrupting) the Output file, so it will be recompiled on next run. (if the Compiler failed without touching the old output file, it will always be recompiled on next run anyway)

Related

Makefile and subdirectories

I'm struggling with the correct syntax of a makefile.
This is my folder structure:
project
│ Makefile
│ HERE SHOULD BE THE OUT FILE AFTER make command
│
└───include
│ header.h
│
│
└───src
function1.c
function2.c
How must the makefile look to ensure correct results?
This is my current makefile:
SOURCES = src/function.c src/function.c src/function.c
OBJECTS = $(SOURCES:.c=.o)
CC = cc
RM = rm -f
CFLAGS = -Wall -Wextra -Werror
NAME = output.a
all: $(NAME)
$(NAME):
$(CC) $(CFLAGS) -c $(SOURCES)
ar rcs $(NAME) $(OBJECTS)
clean:
$(RM) $(OBJECTS)
fclean: clean
$(RM) $(NAME)
re: fclean $(NAME)
my current output if i run make all:
cc -Wall -Wextra -Werror -c src/function1.c src/function2.c
ar rcs output.a src/function1.o src/function2.o src/function1.o
ar: src/function1.o: No such file or directory
make: *** [Makefile:15: output.a] Error 1
if i run make flcean the output looks the following:
rm -f src/function1.o src/function2.o
rm -f output.a
So it doesn´t remove anything because the .o files are stored in the root, not the /src subdirectory
I'm struggling with the correct syntax of a makefile.
Your makefile syntax is fine. In fact, your makefile is syntactically valid and reasonably well structured. It looks a lot better than many of the ones we see around here.
I guess what you're actually struggling with is that it doesn't work, even after you fix the weird disagreement between the source file list in the makefile itself and the actual source files on disk. But "doesn't work" is a pretty vague, though lamentably common, description. You would get better help, faster, by saying something along the lines of "the .o files are created in the top-level directory instead of in the src/ directory." (Which is exactly what I expect to happen, and as a result, the ar command will fail, and the clean target will not clean the .o files.)
You need to understand that make itself doesn't know much about building software. What it knows is how to match rules to patterns so as to execute associated recipes of shell commands. The particular kinds of patterns it matches and the built-in rules that come with it are oriented toward building software, but you can't expect it to go very far with anticipating what you mean. It, like any other computer program, will happily do what you say, instead, when that differs. In this case, it just runs the cc command with the arguments you specify, and cc will choose under those circumstances to put the .o files in the working directory.
From a stylistic and best-practices standpoint, it's best to write rules that build only their target file, unlike your rule for $(NAME) that attempts to build not just $(NAME) but also all the component object files. The object files would be better built according to their own rule or rules. Making the object files prerequisites of the rule for $(NAME) will ensure that they get built when needed. That will also allow for them to not be built when that is not needed. That variation on your rule would look like this:
$(NAME): $(OBJECTS)
ar rcs $# $^
Note also that in the recipe, I have substituted automatic variable $# for a repetition of the rule target name. That's good form, but not obligatory. I have also substituted automatic variable $^ for a repetition of the prerequisite list. That's less clear-cut, in part because $^ is specific to GNU make, but if you're ok with that dependency then it's a great way to avoid repeating yourself.
Now, about building the object files: you could write a pattern rule (GNU make only) or a suffix rule that builds an object file from a corresponding C source file, or you could even write a separate rule for each object file. But you don't actually need to do that. make comes with a built in rule that will serve your needs in that area just fine, so your best bet may be to not attempt to provide your own rule for that at all. That is: modifying the rule for $(NAME) as suggested above should be sufficient for successful building, supposing, again, that the contents of your SOURCES variable accurately reflect the source files you want to build.

gcc - What does ../ (dot dot slash) mean in a variable in a Makefile?

I have searched for hours for an answer to this. I am new to gcc and Makefiles.
I have a Makefile in some source code that looks like this:
CC=gcc
SRCDIR=src
BINDIR=../bin
CFLAGS= -flag
LIBS= -lthing
...
$(BINDIR)/program_name: $(SRCDIR)/program_name.c
$(CC) $(CFLAGS) $(SRCDIR)/program_name.c -o $(BINDIR)/program_name $(LIBS)
I understand what all of this means except what ../ in BINDIR is meant to do. When I make the Makefile, I get the error message:
/usr/bin/ld: cannot open output file ../bin/program_name: No such file or directory
collect2: error: ld returned 1 exit status
Makefile:20: recipe for target '../bin/program_name' failed
make: *** [../bin/program_name] Error 1
My guess is that the original author of this Makefile meant that the bin folder should go in the parent directory of where the Makefile is located. I know when using the Linux CLI command cd that the dot dot means go up a directory. Is that what this is trying to achieve?
To automatically create the $(BINDIR) directory before it is actually needed you must declare it as a prerequisite (dependence) of any target that uses it. But each time its content changes its timestamp also changes. So, declaring it as a regular prerequisite is not the best thing to do because the targets depending on it would be re-built without real reason, just because the content of $(BINDIR) changed.
This is why make also supports order-only prerequisites (OOPs):
$(BINDIR)/program_name: $(SRCDIR)/program_name.c | $(BINDIR)
$(CC) $(CFLAGS) $< -o $# $(LIBS)
$(BINDIR):
mkdir -p $#
Note the | that introduces the list of OOPs. An OOP is built if it does not exist, which causes the targets depending on it to be (re-)built too. But if it exists make does not even consider its last modification time. Even if some target depending on it is older, it is not rebuilt just because of that.
Note: I also used the $< and $# automatic variables. In the rule's recipe they expand as the first prerequisite ($(SRCDIR)/program_name.c) and the target ($(BINDIR)/program_name), respectively. They are highly recommended: less typing, less errors prone, more generic rules... they have many good properties.
Your makefile is missing a rule to create the BINDIR directory - if it doesn't exist, your link line won't be able to put the resulting binary there! A rule like this one should do it:
$(BINDIR):
mkdir -p $(BINDIR)
Just make sure that any other rules (like the one in your question) also depend on this directory!

makefile: dependency not build

The question was edited after MadScientist's answer. See history for the original makefile, but the problem stays the same.
I have a small makefile:
DEPFLAGS=-MD -Mo $(OUTDIR)/$*.Td
POSTCOMPILE=#mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d && touch $#
VPATH=../src
OUTDIR=../out
SOURCES:=$(notdir $(wildcard ../src/*.c))
OBJECTS:=$(SOURCES:%.c=$(OUTDIR)/%.o)
all: $(OBJECTS) $(OBJECTS:%.o=%.d)
$(OUTDIR)/%.o : %.c
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
#$(CC) $(DEPFLAGS) -c $< -o $#
#$(POSTCOMPILE)
$(OUTDIR)/%.d : ;
.PRECIOUS: $(OUTDIR)/%.d
Directory structure looks like:
src
contains file.c
out
empty, after make: contains file.o and file.d
make
contains the makefile
When I call the makefile everything works fine and two files are generated: file.o and file.d
However, when I delete file.d nothing happens. I would expect that make finds a missing dependency for file.c and starts a rebuild. Why doesn't it happen?
Make version is 3.81 built for i386-pc-mingw32 under Windows 7.
Marking a file as .PRECIOUS does not remove all aspects of it's "intermediateness". All it does is prevent it from being deleted, but this feature of intermediate files is still in effect:
If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.
This is why your .d file is not recreated. In order for it to be recreated you need to ensure it's not an intermediate file. Fortunately this is trivial to do: you just need to mention the files explicitly somewhere as a target or prerequisite. You can do it like this:
all: $(OBJECTS) $(SOURCES:%.c=$(OUTDIR)/%.d)
Or if you prefer like this:
depends: $(SOURCES:%.c=$(OUTDIR)/%.d)
which would allow you to run make depends to update the dependency files, if you wanted to.
I'll just point out in passing that this method of managing dependencies is considered outdated. There's a better, more advanced way it can be done described here among other places.
(I'll be a horrific necromancer here, but I've ran into same problem, and found that actual issue isn't one mentioned in answer or comments here)
Dependency rule generated by compiler by default sports file name with ALL suffixes replaced by single suffix .o and path removed. Which doesn't match the pattern of rule in makefile.
For gcc 4.x and later correct options would be
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
#$(CC) -MF $(OUTDIR)/$*.Td -MT $# -c $< -o $#
Mo flag no longer exist, you have to use only MF flag to specify dependency file name.MT flag allows to provide a literal line for target name.

Makefile's 'vpath' doesn't work when searching prerequisites with wildcards

My project includes .c and .s (asm) files. I compile both types with 'gcc' and put output .o files to separate directory './bin'. To do that I'm using single makefile rule like this
bin/%.o: %.[cs]
$(CC) $(CFLAGS) -o $# -c $<
(As far as I understand, using square brackets wildcard in such context is a little bit unconventional, but it's working and it looks neat, so...)
The other day I decided to move some of my .c files to dedicated directory './common', so I added
vpath %.c common
at the beginning of the makefile. And now each time I try to 'make', it stops and throws an error on a file I had moved. For example, for 'common/foo.c' I get
"*** No rule to make target bin/foo.o, needed by..."
as if I haven't specified 'vpath'. But when I modify the rule to compile only .c files
bin/%.o: %.c
... ...
magically it starts to operate properly again and checks './common' for sources.
Looks like 'vpath' mechanism and wildcards can not work together, but I'm still new to 'make' and eager to learn what's the exact reason of such behavior. Any ideas anyone? Thanks in advance.
(Tested with make–3.81 and make–4.1.)
UPD: Having all the files and 'bin' directory reside on the same level like so
|-bin/
|-foo.c
|-bar.s
|-baz.c
|-Makefile
here's MWE
ROOTS = foo.o bar.o
OBJS = baz.o
SS = $(addprefix bin/,$(ROOTS) $(OBJS))
all: ff.out
ff.out: $(SS)
ld -o $# $^
bin/%.o: %.[cs]
gcc -o $# -c $<
Now if I move, say, 'foo.c' to separate directory and specify 'vpath', build stops with "No rule to make target bin/foo.o, needed by ff.out".
I suggest careful reading of How Not to Use VPATH as you seem to be at Step Three of that by having the OBJDIR in some places but not others.
To be explict, using a static pattern rule doesn't get you away from needing either at least one rule per source directory, or at least one make invocation per source directory. So, the simple answer is add a new rule for the new common/ directory that's the same as the other one:
bin/%.o: common/%.[cs]
gcc -o $# -c $<
There are lots of more comprehensive, but complex, answers, see the followon article for some of them.
For simple projects, there is no reason not to just track what directories you have in your main Makefile by adding extra rules. Also, there's a reasonable case for not having that bin/ dir and splitting .o and .out locations. Distributors and others expect to be able to control where files are created running from a seperate directory anyway.
I've thrown up a git repo with branches based on your cut down example that may clarify things.

Makefile doesn't rebuild the obj's when the CFLAGS are modified?

As we know that the binary depends on the obj's, and the obj's depends on the .c files ( assuming a C Project). Let's say, I have a env.mk file. This file has a flag like 'export NO_DISPLAY=YES'. In the main Makefile, I have the following.
ifeq ($(NO_DISPLAY),YES)
CFLAGS += -D__DISPLAY_DISABLE
endif
Obviously, env.mk is included in the main make file. whenever, I change the flag value 'NO_DISPLAY'. The makefile never rebuilts the executable again. However, the same works fine when the .o files are deleted. I understand that the reason behind it as it depends on the .c,.h files. The .c .h files are not modified, therefore makefile ignores to rebuild it. But, I would like makefile to rebuild the code if the CFLAGS value is changed. How can I do it? Please note, I don't want to delete the objs and rebuild it.
target_dbg: $(patsubst ./src/%.c,./obj_dbg/%.o,$(wildcard ./src/*.c))
#echo "Target main rule__dbg $(NPROCS)"
$(CC) $(patsubst ./src/%.c,./obj_dbg/%.o,$(wildcard ./src/*.c)) $(LIBS) -o gif_dbg
./obj_dbg/%.o: ./src/%.c ./include/*.h
#echo "I am called first..dbg"
#mkdir -p ./obj_dbg
#$(CC) $(CFLAGS) -E $<
$(CC) $(CFLAGS) $(LDFLAGS) -DDEBUG -c $< -o $#
Any help will be appreciated.
Make simply works by examining timestamps on files. You hardly want every build artefact to depend on your Makefile (at least not while actively developing it) but if you seriously want Make to handle this dependency, you could put the CFLAGS definition in a secondary file buildflags.mk, include it from the main Makefile, and make all object files depend on buildflags.mk.
I hardly think anybody would actually do this in practice, though. There will always be situations where the only way to be sure you get a clean build is to flush everything and start over. Make sure you have good and up-to-date realclean and/or distclean targets, and make sure you remember to use them when you make fundamental changes to your build infrastructure. Having a nightly build job (or similar) which starts the build from a completely clean slate -- e.g. by checking out a new copy into a temporary directory -- is also obviously a good idea.
Alternatively, or additionally, include a copy of the build flags as a static string in each object file, so you can verify them later, perhaps using a --help option or similar.
You could use make's -B option to force a rebuild each time you change your CFLAGS. See this answer.

Resources