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.
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 know that make usually executes the first target if called without any arguments. But what happens if the first target is a pattern rule? I have a Makefile here that looks as follows:
%.o: %.cc
gcc -c -o $# $<
main: main.o helper.o
gcc main.o helper.o -o $#
From my understanding of make, just calling it w/o any arguments should probably lead to some kind of error in this case because the first target, which is as far as I understood always the default target, does not make sense if make is not given any arguments. But when I call make with this Makefile, it instead builds the main target (and, of course, recursively the targets main.o and helper.o as well).
So, is it always true that make will ignore the pattern rules when looking for the first target? And is it somehow considered bad style to put those in front of the target that one really wants to be the default one? In my opinion, this is somehow confusing.
From the GNU make manual:
The order of rules is not significant, except for determining the
default goal: the target for make to consider, if you do not otherwise
specify one. The default goal is the target of the first rule in the
first makefile. If the first rule has multiple targets, only the first
target is taken as the default. There are two exceptions: a target
starting with a period is not a default unless it contains one or more
slashes, ‘/’, as well; and, a target that defines a pattern rule has
no effect on the default goal. (See Defining and Redefining Pattern
Rules.)
I have seen various makefiles where they use the .SUFFIXES rule. As per my understanding which means, taking a simple example
step1:
.SUFFIXES: .o .c .cpp .cc .cxx .C
#where $< indicates the source file and $# represents the target file.
.cpp.o:
$(CXX) -c $(INCPATH) -o "$#" "$<"
it will compile the target file to a .o file using the source with CXX compiler.
But after this i also see some other commands like
step2:
all: Makefile $(TARGET)
Step3:
someobjectfile.o: dependencies
So, if we can use .SUFFIXES rule to compile my target then why to use Step3.
i apologies if it is a silly question.
I'll start off by pointing out that suffix rules are obsolete in GNU make
Suffix rules are the old-fashioned way of defining implicit rules for make. Suffix rules are obsolete because pattern rules are more general and clearer. They are supported in GNU make for compatibility with old makefiles.
(Although for legacy reasons .SUFFIXES still controls which built-in rules will be available.)
That said, just because you've told make that .o files can be compiled from sources with certain suffixes does not mean that there aren't any other dependencies beyond the individual source file, the following is extremely common for example
someobjectfile.o: someheader.h someotherheader.h
.SUFFIXES controls suffix rules:
Suffix rules are the old-fashioned way of defining implicit rules for make. Suffix rules are obsolete because pattern rules are more general and clearer. They are supported in GNU make for compatibility with old makefiles.
In other words, you can ignore .SUFFIXES and write your pattern rule as:
%.o : %.cpp
someobjectfile.o: dependencies
The above adds dependencies of someobjectfile.o regardless of how .o are made.
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.
At the make manual said:
During the first phase it reads all the makefiles, included makefiles,
etc. and internalizes all the variables and their values, implicit and
explicit rules, and constructs a dependency graph of all the targets
and their prerequisites.
I don't understand how the dependency graph constructed? Consider the following makefile:
%.o: %.z
echo This is overriden implicit rule
default: foo.o
clean:
rm -f fmake test_second
%.o: %.c
echo This is customized implicit rule
After make command
echo This is customized implicit rule
This is customized implicit rule
is displayed, but I'm expexted that
echo This is overriden implicit rule
This is overriden implicit rule
will be, because in make rule only overrides if both the target and the prerequisite patterns match. In this case I think that %.o: %.z implicit rules matched to pattern already.
I've been doing a lot of work with Makefiles in a very, very large codebase for the last year or so. I am heartily sick of make(1s)!
The answer, in general, is "last declaration wins". You also have to contend
with the default make suffix rules (on Solaris these are found in /usr/share/lib/make/make.rules).
So if you want your overridden implicit rule to stand, place it last in the
Makefile hierarchy. If you want to flush the suffixes list, you can do either
or both of
1 add a .SUFFIXES:
line to your Makefile,
2 call make with -r
in MAKEFLAGS (env var) or on the make invocation command line.
[Also, you can prepend "#" to the start of your command to just see the output
of it, rather than the
echo [output goes here]
as well as the actual
[output goes here]
You could also gather insight by using one of the debugging options that
make(1s) allows. On Solaris, that's -d, -dd, -D or -DD. For GNU Make, it's
-d or --debug. Caution, though, dump the output from the command to a file,
because there is a lot of it.
You might want to read http://freecode.com/articles/what-is-wrong-with-make, as a piece of on-the-side illumination.