% in built-in file name function of GNU make - makefile

I encountered some code in a makefile like following. Could anyone teach me what does % in following code means.
$(addsuffix .o, % $(objects))
I searched GNU Make reference and found
$(addsuffix pattern, names...)
But what does a % mark in this function means.
$(addsuffix .o, % $(objects))
Thanks for your help.

Why not just try it and see what it does? In the argument to the addsuffix function, % means %. It's not special in any way, it's just the literal percent character. So the output of this:
objects = foo bar biz baz
$(info $(addsuffix .o, % $(objects))
will be:
%.o foo.o bar.o biz.o baz.o

Related

How to remove extension in makefile

I have the following makefile:
CC=gcc
CFLAGS=-c ---
LDFLAGS = ---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
TESTFILE := $(patsubst %_test.c,%,$(SRCFILES))
all: $(TESTFILE)
$(TESTFILE): $(OBJFILES)
$(CC) $(LDFLAGS) $(OBJFILES) -o $#
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
For all:$(OBJFILES) and below, works perfectly fine. it creates all the object files I need however, I am having trouble creating the file test file. One of the SRC files is ABC_test.c, and the file I want to output is ABC_test (with no extension).
The ABC_test will have dependencies of all the OBJfiles. I think the way I have it set-up is correct but if it is not, please let me know. I am very new to makefiles.
I tried using substitution as you can see in the TESTFILE name. I believe my question is too specific and could not find help with a google search. Any idea what I can do?
It's important to understand that patsubst doesn't omit words from the result. If the word matches the pattern then it is substituted. If the word doesn't match the pattern then it's just emitted as-is.
So, if you have:
FOO = foo_1 foo_2 bar_1 bar_2
$(info $(patsubst foo%,FOO%,$(FOO))
then the output will be:
FOO_1 FOO_2 bar_1 bar_2
It will NOT be, as you seem to be expecting:
FOO_1 FOO_2
with the non-matching values left out. If you want to remove words from the output you need to use the filter and filter-out functions. So for example:
TESTFILE = $(patsubst %_file.c,%,$(filter %_test.c,$(SRCFILES)))

Pass argument of call to another function in Makefile

I would like a way to take the argument to a call invocation in a Makefile rule and pass that to a builtin function, in this case wildcard.
This doesn't seem to work:
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
lib%.a: $(call MODULE_OBJS, %)
#echo $# : $^
In this case I would expect make libfoo.a to print a list of .o files corresponding to the .cc files found under foo/, but nothing is printed. The parameter is getting there because if I append $(1) to the end of MODULE_OBJS the value of % gets printed, but it seems to be lost when getting passed into wildcard.
You need to understand that make will execute $(call MODULE_OBJS, %) before it has even begun building the dependency tree, you cannot accomplish this with a pattern rule. You could use eval hackery but there's a case to made against trying to be too clever with make.
Something like the following is easy enough to maintain
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
libfoo.a: $(call MODULE_OBJS, foo)
lib%.a:
#echo $#: $^
but after wrestling with clever ways of generating library and binary dependencies I prefer simply listing them explicitly.
I got what I wanted with some hacking of the eval rule:
EXCLUDE_MODULES = obj
MODULES = $(filter-out $(EXCLUDE_MODULES), $(patsubst %/, %, $(wildcard */)))
define MODULE_RULE
lib$(MODULE).a: $(patsubst %.cc, obj/%.o, $(wildcard $(MODULE)/*.cc))
#echo $# : $^
endef
$(foreach MODULE, $(MODULES), $(eval $(MODULE_RULE)))
This allows you to call make libfoo.a and get out a list of all the .o's corresponding with the .cc's in that subdirectory.
For those curious, I uploaded a complete example here.
The Metaprogramming Make articles were a useful resource here.

Why does patsubst stop working when using secondary expansion of $$*?

Here is an example from the GNU Make manual section on Secondary Expansion (slightly simplified):
foo_SRCS := bar.c baz.c
.SECONDEXPANSION:
# $$# expands to the target ("foo" in this case)
foo: $$(patsubst %.c,%.o,$$($$#_SRCS))
This works great; it builds bar.o and baz.o:
cc -c -o bar.o bar.c
cc -c -o baz.o baz.c
But if I tweak this example only slightly, the patsubst stops working:
all: foo.a
foo_SRCS := bar.c baz.c
.SECONDEXPANSION:
# $$* expands to the stem of the match ("foo" in this case).
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
ar rcs $# $^
It is no longer building bar.o and baz.o, and instead is using the *.c files directly as prerequisites!
ar rcs foo.a bar.c baz.c
Please note that the $$($$*_SRCS) part is clearly working, as evidenced by the fact that it found foo_SRCS and used that as the prerequisites. But for some reason the patsubst part has become a no-op! Instead of replacing %.c with %.o, it is just using foo_SRCS directly.
What is going on here? How can I get my example to work?
EDIT: I had a theory that the % characters inside the patsubst were getting evaluated early, using the stem match (foo), so that the patsubst itself was looking something like this:
$(patsubst foo.c,foo.o,bar.c baz.c)
To test this theory, I added a file called foo.c to foo_SRCS:
all: foo.a
foo_SRCS := foo.c bar.c baz.c
.SECONDEXPANSION:
# $$* expands to the stem of the match ("foo" in this case).
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
ar rcs $# $^
That resulted in something even weirder:
make: *** No rule to make target `foo.a', needed by `all'. Stop.
The percent characters are being read by make as matches to the wildcard in the stem and are being replaced with the stem match. If you check the make -p output for your example you'll see that the parsed target line looks like this:
%.a: $(patsubst %.c,%.o,$($*_SRCS))
Which, as far as make is concerned, is just a really odd set of patterned targets (or something like that).
If you escape the percent characters from make parsing in a similar way to how you escape the $ from make evaluation you can get what you want to work:
pc := %
$$(patsubst $$(pc).c,$$(pc).o,$$($$*_SRCS))
For added information substitution references (i.e. $(foo_SRCS:.c=.o)) can be used for transformations like this in place of the longer call to patsubst. In this case however, while it works in this scenario with a similar escaping of : (via c := :) it doesn't seem to function as the sole prerequisite of the target (with make giving a Makefile:23: *** commands commence before first target. Stop. error that I don't quite understand) at least with GNU Make 3.81.
You're mixing three features that don't go well together: secondary expansion, pattern rules, and patsubst. I'll try to explain in detail what make is doing when evaluating your code (AFAIUI).
Let's start with your first Makefile:
foo_SRCS := bar.c baz.c
.SECONDEXPANSION:
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
ar rcs $# $^
Read phase. All dollar signs are escaped, so no evaluation happens here. Make enters the following rule in its database:
%.a: $(patsubst %.c,%.o,$($*_SRCS))
Pattern substitution. As far as make is concerned, this is just another pattern rule, with target %.a and two prerequisites separated by whitespace: $(patsubst and %.c,%.o,$($*_SRCS)).
foo.a matches the target pattern, and so the first % in each prerequisite will be replaced by foo. The rule becomes:
foo.a: $(patsubst foo.c,%.o,$($*_SRCS))
Target update phase. As you requested secondary expansion, the pattern is evaluated again in the target update phase:
foo.a: $(patsubst foo.c,%.o,$($*_SRCS))
==> foo.a: $(patsubst foo.c,%.o,bar.c baz.c)
==> foo.a: bar.c baz.c
And so make ends up executing the command
ar rcs foo.a bar.c baz.c
And what about foo.c? If you add foo.c to foo_SRCS, the secondary expansion looks like this:
foo.a: $(patsubst foo.c,%.o,$($*_SRCS))
==> foo.a: $(patsubst foo.c,%.o,foo.c bar.c baz.c)
==> foo.a: %.o bar.c baz.c
And the rule fails because make doesn't know how to build %.o.
Work-around. You can escape the % characters with a backslash:
.SECONDEXPANSION:
%.a: $(patsubst \%.c,\%.o,$$($$*_SRCS))
ar rcs $# $^

Problems with substitution

I'm having trouble getting path substitution working correctly. I have a bunch of source files in SOURCES:
#echo $(SOURCES)
foo.c bar.cpp bah.cxx
And I want a list of object files:
# Imaginary only because nothing works
#echo $(OBJECTS)
foo.o bar.o bah.o
I'm trying to build the list of OBJECTS with patsubst. First, this produces a list of source files and object files. Besides being wrong, it causes a duplicate of _main which fails a link.
OBJECTS = $(patsubst %.c, %.o, ${SOURCES}) $(patsubst %.cc, %.o, ${SOURCES}) \
$(patsubst %.cpp, %.o, ${SOURCES}) $(patsubst %.cxx, %.o, ${SOURCES})
Second, this performs no substitutions. Not only is it wrong, I get back the original list in SOURCES.
OBJECTS = $(patsubst %.c %.cc %.cpp %.cxx, %.o, ${SOURCES})
Third, this produces the original list of source files:
OBJECTS = $(patsubst %.*, %.o, ${SOURCES})
I also tried using the following, which seems to multiply the files like rabbits:
OBJECTS = $(SOURCES:.c=.o) $(SOURCES:.cc=.o) \
$(SOURCES:.cpp=.o) $(SOURCES:.cxx=.o)
How does one perform a simple substitution of extensions when using a portable make?
Tom's answer is correct. Etan's will work too. A shorter solution would be:
$(addsuffix .o,$(basename $(SOURCES))
If you have a filter-like function you can use that. Otherwise you can do it in stages:
SOURCES := foo.c bar.cpp bah.cxx
O := $(SOURCES)
$(info $(O))
O := $(patsubst %.c,%.o,$(O))
$(info $(O))
O := $(patsubst %.cpp,%.o,$(O))
$(info $(O))
O := $(patsubst %.cxx,%.o,$(O))
$(info $(O))
The problem with your first (and third since that is effectively identical) attempt is that patsubst leaves untouched any words in the input that do not match the pattern. So when you built OBJECTS up from multiple calls to patsubst you were duplicating (in each piece) all the SOURCSE entries that didn't match that pattern.
The problem with the second is that patsubst doesn't take multiple patterns so nothing matches that erroneous pattern and so you get SOURCES back entirely unmodified.
First, I don't think patsubst is portable. It is a GNU make feature.
I think one answer to your question is nested subsitutions, like:
$(patsubst %c,%.o,$(patsubst %.cc,%.o,$(patsubst .....)))

Why do makefiles sometimes have 'true <filename>' as part of the build script?

For example:
# Some stuff
all: some dependencies
#$(CC) -o foo.o foo.c
#true foo.o
#some other operation
What purpose does the 'true foo.o' line serve?
Typically this is output from a Makefile generator such as automake. The true will be replaced with an actual command on platforms which require it. The most common case is platforms which don't maintain static archive indexes automatically; the code will look something like
foo.a: foo.o bar.o baz.o ...
ar rv foo.a foo.o bar.o baz.o ...
true foo.a
but on some platforms (those without either System V or GNU ar) it will instead be
foo.a: foo.o bar.o baz.o ...
ar rv foo.a foo.o bar.o baz.o ...
ranlib foo.a
The reason it's not simply removed is that it's a lot easier in m4 and other macro processors to substitute text on a line than it is to conditionally delete the line. (It can be done, but advanced m4 hackery has been known to cause insanity. :)

Resources