prerequisite to make rule with empty recipe - makefile

I would like to know how to add a prerequisite to a rule with an empty recipe in GNU make. Here is a short example I made in order to explain the problem. I have a Test.c file which depends on a certain file header1.h, which includes another file header2.h. This is the make file:
Test : Test.c header1.h
gcc -o Test Test.c
header1.h : header2.h
The last row is not empty it contains a tab character. Now assume I run make and Test is created. Afterwards I change header2.h. If I run make again, make says that Test is already updated. I expected make to remake Test since header2.h is newer than header1.h.
If I add a trivial recipe to the last rule like this
Test : Test.c header1.h
gcc -o Test Test.c
header1.h : header2.h
echo foo
make behaves as I expected. I also tried adding a semicolon after header2.h in the prerequisite list but this did not help.

You've told make that Test depends on Test.c and header1.h, so it won't run the recipe unless either of the timestamps for those two files are newer than the one for Test.
You could add touch $# as a recipe for header1.h but logically it doesn't really depend on the content of header2.h, Test does, so you should add header2.h as a dependency of Test.
Ideally however you'd avoid manually specifying all this and use GCC's dependency generating flags, you can also take advantage of make's built-in rules, an absolutely minimal example for something like this with a single source file would be
CFLAGS := -MMD
Test:
-include *.d

Others already provided appropriate solutions: Compiler generated dependency files.
This does not answer the part of the question, why adding a "trivial recipe" (echo foo) changes anything. This probably is related to the following make bug.
As OP already found out, the bug can be circumvented by adding a trivial recipe (eg. #true). This causes make to re-evaluate the targets' "timestamp" which is why dependencies are respected expectedly.

Related

Make file Doesn't detect changes in source files

I am very much new to make files , I am facing very basic problem , My Makefile doesn't detect changes I made to source files . The problem is , when I first time generate consoleapp binary from my source file i get expected output . But When I change source file again and when I run make again it says
make: 'consoleapp' is up to date , So what changes I have to give to make file so that it detects my changes
Below is my Makefile :
consoleapp:
g++ consoleapp.cpp -o consoleapp
clean:
rm -rf *.o consoleapp
This is my Source File :
#include <iostream>
using namespace std;
int main()
{
cout<<"I am ok \n"; // I am changing this line again after giving make
return 0;
}
make relies on the makefile author to tell it what each target's prerequisites are -- that is, which other targets or files affect the construction of the target in question, so that if they are newer or themselves out of date then the target is out of date and should be rebuilt. As your other answer already indicates, you do not designate any prerequisites for your targets, so make considers them out of date if and only if they don't exist at all.
That's actually problematic for both targets, albeit in different ways. For target consoleapp, which represents an actual file that you want to build, the failure to specify any prerequisites yields the problem you ask about: make does not recognize that changes to the source file necessitate a rebuild. The easiest way to fix that would be to just add the source file name to the recipe's header line, after the colon:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o consoleapp
Generally speaking, however, it is wise to minimize duplication in your makefile code, and to that end you can use some of make's automatic variables to avoid repeating target and prerequisite names in your rule's recipe. In particular, I recommend always using $# to designate the rule's target inside its recipe:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o $#
It's a bit more situational for prerequisites. In this case, all the prerequisites are source files to be compiled, and furthermore there is only one. If you are willing to rely on GNU extensions then in the recipe you might represent the sources via either $< (which represents the first prerequisite), or as $^ (which represents the whole prerequisite list, with any duplicates removed). For example,
consoleapp: consoleapp.cpp
g++ $^ -o $#
If you are not using GNU make, however, or if you want to support other people who don't, then you are stuck with some repetition here. You can still save yourself some effort, especially in the event of a change to the source list, by creating a make variable for the sources and duplicating that instead of duplicating the source list itself:
consoleapp_SRCS = consoleapp.cpp
consoleapp: $(consoleapp_SRCS)
g++ $(consoleapp_SRCS) -o $#
I mentioned earlier that there are problems with both of your rules. But what could be wrong with the clean rule, you may ask? It does not create a file named "clean", so its recipe will be run every time you execute make clean, just as you want, right? Not necessarily. Although that rule does not create a file named "clean", if such a file is created by some other means then suddenly your clean rule will stop working, as that file will be found already up to date with respect to its (empty) list of prerequisites.
POSIX standard make has no solution for that, but GNU make provides for it with the special target .PHONY. With GNU make, any targets designated as prerequisites of .PHONY are always considered out of date, and the filesystem is not even checked for them. This is exactly to support targets such as clean, which are used to designate actions to perform that do not produce persistent artifacts on the file system. Although that's a GNU extension, it is portable in the sense that it uses standard make syntax and the target's form is reserved for extensions, so a make that does not support .PHONY in the GNU sense is likely either to just ignore it or to treat it as an ordinary rule:
.PHONY: clean
clean:
rm -rf *.o consoleapp
because your target has no dependence. Please use this codes that rely to all cpp file in current dir to update binary.
SRCS=consoleapp.cpp
consoleapp: $(SRCS)
g++ $< -o $#

Nothing to be done for 'all'

Im trying to run this simple makefile commands but get the error - 'Nothing to be done for 'all''
FILES = file1.c file2.c file3.c
all:test
test:
for file in $(FILES);
do
echo $$file;
done
The target test has no dependencies and therefore no reason to be built, which is inherited by the target all. It has instructions, but it should include FILES as its prerequisites. What you're doing appears to be ingredients-first, but test is the target. Working backwards is what make is best at. You may benefit from an article called "Auto-Dependency Generation" which takes the opposite approach (you appear to think like I do.)
test: $(FILES)
Then you could do something like the following:
$(FILES:.o:.c): %.o: %.c
$(CC) -c -o $# $<
The first part is a set of possible targets, the list of objects corresponding to the list of sources, and the second is a specific but nameless object (it will assume the name of the corresponding source.) Later on, the target, e.g. test, can be the name of your executable taking these objects as both dependencies and objects to link statically. For my purposes I typically use shared libraries but this is irrelevant to the question at hand.
Edit: untested, will revise if issues ensue

Makefile: Declaring dependencies between included files

Using make's ''Remaking Makefiles'' feature I am generating parts of my makefile with include directives (see Makefile: defining rules and prerequisites in recipes). Now I'm stuck with being unable to see how I can express dependencies between included makefiles. They seem to be all evaluated at once.
Consider the following minimal makefile that illustrates my problem:
all:
-include foo.make
-include bar.make
foo.make: Makefile
echo FOO:=blub bla baz > foo.make
bar.make: Makefile foo.make
echo BAR:=$(FOO) > bar.make
If I now run make I will get:
$ cat foo.make
FOO:=blub bla baz
$ cat bar.make
BAR:=
Why? Since bar.make depends on foo.make, shouldn't the evaluation of bar.make wait until it successfully included foo.make?
And how do I fix this problem and make sure that bar.make is either re-evaluated later or only evaluated once foo.make exists, is included and can define the variable BAR?
The reason I cannot combine foo.make and bar.make into a single makefile and rule is two-fold:
Firstly, in my real setup, bar.make depends on more intermediate targets which in turn transitively depend on foo.make. So at the time foo.make can be created, the content of bar.make cannot yet be made.
Secondly, in my real setup, foo.make and bar.make do not just define variables but also eval() define/endef blocks. So I have to write:
-include makefile_with_prerequisite_variables
define MYDEF
sometarget-$1: $(TARGET_$1_PREREQUISITES)
[...]
endf
-include makefile_with_eval_call_statements
The content of makefile_with_prerequisite_variables and makefile_with_eval_call_statements cannot go into a single makefile snippet:
If I would put makefile_with_eval_call_statements above MYDEF together with makefile_with_prerequisite_variables then the $eval( $call( MYDEF)) statements in it would not work because MYDEF is only declared afterward.
If I would put makefile_with_prerequisite_variables below MYDEF together with makefile_with_eval_call_statements then the recipes defined in MYDEF would not have proper prerequisits because the $(TARGET_$1_PREREQUISITES) variables would then be declared afterward by makefile_with_prerequisite_variables.
In summary, I need to include two different makefiles where one depends upon the other. I do not know how I can express this relationship such that the content of one makefile would only be created after the other makefile is up-to-date and included into the main makefile.
First, your makefile creation in this simple example can easily be fixed by escaping the value of $(FOO) so that it's not expanded when bar.make is created but rather deferred until it's read in. So:
bar.make: Makefile foo.make
echo 'BAR:=$$(FOO)' > $#
However, that might not be sufficient in your more complex real-life makefiles.
GNU make works like this: first parse all the makefiles. Then for every included makefile, treat it as a goal and try to build it (e.g., act as if the user invoked make include1.mk include2.mk include3.mk ...). Then at the end of that, if any of the included makefiles was rebuilt, re-exec ourselves and start the entire process over from scratch.
GNU make does NOT work like this: parse makefiles, try to rebuild the first included makefile and if it's rebuilt, re-exec; if it's not rebuilt go on to the next included makefile, etc.
A simple trick you can use if you have to have this type of order is to put the include of bar.make into foo.make:
all:
-include foo.make
foo.make: Makefile
printf -- '-include bar.make' > $#
echo FOO:=blub bla baz >> $#
bar.make: Makefile foo.make
echo 'BAR:=$$(FOO)' > $#
By doing this you ensure that if foo.make doesn't exist, make can't see the include of bar.make and so it won't try to build it. Only after the first re-exec will make see the include of bar.make and try to build it.
One thing: if you get the latest version of GNU make you no longer need to use the -include trick. You can just use include even with generated makefiles.

makefile conditionals

Note: using MinGW's make (should be GNU make)
i have a couple of -include statements in my makefile to import dependencies which were generated using g++ -MM. However I would like to only do this when necessary. I have several different build targets and I don't want all of their respective dependency files to be included since this takes a while (suppose I'm running make clean: no need to include them in this case)
Here's the format of my makefile.
DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
all: program_debug
-include $(DEPS_debug) #make: include: Command not found
program_debug: $(OBJ_debug)
$(CC) $(CFLAGS) $(OBJ_debug) -o $#
If you really don't want to include those files needlessly, you have a couple of options:
You can put in a conditional as Diego Sevilla suggests (but I would recommend using MAKECMDGOALS so that you can write a more flexible version, specific to targets, e.g. you'll include foo.d if and only if you're making foo.o).
You can use make recursively (heresy!), invoking $(MAKE) for each target object, using a makefile that includes that target's dependencies.
But actually including the file takes negligible time, it's the rebuilding of the file (automatic for any included file that's out of date) that takes time.
If needless rebuilding is what you want to avoid, you can use a very clever trick. When must foo.d be rebuilt? Only when something about foo has changed. But in that case foo.o must also be rebuilt. So don't have a seperate rule for foo.d, just rebuild it as a side effect of making foo.o. That way you can include all dependency files and not waste time rebuilding them if they aren't needed.
EDIT:
I'm astounded that merely including these files can add 2-3 seconds to make clean. My last paragraph is off the mark, so let me expand on the first two options.
If all is the only target for which these files should be included, and you make all from the command line (and not e.g. make all tests tarball install kitchenSink), then this will do it:
ifeq ($(MAKECMDGOALS),all)
-include $(DEPS_debug)
endif
Note that this will not include foo.d if you make foo.o. You can write a more sophisticated conditional, something like
$(foreach targ,$(MAKECMDGOALS),$(eval $(call include_deps $(targ)))...
but that's pretty advanced, so let's get a simple version working first.
If you'd rather avoid the conditional and use recursive Make, the simplest way is to split the makefile in two:
makefile:
all:
$(MAKE) -f makefile.all
clean:
rm whatever
...other rules
makefile.all:
DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
-include $(DEPS_debug)
all: program_debug
program_debug: $(OBJ_debug)
$(CC) $(CFLAGS) $(OBJ_debug) -o $#
Indenting a line by a TAB makes make think it's a command to be passed to the shell (as you found out). It doesn't work that way.
The - in front of include suppresses errors that might result from DEPS_debug not existing (e.g. when running clean or release without having had a dependency-file-generating call first). Since DEPS_debug is not a dependency of those rules (clean / release), your dependency files do not get generated when you call them, and everything is fine. I don't really see the problem you're having - you don't have to make the include conditional.
Perhaps you'd like to change your approach, though. Instead of having a seperate *.d target, with a seperate -M preprocessor pass, you might want to try something like -MMD -MP which generates the dependency files inline during code generation, in your standard *.c -> *.o pass.
(I know this sounds completely wrong at first, but when you think about it, it makes sense. Makefile logic is a bit backwards that way, unless you're familiar with functional programming.)
includes are independent of the rules, as they are makefile indications, not compilation indications. You can, however, use makefile conditionals based on special makefile variables such as MAKECMDGOALS, that is set to the default goal:
ifeq ($(MAKECMDGOALS),all)
-include whatever
endif
This is included when no default goal is specified. You can change the condition to specify the exact goal you want to check to include other sub-makefiles.

making all rules depend on the Makefile itself

When I change a Makefile, its rules may have changed, so they should be reevaluated, but make doesn't seem to think so.
Is there any way to say, in a Makefile, that all of its targets, no matter which, depend on the Makefile itself?
(Regardless of its name.)
I'm using GNU make.
This looks like one more simple, useful, logical thing that Make should be able to do, but isn't.
Here is a workaround. If the clean rule is set up correctly, Make can execute it whenever the makefile has been altered, using an empty dummy file as a marker.
-include dummy
dummy: Makefile
#touch $#
#$(MAKE) -s clean
This will work for most targets, that is targets that are actual files and that are removed by clean, and any targets that depend on them. Side-effect targets and some PHONY targets will slip through the net.
Since GNU make version 4.3 it is now possible with the use of those two special variable:
.EXTRA_PREREQS
To add new prerequisite to every target
MAKEFILE_LIST
To get the path of the make file
To have every target depend on the current make file:
Put near the top of the file (before any include since it would affect the MAKEFILE_LIST) the following line:
.EXTRA_PREREQS:= $(abspath $(lastword $(MAKEFILE_LIST)))
To have every target depend on the current make file and also the make files which were included
Put the following line at the end of your file:
.EXTRA_PREREQS+=$(foreach mk, ${MAKEFILE_LIST},$(abspath ${mk}))
The only answer I know to this is to add makefile explicitly to the dependencies. For example,
%.o: %.c makefile
$(CC) $(CFLAGS) -c $<

Resources