What invokes this pattern matching rule? - gcc

I have this Makefile which seems to be working, but I'm not sure how:
EXECUTABLE=hello
CC=gcc
OBJS = a.o
all: $(EXECUTABLE)
%.o : %.c
$(CC) -o $# -c $<
$(EXECUTABLE): $(OBJS)
$(CC) -o $# $<
I know the top 3 lines are local defines, and when I type "Make" it will build the all target. Now from here I'm a little lost... I'm guessing:
Make sees the $(EXECUTABLE) label and jumps the that build command
it sees the $(OBJS) label and since a.o doesn't exist in the local directory it jumps to the pattern matching rule
Make finds a.c and runs the rule to generate a.o
Now Make returns to the $(EXECUTABLE) command and runs the combination of .o files to make the "hello" program
Questions:
Is my understanding of that flow correct?
Is the placement of the "label"s in this file relevant?
Is there some GNU documentation that I'm missing which confirms my suspicions of how this is working?

Your flow is basically correct. Make will build the first target listed in the file if you do not explicitly pass one on the command line. In most makefiles people will have all as the first target so like in your example you can just type make and it will automatically build the all target. What make does internally is build a list of dependencies that you are defining in your Makefile. all is dependent on $(EXECUTABLE) which is dependent on $(OBJS). In order to satisfy the the creation of the all target it has to start at the bottom of that dependency list and work its way up. The make manual is actually very good if you want to take a look here: http://www.gnu.org/software/make/manual/ and notably to your specific question here: http://www.gnu.org/software/make/manual/make.html#How-Make-Works

I found a tool to help answer to one part of my question at least, so I'll post it for the reference of myself and others:
It is possible to "debug" a Makefile via $(warning <some string>) calls.
So in my example I used it as such:
all: $(warning All before exe call) $(EXECUTABLE)
$(warning All warning after call)
%.o : %.c
$(warning before pattern)
$(CC) -o $# -c $<
$(warning after pattern)
$(EXECUTABLE): $(warning before obj) $(OBJS)
$(warning after obj)
$(CC) -o $# $<
And got the output showing me the flow:
mike#mike-VirtualBox:~/C$ make
Makefile:6: All before exe call // started at all
Makefile:14: before obj // Jumped to EXECUTABLE label
Makefile:10: before pattern // Jumped to pattern matching
Makefile:10: after pattern
gcc -o a.o -c a.c
Makefile:15: after obj // back to EXECUTABLE label
Makefile:15: after build // back to build command
gcc -o hello a.o
Makefile:7: All warning after call
Using this I discovered that I could do this:
$(EXECUTABLE): $(warning before obj) $(OBJS)
but not:
$(EXECUTABLE):
$(warning before obj)
$(OBJS)
Which makes sense since white space is important in Makefiles

Related

Makefile: no rule to make target '%.o', needed by '%'. Stop

I got the following error:
make: *** No rule to make target cardemo.o, needed by cardemo.exe. Stop
Trying to make this makefile
#Makefile for djgpp
#ALLEG =-lalleg
CC =gcc
OBJECTS = cardemo.o
all: cardemo.exe
#executables
cardemo.exe:$(OBJECTS)
$(CC) $(OBJECTS) $(ALLEG) -o $#
clean:
del *.o
del cardemo.exe
This is my first time creating a makefile with the help of Tutorials and Templates from Google just some days ago so excuse me if you find other mistakes thanks.
According to [GNU]: Catalogue of Built-In Rules:
Compiling C programs
n.o is made automatically from n.c with a recipe of the form $(CC) $(CPPFLAGS) $(CFLAGS) -c.
Example:
cardemo.c:
int main()
{
return 0;
}
Makefile:
#Makefile for djgpp
#ALLEG = -lalleg
#CC = gcc
OBJECTS = cardemo.o
all: cardemo.exe
#executables
cardemo.exe: $(OBJECTS)
$(CC) $(OBJECTS) $(ALLEG) -o $#
clean:
del *.o
del cardemo.exe
Output:
(qaic-env) [cfati#cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q075071635]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> ls
Makefile cardemo.c
[064bit prompt]> make
cc -c -o cardemo.o cardemo.c
cc cardemo.o -o cardemo.exe
[064bit prompt]> ls
Makefile cardemo.c cardemo.exe cardemo.o
Everything went fine, so the only logical conclusion one could draw is that you don't have a file called cardemo.c in the same directory.
If you modify OBJECTS related line (to OBJECTS = cardemo_notexist.o), you will get the same error.
To get past this, either:
Rename the source file from whatever name has now (could it be carddemo.c ?) to cardemo.c
Note: as #Mopower mentioned in a comment, original was Cardemo.c
Rename the object name so it has the source file stem name: OBJECTS = sourcefile_name.o
If renaming any of the 2 items above is not an option (or maybe cardemo.c is located in a different directory), add a compilation rule that will build cardemo.o from sourcefile_name.c:
cardemo.o: sourcefile_name.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
The problem is that you have putted $(OBJECTS) in the dependencies spot, which means makefile will need to make that file first (if it doesn't exist), so you should add a rule to make objs from c file like this:
%.o: %.c
$(CC) -o $# -c $<
$# means the target name, $< means the first dependency (You can also use $^ here, $^ means all the dependencied).

Problems with building from target - Makefile

This might be a very stupid question but I have never really used Makefiles in a sophisticated way and at my first try to "step it up" i ran into the following problem:
I have 4 targets where run is the one I want to call to build my source.
run > the main target
exec > builds the executable
%.o > supposed to compile the source
source > connects the source files
The structure in priciple is as follows:
run: source exec
source:
$(eval SOURCE := file1.f90)
$(eval SOURCE += file2.f90)
...
$(eval OBJECTS := $(SOURCE:%.f90=%.o))
exec: $(OBJECTS)
$(FC) $(FLAGS) -o $# $(OBJECTS)
%.o: %.f90
$(FC) -c $(FLAGS) -o $# $<
From what I understood from the manual is that the compile target represents an implicit rule and all of the "missing" objects should be generated once exec is called. Unfortunately, I get the error that the object files can't be found ifort: error #10236: File not found: 'file1.o' (because of no compilation) and now I'm wondering what I do wrong?
Any help appreciated!
Your source rule is not correct. Those assignments should not be in a rule. And since you are hard-coding the source names, you might as well hard-code the object names instead:
OBJECTS := file1.o
OBJECTS += file2.o
...
The next two rules look correct, but you can use $^ in the exec rule:
exec: $(OBJECTS)
$(FC) $(FLAGS) -o $# $^
%.o: %.f90
$(FC) -c $(FLAGS) -o $# $<
Then the run rule (which should be the first) can be like this:
run: exec
./$#
I don't use Fortran, so I haven't tested this; if it doesn't work, tell us the exact error message in a comment, and we'll troubleshoot.

Running Makefile targets

I am trying to 'fire' off the compilation by making all dependencies in a list of items, which are themselves targets.
From the answer (last, posted by Carl..) given in seems to suggest that something like this is possible.
Wildcard targets in a Makefile
all: $(OBJECTS)
OBJECTS = foo.o bar.o
bar.o: bar.c
#echo make $#
foo.o: foo.c
#echo make $#
.PHONY: all
My question is, when I run make I get the following, I cannot seem to get it to compile.
make: Nothing to be done for `all'.
Reverse the order of the first two lines, like so:
OBJECTS = foo.o bar.o
all: $(OBJECTS)
In your example, when Make gets to the all rule, OBJECTS has not yet been defined, so it resolves to this:
all:
Make sees a rule with no commands and no prerequisites-- nothing to be done.
You can do something like
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
This means:
To make a .o file, we need a .c file with the same name ( represented by %). The command to make the .o file is the name of the C compiler $(CC), followed by any compiler flags $(CFLAGS), then -c, etc. $< is the name of the first prerequisite ($^ is the names of all prerequisites, if you want that), and $# is the name of the target.

Could someone explain this make file?

I found this makefile on this site. They don't explain this example, so I was wondering if anybody new what was going on.
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
sets four variables to be constant strings. For the rest of the makefile, wherever $(CC) appears (for example), it will be replaced by g++
OBJECTS=$(SOURCES:.cpp=.o)
sets the variable OBJECTS to be the same as SOURCES, except wherever the pattern .cpp appears in a words of SOURCES, its replaced by .o
EXECUTABLE=hello
sets another constant string var
all: $(SOURCES) $(EXECUTABLE)
The first actual rule in the makefile, This tells make that to build all it must first build everything in $(SOURCES) and $(EXECUTABLE), and then do nothing. Since this is first, it becomes the default target, so running make is equivalent to make all
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
Another rule: to create $(EXECUTABLE) (which expands to hello) it must first build everything in $(OBJECTS) (equivalent to main.o hello.o factorial.o) and then run the command $(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) -o $# $<
A pattern rule: in order to build a file ending in .o, first rebuild/create/find the corresponding file ending in .cpp, and then run the command $(CC) $(CFLAGS) -o $# $<.
These last two rules contain the special variables $# and $< which are only valid in rule actions and expand to the target and first dependency respectively
So when you run make, it reads all this and then tries to build the default target (all).
Since it doesn't exist, it tries to build the files main.cpp, hello.cpp, factorial.cpp, and hello. Since the first 3 (presumably) exist, it looks for rules/dependencies for them, but doesn't find any, so decides there's nothing to do for them. If they didn't exist, make would give an error saying "no rule to make target 'main.cpp'"
In the case of "hello" it depends on main.o, hello.o and factorial.o, so it looks into them. For main.o, the pattern rule says it depends on main.cpp, so if main.o doesn't exist or if main.cpp is newer, it will run the command g++ -c -Wall -o main.o main.cpp. The same happens for hello.o and factorial.o.
Once those are done, if hello doesn't exist or is older than any of those .o files (which may have just changed, so are possibly pretty new), it will run that command to relink it. Finally, it will run the empty command (doing nothing) to 'rebuild' all.

What do the makefile symbols $# and $< mean?

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
What do the $# and $< do exactly?
$# is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.
For example, consider the following declaration:
all: library.cpp main.cpp
In this case:
$# evaluates to all
$< evaluates to library.cpp
$^ evaluates to library.cpp main.cpp
From Managing Projects with GNU Make, 3rd Edition, p. 16 (it's under GNU Free Documentation License):
Automatic variables are set by make after a rule is matched. They
provide access to elements from the target and prerequisite lists so
you don’t have to explicitly specify any filenames. They are very
useful for avoiding code duplication, but are critical when defining
more general pattern rules.
There are seven “core” automatic variables:
$#: The filename representing the target.
$%: The filename element of an archive member specification.
$<: The filename of the first prerequisite.
$?: The names of all prerequisites that are newer than the target,
separated by spaces.
$^: The filenames of all the prerequisites, separated by spaces. This
list has duplicate filenames removed since for most uses, such as
compiling, copying, etc., duplicates are not wanted.
$+: Similar to $^, this is the names of all the prerequisites separated
by spaces, except that $+ includes duplicates. This variable was
created for specific situations such as arguments to linkers where
duplicate values have meaning.
$*: The stem of the target filename. A stem is typically a filename
without its suffix. Its use outside of pattern rules is
discouraged.
In addition, each of the above variables has two variants for
compatibility with other makes. One variant returns only the directory
portion of the value. This is indicated by appending a “D” to the
symbol, $(#D), $(<D), etc. The other variant returns only the file
portion of the value. This is indicated by appending an “F” to the
symbol, $(#F), $(<F), etc. Note that these variant names are more than
one character long and so must be enclosed in parentheses. GNU make
provides a more readable alternative with the dir and notdir
functions.
The $# and $< are called automatic variables. The variable $# represents the name of the target and $< represents the first prerequisite required to create the output file.
For example:
hello.o: hello.c hello.h
gcc -c $< -o $#
Here, hello.o is the output file. This is what $# expands to. The first dependency is hello.c. That's what $< expands to.
The -c flag generates the .o file; see man gcc for a more detailed explanation. The -o specifies the output file to create.
For further details, you can read this article on linoxide about Linux Makefiles.
Also, you can check the GNU make manuals. It will make it easier to make Makefiles and to debug them.
If you run this command, it will output the makefile database:
make -p
The $# and $< are special macros.
Where:
$# is the file name of the target.
$< is the name of the first dependency.
The Makefile builds the hello executable if any one of main.cpp, hello.cpp, factorial.cpp changed. The smallest possible Makefile to achieve that specification could have been:
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
pro: very easy to read
con: maintenance nightmare, duplication of the C++ dependencies
con: efficiency problem, we recompile all C++ even if only one was changed
To improve on the above, we only compile those C++ files that were edited. Then, we just link the resultant object files together.
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
main.o: main.cpp
g++ -c main.cpp
hello.o: hello.cpp
g++ -c hello.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
pro: fixes efficiency issue
con: new maintenance nightmare, potential typo on object files rules
To improve on this, we can replace all object file rules with a single .cpp.o rule:
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
.cpp.o:
g++ -c $< -o $#
pro: back to having a short makefile, somewhat easy to read
Here the .cpp.o rule defines how to build anyfile.o from anyfile.cpp.
$< matches to first dependency, in this case, anyfile.cpp
$# matches the target, in this case, anyfile.o.
The other changes present in the Makefile are:
Making it easier to changes compilers from g++ to any C++ compiler.
Making it easier to change the compiler options.
Making it easier to change the linker options.
Making it easier to change the C++ source files and output.
Added a default rule 'all' which acts as a quick check to ensure all your source files are present before an attempt to build your application is made.
in exemple if you want to compile sources but have objects in an different directory :
You need to do :
gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...
but with most of macros the result will be all objects followed by all sources, like :
gcc -c -o <all OBJ path> <all SRC path>
so this will not compile anything ^^ and you will not be able to put your objects files in a different dir :(
the solution is to use these special macros
$# $<
this will generate a .o file (obj/file.o) for each .c file in SRC (src/file.c)
$(OBJ):$(SRC)
gcc -c -o $# $< $(HEADERS) $(FLAGS)
it means :
$# = $(OBJ)
$< = $(SRC)
but lines by lines INSTEAD of all lines of OBJ followed by all lines of SRC

Resources