how to append suffix after makefile's automatic variable? - makefile

OBJS := a.o b.o c.o
rule : $(OBJS)
#echo $^
#echo $^.bc // #echo a.o.bc b.o.bc c.o.bc -> what I want to do
I want to add suffix after automatic variable $^
However, even though I use $^.bc, it shows
a.o b.o c.o.bc
not,
a.o.bc b.o.bc c.o.bc
Are there any ways to do this?

Problem
The automatic variable $^ is in your case a space-separated list of elements since it expands to a.o b.o c.o.
Therefore, echo $^.bc will result in a.o b.o c.o.bc instead of a.o.bc b.o.bc c.o.bc, because the suffix .bc is only appended to the last element of the list, i.e., c.o.
If you want to obtain a.o.bc b.o.bc c.o.bc, then what you want is to add the suffix .bc to every single element of that space-separated list, not just the last one.
Solution
GNU Make's addsuffix builtin function does work on lists:
OBJS := a.o b.o c.o
rule: $(OBJS)
#echo $^
#echo $(addsuffix .bc,$^)
Running make on the makefile above:
$ make
a.o b.o c.o
a.o.bc b.o.bc c.o.bc
produces the output you are looking for.

Related

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:
LIST1 := hello.o world.o
LIST2 := hello.c world.c
# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
cc -c $^ -o $#
# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
cc -c $^ -o $#
Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?
I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.
You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as #MadScientist suggests, that would be best. If not (say the names differ, you can do something like):
LIST1 := hello.o bob.o
hello.o : hello.c
bob.o : sally.c
$(LIST1):
cc -c $< -o $#
Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:
LIST1 := hello.o bob.o
LIST2 := hello.c sally.c
all:
define recursive_def
$(firstword $(1)) : $(firstword $(2))
cc -c $$^ -o $$#
$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef
$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)
$(eval $(call recursive_def,$(LIST1),$(LIST2)))
The short answer is "no". Why don't you just write a pattern rule?
all: $(LIST1)
%.o : %.c
cc -c $^ -o $#
? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.
ETA
If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(SRCS))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<
If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<

Given a target's name, get all of its prerequisites

If I have a makefile with e.g.:
foo.o: foo.c a.h b.h c.h
cc -c foo.c -o foo.o
Now, in some other part of the makefile, I want to get all the prerequsites of foo.o, like I'd do with $^ in the recipe. Something like:
$(info $(call GET_TARGET_PREREQS(foo.o))) # prints "foo.c a.h b.h c.h"
Basically, I have dependency files (generated by -M) for all my object files, and from there I want a list of all the header files that are included by a given object.
I'm hoping for a more or less pure make solution, and not a sed script that parses the *.d files and outputs makefile fragments.
If you want to print all prerequsites, you can always use $^
.PONY: all
all: a b c
#echo $^
a:
b:
c:

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 $# $^

what is mean by "make skips the implicit rule search for phony targets "

I am new to Makefiles and was reading some docs on PHONY targerts. Can some one please explain what is mean by "make skips the implicit rule search for phony targets". If we are declaring a PHONY target as default target, is there any restriction?
It means that if a target is marked as .PHONY, then it must be an explicit rule, i.e. something like
a.o: a.c
$(CC) -o $# -c $<
and not an implicit rule, like a pattern rule or a suffix rule. As an example, consider the following makefile:
.PHONY: a.o
all: a.o b.o
%.o: %.c
$(CC) -o $# -c $<
Invoking make will do the following:
$ make
cc -o b.o -c b.c
$
Note that only b.c was compiled, not a.c.

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.

Resources