I am new to writing makefiles. Recently I have seen pattern rules in makefiles. For example:
%.o: %.cc
# command to compile comes here
After rigourous searching in the net, I found out what the above statement does,
But I came across another statement below.
%: %.o
# Command to link lies here
I do not understand this rule. Can anyone explain the second pattern rule?
The second rule is also a pattern rule, it says how to make a file with no extension from a file with the same name, but .o at the end. So it's a rule to link foo from foo.o, bar from bar.o and so on.
Related
I have these recipes in my Makefile. They generate cross-compiled objects for ARM architecture and link them into an elf binary:
%.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: %.ao startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
This works fine from a clean build.
Contrary to my expectation, if I then say touch foo.c; make foo.elf, gmake responds with
make: 'foo.elf' is up to date.
If I try to make foo.ao, gmake says that it, too , is up to date.
What am I missing?
Edit after reading the comments:
TLDR: I did have multiple rules matching the same target, as John Bollinger alluded and HardcoreHenry said specifically.
In addition to the rules above, there's a rule for assembly sources so I can use those vendor files:
%.ao: %.s
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
I had been debugging some macros, and used -save-temps to look at preprocessor output. This option also writes .s files. So after I'd run make foo.elf, I'd have the following in my directory:
foo.c
foo.i
foo.s
foo.ao
foo.elf
I can touch foo.c, but make sees that there's a foo.s which is older than foo.ao, and produces the output that it does. On a clean build, there is no foo.s, so make finds the %.c:%.ao rule and the build proceeds from foo.c.
(BTW, .ao stands for ARM object. In addition to cross-compiling for AMR, I compile many of the sources to run unit tests on the host, using the built-in .o:.c rule)
I'm not a fan of pattern rules.
Make can make very strange decisions on which rules apply depending on whatever is lying around on your hard disks.
It's all a bit arbitrary.
Much better IMHO to tell make exactly what files you need for a target.
It's pretty easy too.
Just prefix your pattern rule with the list of targets you actually want it to apply to.
This makes it a Static Pattern Rule.
objects := main.ao tools.ao devices.ao# etc
${objects}: %.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: ${objects} startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
As an added bonus, make now won't try to create the pre-existing startup_stm32f0xx.ao and system_stm32f0xx.ao.
Usually I find it nicer to list the source files, but YMMV:
sources := main.c tools.c devices.c
objects := $(patsubst $.c,%.ao,${sources})
(P.S. Using a Static Pattern Rule doesn't really give you any advantage over a normal rule in this noddy case. I just wanted to show a small tweak that would make your makefiles much more consistent in their behaviour.)
I know it's bad form to use an answer to respond to another answer, but I ran out of space in a comment to #bobbogo's answer.
Sorry but I can't agree with your assessment of pattern rules. It's not true that you will get "strange decisions" based on "whatever is lying around on your harddisks", and it's certainly not arbitrary.
There is one advantage of static pattern rules over pattern rules, and that is also its downside: a static pattern rule is a shorthand for creating an explicit rule, so that rule will always be used to build that target. A pattern rule, on the other hand, is just one possible way to build a target: if the prerequisites of a pattern rule don't exist and can't be made, then make keeps going and looks for other pattern rules that might be able to build that target.
So if you have multiple possible ways you can build a target then an explicit rule cannot be used for that.
The problem with pattern rules is that if NO pattern rule applies then make just assumes there is no rule to build that target. If the target exists then make simply says "up to date" (as we see in the question) since there's no rule to build it. That can be confusing to users.
If you use an explicit rule (including a static pattern rule) and some prerequisite doesn't exist and can't be created, then make will exit with an error, which can make it easier to figure out what went wrong.
I have a makefile that does something like this:
.INTERMEDIATE: gen0.tmp gen1.tmp
.PHONY: %_test
%_test: tests/%.so
ln -fs $< test.so
tests/%.so: gen.o test_src/%.c
cc -shared $^ -o $#
gen.c: gen0.tmp gen1.tmp
cat $^ > $#
gen%.tmp:
seds and awks and non-relevant stuff
As far as i have understood make's documentation, all files created from implicit rules are treated as intermediate, but that is not true for pattern rules, yet whatever .so i create with %_test rule is being deleted with other intermediate files, unless it existed before calling make. What is wrong here?
Also
.SECONDARY: tests/%.so
Doesn't work and
.SECONDARY:
does, but then targets explicitly marked as .INTERMEDIATE aren't beeing deleted, and i don't think marking my main target as .SECONDARY is good practice.
PS: i use make version 3.81
I don't understand your statement all files created from implicit rules are treated as intermediate, but that is not true for pattern rules.
A pattern rule IS a (type of) implicit rule. It absolutely is the case that targets which are created as a result of a pattern rule may be considered intermediate.
In a Makefile with
%.o: %.c
#echo Compiling $< ...
I'm getting the warning '%'-style pattern rules are a GNU make extension when I run autoreconf --install (of autoconf version 2.69). The warning is not very clear, but makes me think that there's something to be added to configure.ac.
I conducted searches on google.com, duckduckgo.com and yahoo.com, but they all don't seem to be able to differentiate between the large number of build logs they index (why should they...) which makes the search painful. I figured that:
I can silence the warning by adding AM_INIT_AUTOMAKE([-Wno-portability]) to configure.ac (found in a post of the openais mailing list) which seems not great because simply silencing a warning is generally not a good idea in a technical environment - please tell me if GNU autotools is an exception.
Replace
%.o: %.c
with
.c.o:
That's a suffix rule doing the same thing, and it's more portable. If your rule involves a suffix that is not known to make, list it in the prerequisites for the special .SUFFIXES target:
.SUFFIXES: .hack .win
.hack.win:
# build a .win file from a .hack file.
More on how this works in detail here. They recommend to use pattern rules instead of suffix rules because they're clearer and more general, which is true, but as autoconf notes, they are indeed less portable. So if that is a worry (if you want to build on BSD/Mac OS and not install GNU make, basically), fall back on the "old-fashioned suffix rules."
If you have a pattern rule that cannot be replaced by a suffix rule, another possible replacement that automake doesn't complain about is a static pattern rule. This is similar to a pattern rule but requires a list of targets it applies to. Instead of saying
%.o: %.c
You would have to say
OBJS = foo.o bar.o baz.o # list all .o files here
$(OBJS): %.o: %.c
Or more generally,
target-pattern: prerequisite-pattern
is replaced by
target-list: target-pattern: prerequisite-pattern
Winteermute covered almost all aspects of the issue. I will add one of my own frustrations here. In my make file, I have been using a pattern rule to install shell scripts without their .sh suffix. Automake does not like pattern rules and give you warning. You can simply ignore the warning for now. My configure.ac file:
AM_INIT_AUTOMAKE([-Wall -Wportability])
In my Makefile.am
dist_bin_SCRIPTS = foobar
# pattern rule
% : %.sh
cp $< $#
chmod +x $#
In my script directory I have the foobar.sh file.
I have not been able to figure out a better way to specify a suffix rule to cover the case where the target does not have an extension although I really tried hard to search on the internet and read the manuals backward a few times.
The reason I am distributing the *.sh file is that the user does not have to know the implementation details. They just need to remember the name of the executable. Furthermore, asking the user to type the extra .sh is really a waste of life.
I am trying to wrap my head around pattern rules and how they function. I am using this article for reference which states
A pattern rule is a concise way of specifying a rule for many files at
once. The rule will depend on the file names, but usually it depends
on them in a simple way. You specify a pattern by using the %
wildcard. When present in the dependency list, % matches any string of
any length; when present in the list of targets, % stands for the
string that % in the dependency list matched.
The following pattern rule will take any .c file and compile it into a
.o file:
%.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)
(This assumes that you have the variables CC, CFLAGS, and INCLUDES
defined to be something suitable. Makepp will guess a value for CC and
CFLAGS.)
The first line of the rule says that it applies to every possible
input file that matches the pattern %.c. These .c files can be
transformed into the corresponding .o file using the specified
actions.
The action of rule is quite similar to the other actions we've seen
previously, except that it uses automatic variables. An automatic
variable is a variable whose value is automatically set by makepp
depending on the rule that it appears in. Some useful automatic
variables are:
$(input)
The name of the first input file. In this rule, this would be the file that matches the %.c pattern. $(dependency) is a synonymn for $(input). In older makefiles, you will also see the cryptic symbol $< used as well.
$(output)
The name of the first output file. In this rule, this would be the file that matches the %.o pattern. $(target) and $# are synonymns.
$(inputs)
The name of all explicitly listed input files. In this case, since there is only one, $(inputs) is equivalent to $(input). $(dependencies) and $^ are synonymns.
$(outputs)
The name of all explicitly listed targets. In this case, since there is only one, $(outputs) is equivalent to $(output). $(targets) is a synonymn for $(outputs).
Here are the questions that I have:
1 ) Suppose I have 2 files FileA.c and FileB.c. When I apply the above mentioned pattern rule how would that apply to the above two files. The example given only deals with one file.
2) Whats the difference between the automatic variable input and inputs
A pattern rule will be applied to each target file that matches the rule that make needs to build.
So if you need to build both FileA.o and FileB.o (because they are both listed as prerequisites of some other target (e.g. FileBin: FileA.o FileB.o) that rule will be run twice, once for each.
Take the rule
FileBin: FileA.o FileB.o
#echo '$$input = $(input)'
#echo '$$inputs = $(inputs)'
When run that would output
$input = FileA.o
$inputs = FileA.o FileB.o
It should also be pointed out that input and output are makepp variable names and not valid for GNU make itself.
I recently browsed through a makefile with these lines of code in a OS design course at CMU.
$(TEST_PROGS) tests/verify_test: %: %.o libtraceback.a
$(CC) -o $# $#.o -L. libtraceback.a $(CFLAGS) $(LDFLAGS) $(LIBS) -static
python ./symtabgen.py $#
I don't understand what "%:" could mean here. The TEST_PROGS variable contains list
traceback/traceback_globals.o traceback/traceback.o
traceback/traceback_globals.o traceback/traceback.o are required in making libtraceback.a
I've went so far as to play around with removing %.o. Doing so stopped the TEST_PROGS objects from compiling
Removing %: but keeping %.o gave out several warnings and nothing compiled.
I'm hoping someone could shed some light into the syntax of makefile here. A quick Google search revealed that %: is related to secondary expansion. But in this code that I'm looking at,the special target .SECONDEXPANSION isn't defined.
Please help, this code makes my brains hurt ...
The canoncial place to look is the Make manual.
Anyway, this an example of a static pattern rule. It uses wildcards to specify a relationship between each target and a similarly-named prerequisite.
This is a static pattern.
This is what it means:
Your target is any of the files described by $(TEST_PROGS) or test/verify_test
What you need to build your target is the second part: %.o libtraceback.a
The string that will replace the % symbol is exactly the name of the file that you are trying to build.
So, for example, executing
make test/verify_test
will set % to be "test/verify_test" and it will require test/verify_test.o and libtraceback.a