make file - ignoring .c files in prerequisites for implicit rules - makefile

I am learning make from GNU documentation: https://www.gnu.org/software/make/manual/make.html#Overview .
(1) I am confused on which .c files we can omit when specifying the prerequisites for a target which has an implicit rule. For eg:
ex: books.o
cc -o ex books.o
books.o : hello.c hello.h books.c books.h lib.c
cc -c hello.c books.c lib.c
In the above example can I ignore the recipe (make it implicit) for the target books.o , i.e. can I write
books.o : hello.h books.h
even though there is no lib.c?
(2) The documentation didn't mention (so far) what is 'cc'? Is it 'gcc'?

Related

Writing compilation rule before linking rule in makefile doesn't produce executable [duplicate]

My makefile have two lines:
Rule_1
File.o : File.cpp
g++ -c File.cpp -o File.o
Rule_2
File : File.o
g++ File.o -o File
I want any change in File.cpp leads to regeneration of both File.o and File. This is done by:
Makfile:
Rule_2
Rule_1
But the following does not work and only regenerates File.o
Rule_1
Rule_2
Why? I note that, I am not using any all: in my makefile. With all: File both methods above work.
I assume your make tool is GNU Make.
Unless you specify targets on the commandline, like:
make File
make will by default attempt to make the first target
in the makefile, which in your problem case is File.o.
See How make Processes a Makefile
When you add:
all: File
at the top, all is the first target, which depends on File,
which in turn depends on File.o.
And I suggest you replace that with:
.PHONY: all
all: File
See Phony targets

Right way to use VPATH/vpath?

I am trying to use my Makefile (Make for Windows) by adding source paths to vpath/VPATH. This seems trivial but for some reason I am unable to get it to work
My directory structure is like this:
├── Makefile
├── out\
└── src\
└── hello.cpp
My Makefile is:
TGT=out
OBJ=hello.o
VPATH=src
# vpath %.cpp src
all: $(TGT)\app.exe
$(TGT)\app : $(TGT)\$(OBJ)
g++ $^ -o $#
$(TGT)\%.o : %.cpp
g++ -Wall -Wextra -Werror -c $<
changing to vpath didn't help me. I seem to have something fundamentally wrong here. The error I see is:
make: *** No rule to make target `out\hello.o', needed by `out\app'. Stop.
EDIT: debug output from make -d
Considering target file `all'.
File `all' does not exist.
No implicit rule found for `all'.
Considering target file `out\app'.
File `out\app' does not exist.
Considering target file `out\hello.o'.
File `out\hello.o' does not exist.
Looking for an implicit rule for `out\hello.o'.
Trying pattern rule with stem `hello'.
Looking for a rule with intermediate file `out\hello.cpp'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `hello.cpp'.
No implicit rule found for `out\hello.o'.
Finished prerequisites of target file `out\hello.o'.
Must remake target `out\hello.o'.
As MadScientist points out you should avoid backslashes as they have odd results like this, had you used forward slashes throughout your Makefile you wouldn't have had this issue, that said it is possible to work around them.
There are a few things wrong here:
You haven't posted the same Makefile you're using again, the first rule after all should have $(TGT)\app.exe as a target.
A backslash before % in a pattern rule will turn it into a literal %, escape the backslash
You forgot to tell gcc where to output the object file
Once you've fixed all of this you should find vpath works as expected, the complete fixed Makefile is
TGT=out
OBJ=hello.o
vpath %.cpp src
all: $(TGT)\app.exe
$(TGT)\app.exe : $(TGT)\$(OBJ)
g++ $^ -o $#
$(TGT)\\%.o : %.cpp
g++ -Wall -Wextra -Werror -c $< -o $#

How to create a makefile that will place object code in different folder

I am very new to Makefile. I had build the following makefile(Which don't work).I wan't put genarated object codes in differnt folder(the folder is in current directory).
$ ls
main.cpp Makefile object_code Time.cpp Time_.h
how can I do this ??
VER = Debug
CC = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
clean:
rm $(OBJECTFIELS) main
this is error.
$ make
g++ ./object_code/main.o ./object_code/Time.o -o ../Debug/main
g++: error: ./object_code/main.o: No such file or directory
g++: error: ./object_code/Time.o: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:8: recipe for target '../Debug/main' failed
make: *** [../Debug/main] Error 1
please this is last question.
I don't see how you can possibly get that output given the makefile you've posted here.
Either the object files already exist in which case the link will succeed rather than printing that error.
Or the object files don't exist in which case make will complain because it doesn't know how to make them. There must be some difference between the makefile you're using and the one you've posted here.
In any event, make knows how to build a file foo.o from a file foo.cpp for any string foo. There's a built-in rule that tells it how to do that.
But, make doesn't know how to build a file ./object_code/foo.o from a file foo.cpp, regardless of foo. There's no built-in rule that tells make how to build object files in some random other directory. If you want make to do that, you'll have to tell it how. You should remove the lines:
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
and replace them with a pattern rule describing how to build object files into the object_code directory (I'm using CXX as the compiler variable here: by convention CC is the C compiler and CXX is the C++ compiler, and you should always stick with convention unless there's a good reason not to):
VER = Debug
CXX = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CXX) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/%.o : %.cpp
$(CXX) -c -o $# $<
clean:
rm $(OBJECTFIELS) main

What is the importance of target in makefile?

I am learning how to create makefile on a Linux distro.
I am using the following code (I know it can be written in a small form, but the long form is intentional) to properly understand the behavior of makefile
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
clean:
rm test.o
Now, when I use make and make clean in the shell, they are working as intended.
However, I want to know the importance of target in makefile. Hence, started by changing test.o: test.c line to test2.o: test.c and typed make in the shell; my initial guess was that there would be a file in my home directory called test2.o, but that's not the case, I still see test.o being created again.
So, the above behavior begs my question, what is the important of target component in makefile?
The 'target' is the file which Make checks to determine whether it needs to execute the commands associated with the target at all.
I.e. if you change test.o: test.c to test2.o: test.c, Make sees that test2.o does not exist and hence executes the command cc -c test.c -- which still only creates test.o. Hence, if you re-run make, you will see that the compiler is executed again because test.o still does not exist.
In the original version, test.o: test.c, the compiler will only be executed if test.o does not exist, or if the modification time of test.c is newer than that of test.o.
The target becomes available in the commands section as a variable $#, which can be used to define what gets built.
In your makefile you had:
test2.o: test.c
cc -c test.c
Because you didn't tell the compiler what the output would be as part of the cc command, it created test.o from test.c, which is the default behaviour. If you run cc -c file.c it will generate file.o by default.
You need to specify the destination file as part of the commands run for generating the target, so:
test2.o: test.c
cc -c test.c -o $#
Would cause the compiler to generate the test2.o file appropriately.
At a fundamental level, a makefile is nothing more that a set of targets, dependencies for the targets and the sets of commands for making those targets. You have to ensure that as part of the build process, the final product from a set of commands is the target in order to have a properly functioning makefile.
The compiler doesn't know anything about the fact that it's being run in the makefile.
There are a bunch of automatic rules, pre-created by the default make system. These include rules for making .o files from .c files - it knows that it needs to compile a file using the following rule and commands:
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
where COMPILE.c:
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
and OUTPUT_OPTION is:
OUTPUT_OPTION = -o $#
CC defaults to cc, CFLAGS defaults to empty, CPPFLAGS defaults to empty and TARGET_ARCH defaults to empty. You can see these definitions using make -p
So the resulting command is:
cc -c -o $# $<
Where $# is the name of the target and $< is the first item in the list of dependencies. This pattern matches all target files called <something>.o where there is an existing file called <something>.c. If there's a request to build test.o as a target then it will compile a file called test.c, because that file exists and matches these rules.
tl;dr
Your test2.o rule is never executed. test.o is created by make's implicit rule.
Let's take this apart.
test.o: test.c
cc -c test.c
This is a rule.
The general syntax for a rule is:
targets : prerequisites
recipee
So, test.o is the target, and test.c the prerequisite.
If:
the target (file) does not exist, or
(one of) the prerequisite(s) is newer than the target,
the recipee is executed (which should, but does not have to, create the target).
So, let's look at your Makefile:
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
When you say make test, you want to create the target test. This target has test.o as prerequisite.
For test.o exists another rule, with test.c as prerequisite. So that rule gets checked and executed first (compiling your source to object code), before the test prerequisite is checked, and the recipee run if required (linking your object code to executable format).
Hence, started by changing test.o: test.c line to test2.o: test.c and typed make in the shell; my initial guess was that there would be a file in my home directory called test2.o, but that's not the case, I still see test.o being created again.
No target has a test2.o prerequisite, and you did not ask for that to be build specifically (make test2.o), so the recipee for test2.o is never executed.
But test still has test.o as a prerequisite. As there is no explicit rule for a target of that name in your Makefile, make substitutes it with its implicit rule for creating a .o file from an existing .c file...
The default output file from cc -c test.c is test.o. If you want it to create test2.o, you need to tell it explicitly:
test2.o: test.c
cc -o test2.o -c test.c
cc doesn't know anything about the makefile or what target it's being run from.
The importance of targets is that they're used for finding all the dependencies. So the first rule in your makefile says that test is dependent on test.o: before you can create test, you first need to create test.o, and if test.o has changed, you need to rebuild test.
The commands below the target are expected to do whatever it takes to create the target. But you have to code that explicitly (although there are some macros that can automatically substitute targets and dependencies into the command line -- these are mostly useful when the target contains a wildcard pattern).

What are double-colon rules in a Makefile for?

Section 4.13 of the GNU Make manual describes the so-called double-colon rules:
Double-colon rules are rules written with ‘::’ instead of ‘:’ after the target names. They are handled differently from ordinary rules when the same target appears in more than one rule.
When a target appears in multiple rules, all the rules must be the same type: all ordinary, or all double-colon. If they are double-colon, each of them is independent of the others. Each double-colon rule's commands are executed if the target is older than any prerequisites of that rule. If there are no prerequisites for that rule, its commands are always executed (even if the target already exists). This can result in executing none, any, or all of the double-colon rules.
Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.
The double-colon rules for a target are executed in the order they appear in the makefile. However, the cases where double-colon rules really make sense are those where the order of executing the commands would not matter.
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Each double-colon rule should specify commands; if it does not, an implicit rule will be used if one applies. See section Using Implicit Rules.
I kinda grok the meaning of each sentence of this section individually, but it's still not clear to me what double-colon rules are for. As for being rare, I have not yet seen any open-source project whose Makefile did not begin with
all::
Therefore: What's the intended purpose of double-colon rules in Makefiles?
Each :: rule is processed independently, so it can be simpler. For example, the single rule:
libxxx.a : sub1.o sub2.o
ar rv libxxx.a sub1.o
ar rv libxxx.a sub2.o
can be replaced with two simpler rules:
libxxx.a :: sub1.o
ar rv libxxx.a sub1.o
libxxx.a :: sub2.o
ar rv libxxx.a sub2.o
Utilities like AutoMake have an easier time spitting out many simple rules than a few complex ones.
A great answer with more examples was posted, then taken down, then found here:
https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html
Thanks to R.K. Owen for writing it, and Edward Minnix for finding it again!
There are 3 situations where the double colon are useful:
Alternate between the compile rules based on which prerequisite is newer than the target. The following example is based on "Example 19-3. Double-colon rules" from http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html
Sample .c file:
c#desk:~/test/circle$ cat circle.c
#include <stdio.h>
int main (void)
{
printf("Example.\n");
return 0;
}
Makefile used:
c#desk:~/test/circle$ cat Makefile
# A makefile for "circle" to demonstrate double-colon rules.
CC = gcc
RM = rm -f
CFLAGS = -Wall -std=c99
DBGFLAGS = -ggdb -pg
DEBUGFILE = ./debug
SRC = circle.c
circle :: $(SRC)
$(CC) $(CFLAGS) -o $# -lm $^
circle :: $(DEBUGFILE)
$(CC) $(CFLAGS) $(DBGFLAGS) -o $# -lm $(SRC)
.PHONY : clean
clean :
$(RM) circle
Outcome:
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
make: *** No rule to make target 'debug', needed by 'circle'. Stop.
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
c#desk:~/test/circle$ vim circle.c
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
c#desk:~/test/circle$ vim debug
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
Make a pattern rule terminal.
The following example explains this situation: the a.config file is obtained from a.cfg, which in turn is obtained from a.cfg1 (a.cfg being the intermediate file).
c#desk:~/test/circle1$ ls
a.cfg1 log.txt Makefile
c#desk:~/test/circle1$ cat Makefile
CP=/bin/cp
%.config:: %.cfg
#echo "$# from $<"
#$(CP) $< $#
%.cfg: %.cfg1
#echo "$# from $<"
#$(CP) $< $#
clean:
-$(RM) *.config
Outcome (as the %.config rule is terminal, make inhibits the creation of the intermediate a.cfg file from a.cfg1):
c#desk:~/test/circle1$ make a.conf
make: *** No rule to make target 'a.conf'. Stop.
Without the double colon for the %.config, the outcome is:
c#desk:~/test/circle1$ make a.config
a.cfg from a.cfg1
a.config from a.cfg
rm a.cfg
Make a rule that executes always (useful for clean rules). The rule must not have prerequisites!
c#desk:~/test/circle3$ cat Makefile
CP=/bin/cp
a.config::
#echo "Always" >> $#
a.config::
#echo "Always!" >> $#
clean:
-$(RM) *.config
Outcome:
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
Always
Always!
They are handy for non-recursive makefiles and targets like clean. That is, an individual .mk file can add its own commands to the clean target already defined elsewhere.
Documentation gives an answer:
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Just as the documentation says, double-colon rules are rarely very useful. They are a nice, little way of not naming the individual targets of a composite phony target (like all::), but not really necessary in this role. I can only form one contrived example where they are necessary:
Suppose you have a logfile L that is concatenated from several other logfiles L1, L2, .... You formulate a number of double-colon rules like:
L :: L1
cat $< >> $# && rm $<
L :: L2
cat $< >> $# && rm $<
Nowadays in GNU make, you would of course use $^ for this kind of magic, but it is listed as an inspired feature on GNU make's feature tab.
I'll contribute a simple example to hopefully make the usage clear:
Experiment with the following makefile:
a.faux:: dep1.fake
$(info run a dep1.fake)
touch a.faux
a.faux:: dep2.fake
$(info run a dep2.fake)
touch a.faux
dep1.fake:
touch dep1.fake
dep2.fake:
touch dep2.fake
Run make a.faux, it will causes dep1.fake and dep2.fake to run. Delete dep1.fake and run make a.faux again, only dep1.fake will run.

Resources