How to use GNU make's implicit rules to make `foo` from `foo.s`? - makefile

Here's my makefile:
AS=nasm
ASFLAGS=-f elf64
%: %.o
${LD} -o $# $<
Suppose I have a source file foo.s, I can run make foo.o then make foo to make the executable foo.
$ make foo.o
nasm -f elf64 -o foo.o foo.s
$ make foo
ld -o foo foo.o
But if I run make foo directly, cc is used instead.
$ rm foo foo.o
$ make foo
cc -f elf64 foo.s -o foo
cc: error: elf64: No such file or directory
cc: error: unrecognized command line option ‘-f’
make: *** [<builtin>: foo] Error 1
This is explained in the documentation, at the end of the section "Linking a single object file".
How should I write my makefile so that I can run make foo to make foo.o from foo.s and then foo from foo.o automatically?

You can clear the default implicit rule with:
%: %.s
See Canceling Implicit Rules in the make manual.

You could replace:
%: %.o
${LD} -o $# $<
by:
ASEXES := $(patsubst %.s,%,$(wildcard *.s))
$(ASEXES): %: %.o
${LD} -o $# $<
This is a a Static Pattern Rule. For each word in $(ASEXES), it instantiates an explicit rule, not a pattern rule. So, it is treated exactly as if you had explicitly written:
foo: foo.o
${LD} -o $# $<
for each foo in $(ASEXES), while pattern rules like:
%: %.o
${LD} -o $# $<
are treated differently (see the section entitled Static Pattern Rules versus Implicit Rules of the GNU make manual).

Related

BSD make & GNU make

I have Makefile. This runs on FreeBSD with gmake and make. In BSD Make command not output log same with gmake.
$ gmake
compile main.cpp
linking myout
$ make
c++ -O2 -pipe -c main.cpp -o main.o
linking myout
$ cat Makefile
TARGET = myout
default: $(TARGET)
SRCS = main.cpp
OBJS = $(SRCS:%.cpp=%.o)
default: $(BIN)
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
$(TARGET): $(OBJS)
#echo linking $#
#$(CXX) $(OBJS) -o $#
clean:
#rm -f $(OBJS) $(TARGET)
According to the FreeBSD make documentation, it doesn't support pattern rules. So your rule here:
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
in FreeBSD make is just an explicit rule telling make how to build the literal file %.o from the literal file %.cpp. Since you don't try to build a file named %.o (you're trying to build main.o), this rule is ignored / never used.
It looks like if you want something that will work the same way between both versions of make you'll have to restrict yourself to the POSIX standard suffix rules format, like this:
.SUFFIXES: .cpp .o
.cpp.o:
#echo compile $<
#$(CXX) -c $< -o $#
The default build utilities are different. FreeBSD uses a different implementation of make than GNU/Linux. The respective man pages outline differences.
https://forums.freebsd.org/threads/difference-gmake-gnu-and-freebsd-make.28784/

makefile: No rule to make target '%.o'

I have 3 files: Source.cpp 2ndfile.cpp 2ndfile.hpp
And I'm trying to compile them with mingw32-make
makefile that doesn't work:
all: launch.exe
launch.exe: %.o
g++ -o $# $^
%.o: %.cpp
g++ -c $< -std=gnu++11
makefile that works:
all: launch.exe
launch.exe: source.o 2ndfile.o
g++ -o $# $^
source.o: source.cpp
g++ -c source.cpp -std=gnu++11
2ndfile.o: 2ndfile.cpp
g++ -c 2ndfile.cpp -std=gnu++11
My question is: why the first one doesn't work? What's my problem with '%' patterns?
The error I get: mingw32-make: *** No rule to make target '%.o', needed by 'launch.exe'. Stop.
My question is: why the first one doesn't work? What's my problem with '%' patterns?
A pattern rule matches targets to prerequisites via a common element in their names, represented by the % wildcard. You present your own example in the form of this rule:
%.o: %.cpp
g++ -c $< -std=gnu++11
On the other hand, this rule ...
launch.exe: %.o
g++ -o $# $^
... is not a pattern rule, because the target name does not contain a %. There, you seem to be trying to use % in an entirely different sense, analogous to * in a glob pattern. It does not serve that purpose, even in pattern rules. That would give pattern rules a very different (and much less useful) meaning. Instead, in your non-pattern rule, the % is treated as an ordinary character.
There are many ways to write makefiles, but a good, simple model to start from for exploring pattern rules would be a combination of your first and second examples:
all: launch.exe
launch.exe: source.o 2ndfile.o
g++ -o $# $^
%.o: %.cpp
g++ -c $< -std=gnu++11
Substitute % with *.
all: launch.exe
launch.exe: *.o
g++ -o $# $^
*.o: *.cpp
g++ -c $^ -std=gnu++11
EDIT: there's an answer below why this is a bad idea. Here's what works:
all: launch.exe
launch.exe: Source.o 2ndfile.o
g++ -o $# $^
%.o: %.cpp
g++ -c $^ -std=gnu++11

Override static pattern rule in Makefile (without it giving a warning)

I would like to use a static pattern rule to specify a default recipe for a class of targets, but override that recipe for a few specific targets.
Here's a trivial example that illustrates what I'm trying to do. For each directory that contains a file "test.py" I want to invoke the command "run_test.py", except when the directory is named "one" I want to invoke a different set of commands:
TESTS := $(shell find * -name "test.py" | xargs -I {} dirname {})
.PHONY: $(TESTS)
all: $(TESTS)
$(TESTS): %:
python run_test.py $#
one:
python run_test.py $# mode=1
python run_test.py $# mode=2
python check_results.py $#
This works, but gives a warning:
$ make
Makefile:12: warning: overriding commands for target `one'
Makefile:9: warning: ignoring old commands for target `one'
Is there another way to do this, or eliminate the warning?
No, you can't do that. A static pattern rule is really not a pattern rule: instead it's just a shorthand for writing a lot of explicit rules.
If you want to have most targets use one recipe but a few use another recipe, you should define a real pattern rule for "most" targets, not a static pattern rule, then use explicit rules to override:
%.o: %.cc
g++ -c $< -o $#
test.o: test.cc
g++ -Wall -c $< -o $#
Why do you want to use a static pattern rule instead of a regular pattern rule?
ETA You could also use target-specific variables:
CFLAGS =
test.o: CFLAGS = -Wall
$(OBJS): %.o: %.cc
g++ $(CFLAGS) -c $< -o $#
ETA2 OK, that's much different than your original example.
You have two obvious choices that I can see. The first is to remove the special targets from the list; something like:
SPECIAL_TESTS := one
TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))
.PHONY: all $(TESTS)
all: $(TESTS)
$(filter-out $(SPECIAL_TESTS),$(TESTS)):
python run_test.py $#
$(SPECIAL_TESTS):
python run_test.py $# mode=1
python run_test.py $# mode=2
python check_results.py $#
The other way to do it is with target-specific variables that define the entire recipe, something like this:
TEST_RECIPE = python run_test.py $#
one: TEST_RECIPE = python run_test.py $# mode=1 \
&& python run_test.py $# mode=2 \
&& python check_results.py $#
TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))
.PHONY: all $(TESTS)
all: $(TESTS)
$(TESTS):
$(TEST_RECIPE)

Makefile pattern matching failure

BINS = $(patsubst %.c, %, $(SRCS))
all: $(BINS)
%: %.o
$(info ---------- linking $< ---------)
$(CC) $< -o $# -L$(LIBPATH) -llibrary
Will name in $(BINS) match %? I need the rule %: %.o to be invoked which in turn calls other rule to create .os. But this match is not happening due to which implicit rules are getting triggered.
My goal is to create binaries with same name as their .c files with out the extension. .os should be created in the process
This might sound drastic, but you should remove all rules, then it will work. Yes, I'm serious. make has built-in rules to create foo from foo.c by compiling, since it is so common. Watch it happen:
$ cat hello.c
#include <stdio.h>
int main (void)
{
printf ("hello, world\n");
return 0;
}
$ cat Makefile
cat: Makefile: No such file or directory
$ make CFLAGS=-lm hello
cc -lm hello.c -o hello
$ ./hello
hello, world
$
More realistically, if you want to compile a set of executables each from their *.c counterpart, all you need in your Makefile is
all: prog1 prog2 progN
Sweet, ain't it?
This works for me:
all : ${BINS}
%.o: %.c
$(CC) -c -o $# $<
$(BINS) : %: %.o
#echo ---------- linking $< ---------
$(CC) -o $# $< -L$(LIBPATH) -llibrary
It would be simpler to compile and link in one go:
$(BINS) : %: %.c
#echo ---------- compiling and linking $< ---------
$(CC) -o $# $<

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.

Resources