patsubst's returned value when no pattern found - makefile

I'm trying to send "sub-make" commands to a subdirectory. I have a Parent Directory with a "top_level" Makefile and a child directory with its own Makefile.
My parent Makefile has a target line as follow :
target%:
make -C sub_dir $(patsubst target-%,%,$#)
I can do in the parent folder:
make target-clean && make target-all
It will be interpreted as :
make -C sub_dir clean && make -C sub_dir all
I want to be able to do:
make target
but in this case, I get :
make -C sub_dir target.o
I was expecting that while "patsubst" does not find the pattern, it will return either nothing or the tested expression. But it returns this "target.o".
Can someone explain it to me ? How can I manage to get nothing ?
I tried these expressions without success:
make -C sub_dir $(patsubst target%,%,$#)
make -C sub_dir $(patsubst -%,%,$(patsubst target%,%,$#))
make -C sub_dir $($(patsubst -%,%,$(patsubst target%,%,$#)):.o=)
The last one is tricky, it gives:
make -C sub_dir
make[1]: Entering directory /home/aurelien/Documents/Projects/parent/sub_dir'
make[1]: 'subtarget' is up to date.
make[1]: Leaving directory '/home/aurelien/Documents/Projects/parent/sub_dir'
cc target.o -o target
cc: target.o: No such file or directory
cc: no input files
make: *** [target] Error 1

The target% pattern matches but only with at least one character for the %, not zero. From the GNU make manual:
A pattern rule contains the character ‘%’ (exactly one of them) in the
target; otherwise, it looks exactly like an ordinary rule. The target
is a pattern for matching file names; the ‘%’ matches any nonempty
substring, while other characters match only themselves.
So target does not match and make uses its implicit rules to build target: build target.o and then target from target.o. When trying to find a way to build target.o, the pattern rule matches and the recipe:
make -C sub_dir $(patsubst target-%,%,$#)
is expanded. But as target.o does not match target-%, patsubst does nothing and your recipe becomes:
make -C sub_dir target.o

The problem is that a pattern must match one or more characters. So, this pattern:
target%:
does not match the target name target, because there are no characters left over to match the pattern.
So, make looks for another implicit rule that can be used to build target and it finds the built-in rule:
% : %.o
so it tries to build target.o. This target will match the pattern target% with a stem of .o, so it tries to use your rule to build that.
To specifically answer your question, any word that does not match the substitution pattern in patsubst will be passed through without changing it.

Related

why my makefile works with asterisk as wildcard, but do not with percentage?

In my makefile:
default: *.s
echo $(basename $<)
Does echo the basename, but
default: %.s
echo $(basename $<)
outputs:
make: *** No rule to make target '%.s', needed by 'default'. Stop.
I have smf.s file in directory, where the makefile is. So why do not makefile use it as Prerequisite? (only shell-like * does, but % does not), why?
Your first rule:
default: *.s
echo $(basename $<)
works as you expect because * is a wildcard character in GNU Make.
On the other hand, your second rule:
default: %.s
echo $(basename $<)
has %.s as a prerequisite. Since there is no file named %.s Make needs an additional rule to generate this missing file %.s. That is what the error message is about:
make: *** No rule to make target '%.s', needed by 'default'. Stop.
You may think that % is a wildcard character. Actually, it behaves as such in pattern rules. However, your second rule isn't a pattern rule. The following is an excerpt from the documentation:
A pattern rule looks like an ordinary rule, except that its target contains the character ‘%’ (exactly one of them).
Your second rule's target – i.e., default – does not contain the character %. Therefore, it can't be qualified as a pattern rule, so the % in the prerequisite, %.s, is literally the % character.

Percent symbol not getting evaluated in makefile

I'm new to makefiles etc.
The file looks like this:
COMPILER_NAME = gcc
COMPILER_FLAGS =
PATH_OBJECTS = ./obj
PATH_SOURCES = ./src
$(PATH_OBJECTS)/%.o: $(PATH_SOURCES)/%.c
$(info Generating object files...)
#$(COMPILER_NAME) $(COMPILER_FLAGS) -c $< -o $#
cleanup: $(PATH_OBJECTS)/%.o
$(info Final cleanup...)
#rm -rf $<
When i try to actually make the project i get this error:
make: *** No rule to make target 'obj/%.o', needed by 'cleanup'. Stop.
It's like the % wildcard is not getting evaluated correctly. Please help me.
A pattern rule has '%' in the target, and maybe in one or more of the prerequisites. What you have:
cleanup: $(PATH_OBJECTS)/%.o
...
is not a pattern rule, and that '%' is not a wildcard, it's just a character. That's an ordinary rule that looks for a file called "./obj/%" as a prerequisite, and there's no such file.
If you want cleanup to remove all of the object files in that directory, there's no need for any of this complication. Just do this:
cleanup:
#echo Final cleanup...
#rm -rf $(PATH_OBJECTS)/*.o
Note that this uses the shell command echo, not the Make command info, and the shell wildcard '*', not the Make wildcard '%'.
If you want a target to depend on all the object files you can build, you must construct that list yourself; it's not difficult, but it doesn't look like something you need here.

How to set a Makefile target depend on pattern prerequisites?

I have a chain of pattern dependencies in a makefile, and in the end they should come together in one file, e.g.: *.x -> *.y -> onefile.z
So I made the files like this:
$ touch a.x b.x
and the rules:
%.y: %.x some-other-script
touch $#
onefile.z: %.y second-other-script
touch $#
This rule does not work:
$ make onefile.z
make: *** No rule to make target '%.y', needed by 'onefile.z'. Stop.
Using a wildcard:
%.y: %.x some-other-script
touch $#
z: $(wildcard *.y) second-other-script
touch $#
This does not work either: it sees there are no *.y files and proceeds making onefile.z skipping the first rule.
$ make onefile.z
touch onefile.z
$ ls
a.x b.x onefile.z Makefile
I probably could merge two rules into one, but in the real application, there are more steps, and some are making requests over HTTP and take much time, and in fact should not be repeated without a reason.
Is there a way to make such a dependency?
onefile.z: %.y second-other-script is a regular rule, not a pattern rule or a static pattern rule, so the % is interpreted literally. Even if it were a pattern rule, how is make supposed to infer what the stem is supposed to match?
$(wildcard *.y) tells make to find all the files that match *.y, but of course there are none yet so it returns an empty string.
The following should work, if I've understood your question correctly:
xfiles := $(wildcard *.x)
yfiles := $(xfiles:.x=.y)
%.y: %.x some-other-script
touch $#
onefile.z: $(yfiles) second-other-script
touch $#
See the Gnu Make documentation on
Wildcard functions $(wildcard ...)
Substitution functions $(foo:from=to)

How can I use a pattern rule to add prerequisites like I can to define variables?

I have the following Makefile:
all: foo/bar/baz
foo/%:
#echo $(VAR)
cp $#.in $#
# This works
foo/bar/%: VAR := Hello world
# This doesn't
foo/bar/%: foo/bar/%.in
foo/bar/baz.in:
touch $#
When I run it, the output is
Hello world
cp foo/bar/baz.in foo/bar/baz
cp: cannot stat ‘foo/bar/baz.in’: No such file or directory
Makefile:4: recipe for target 'foo/bar/baz' failed
make: *** [foo/bar/baz] Error 1
In other words, the pattern-specific variable rule works, but the equivalent syntax to declare an extra prerequisite doesn't. What should I do instead?
The real use case is for copying headers before a build. I wrote
obj/subdir/%.o: CPPFLAGS += -Igen/include
obj/subdir/%.o: | gen/include
gen/include:
# Copy the headers
but the headers don't get copied.
You cannot do this. Pattern rules must define all prerequisite patterns when the rule is created; they cannot be added later.
Writing a pattern rule with no recipe deletes the pattern rule.

GNU make not recognizing %

I'm trying to make a makefile for compiling various examples that are within a subfolder. The makefile consisting of just:
S_1_2.exe : Twister.cpp Parsing.cpp ./Surfaces/S_1_2.cpp
g++ -o $#.exe $^ -I . -W -Wall
Works fine when run with the command "make S_1_2.exe". However:
%S_1_2.exe : Twister.cpp Parsing.cpp ./Surfaces/S_1_2.cpp
g++ -o $#.exe $^ -I . -W -Wall
fails, even when run with the command make S_1_2.exe, with the error "make: * No rule to make target 'S_1_2.exe'. Stop."
Shouldn't %S_1_2.exe do pattern matching and so match S_1_2.exe? In which case why is it not matching this rule?
I am using GNU Make 3.81
The percentage symbol matches a non-empty string. So you should use %_1_2.exe or better yet - %.exe. I don't know if there is any other symbol that matches empty strings too.
The % is for matching a part of the target against the same part in one or more dependencies.
You can't omit it from all dependencies.

Resources