Generated prerequisite not triggering rebuild - makefile

I have the following Makefile:
.PHONY: version
OBJECTS = $(C_SOURCES:.c=.o)
%.o: %.c Makefile version.h
$(call make_dir,$(dir $#))
$(CC) -c $(CFLAGS) $< -o $#
version.h: version
version:
$(PYTHON_EXE) build/version.py
version.h contains the current git commit hash. build/version.py updates version.h, if the current git commit hash is different (no changes if the commit hash is the same)
I want to run build/version.py everytime make is run, so version.h is always up to date. This is currently working, but if version.h changes my object files aren't being re-compiled. They get re-compiled the NEXT time I run make.

That's because version.h doesn't have an actual rule associated with it, and the other target tells make it builds version, not version.h. So, make doesn't think that version.h was actually changed.
Give it a recipe, even an empty recipe, so make will understand it might have changed:
version.h: version ;
(the semicolon adds an empty recipe)

Related

Delete targets with recipes failed in 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)

Makefile builds target even if prerequisites haven't changed

Most makefiles have a structure such as this:
.PHONY: prebuild
all: $(TARGET)
prebuild: Makefile
$(shell DEPDIR=$(DEPDIR) mkdir -p $(DEPDIR)/../common >/dev/null)
# do other work related to preparing for the object files to be built such as run a script to modify a header file included by $(TARGET).c
$(TARGET): $(TARGET).c prebuild
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c
The implicit rules know how to build $(TARGET).o from $(TARGET).c, and doesn't do any work if $(TARGET).o is already newer than $(TARGET).c. This happens when make is run multiple times without changing the source file.
However, building the all target above will seemingly always rerun the $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c link to link the application and create the application binary. This happens even if that binary already exists and doesn't need to be recreated. In some larger projects, this process can take a long time (tens of seconds), which is sometimes not desirable.
Edit #1: The issue has to do something with an extra phony target that I do want to run ONCE before the object files are built. In my case, I'm running a script which takes Makefile variables and possibly updates a header file that is included in the C file. But, if the Makefile doesn't change, the prebuild target isn't run. However, the $(TARGET) target is still run even if prebuild doesn't do anything (for instance, because Makefile wasn't changed). FYI: because of the structure of my build system, I have prebuild run always because my build system is used for a variety of applications that can dynamically redefine prebuild.
How can this Makefile be restructured to not do the linking again when not necessary?
Edit #2:
Here's a simplified example that seems to illustrate my issue:
Before running, create a new directory and touch a b
.PHONY: prebuild main all
all: main
prebuild: a Makefile
#echo prebuild ran
main: prebuild
#echo main ran
When I run, I get this output:
prebuild ran
main ran
This is what happens no matter how many times I run make, even though the prerequisite a nor Makefile doesn't change. What I expect to happen is prebuild doesn't run (because a and Makefile don't change) and main also doesn't run because prebuild doesn't run. Clearly, I'm misunderstanding something.
The problem is that extra dependency triggering your rebuild.
Try this:
.PHONY: all
OUTPUTDIR=common/
TARGET=finalexe
all: $(OUTPUTDIR)/$(TARGET)
$(OUTPUTDIR)/$(TARGET): $(TARGET).c | $(OUTPUTDIR)
$(CC) $(CFLAGS) -o $# $(TARGET).c
$(OUTPUTDIR):
mkdir -p $#
In this above example, 'finalexe' will be created if A. it doesn't yet exist or B. if finalexe.c was modified. The timestamp on the OUTPUTDIR is not checked.

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 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