Not able to understand the use of .suffixes rule in makefile ubuntu - makefile

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.

Related

Missing dependency in Makefile

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.

make: Reference stem of target in prerequisite without patterns

I have a project with many .c and .s files. Writing out individual rules for each is a hassle, what I had before for my .c files was this.
$(OBJ_DIR)/%.o : %.c %.h
*recipe*
While this works fine for projects with just c source files, it will not work with a project with assembly files.
I've read through the documentation for make on gnu.org and have not been able to figure out a way to reference the stem of the target name or even the whole target name in the prerequisites without using patterns. I would like to do something along these lines.
$(C_OBJ_FILES) : %.c %.h # Where % WOULD be the stem of the target name
$(AS_OBJ_FILES) : %.s # Where % WOULD be......
I currently have separate directories for objects compiled from assembly sources and objects compiled with c sources. While this works, I'd like to have them in the same directory. I also considered creating a hidden symlink that points to the objects directory that I could use to differentiate assembly and c source files, but again, that doesn't solve my question.
Edit: I am not looking for a work around that avoids referencing the target name, since being able to reference it in the prerequisites would help several other parts of my Makefiles. If this is definitely not possible, then say so and that'll answer my question.
What you are looking for is probably static pattern rules:
C_OBJ_FILES = $(patsubst %.c,$(OBJ_DIR)/%.o,$(wildcard *.c))
AS_OBJ_FILES = $(patsubst %.s,$(OBJ_DIR)/%.o,$(wildcard *.s))
# static pattern rule for C files
$(C_OBJ_FILES) : $(OBJ_DIR)/%.o : %.c %.h
<recipe>
# static pattern rule for assembly files
$(AS_OBJ_FILES) : $(OBJ_DIR)/%.o : %.s
<recipe>
In your recipes you can use $#, $< and $*; they will respectively expand as the target (the object file), the first prerequisite (the C or assembly source file) and the stem (the base name of the C or assembly source file). Example:
# static pattern rule for C files
$(C_OBJ_FILES) : $(OBJ_DIR)/%.o : %.c %.h
#echo '[CC] $*' && \
$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $#
The standard approach is:
all: x.o y.o z.o
%.o: %.s
*recipe*
%.o: %.c
*recipe*
And then makedepend can fill in transitive deps, such as C headers. It's not "a hassle" to "write out individual rules", you just let the program do it, automatically.
Your remark about "avoiding referencing the target name" ($#) is just bizarre, in a make context. You make it sound like you'd rather not express the DAG in a Makefile at all, that you'd rather write a tediously repetitive Bourne script that describes your build process. I encourage you to embrace make patterns, they're a natural way to express the problem, and will help you describe your requirements in just a few lines of code.

make - pattern rule target wrongly treated as intermediate

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.

How to deal with autoconf warning "'%'-style pattern rules are a GNU make extension"

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.

What is the Makefile Target `.c.o` for?

Someone recently mentioned the target .c.o in Makefiles for cross compatability, but I fail to understand its purpose. Can anyone clarify?
It's an old-fashioned suffix rule. The more up-to-date way to do it is to use a pattern rule:
%.o : %.c
It's a canned rule for translating .c files, i.e. C modules, to .o object files. It exists so you don't have to write this rule yourself and is parameterized by Make variables such as CC (the C compiler to use), CFLAGS (compiler flags), etc.
So, if you use this implicit rule to compile C modules and don't tinker with any Make variables, then the person building your code can specify a compiler and flags on the command line without editing the Makefile.

Resources