Reputation: 38777
For example, lets say I have a compiler that can build foo
files from either bar
or baz
sources.
The rules for this might look like:
%.foo: %.bar
# commands to
# invoke compiler
%.foo: %.baz
# commands to
# invoke compiler
However, this could start getting a bit long and redundant as the number of input types and recipe commands increase. Is there any syntax available to compress this into a single rule?
%.foo: $(oneof %.bar %.baz)
# commands to
# invoke compiler
Upvotes: 3
Views: 335
Reputation: 99
What you propose at the beginning is right: Makefiles should be clear and concise regarding building rules.
In the other hand you may take a look at Canned Recipes to try to avoid repeating the same recipes once and again:
define MAKE_FOO =
#You may use automatic variables such as $^ or $@.
mv $< $@ #In this example just a file renaming.
endef
%.foo: %.bar
$(MAKE_FOO)
%.foo: %.baz
$(MAKE_FOO)
The canned recipe MAKE_FOO
will expand to whatever recipes you write inside the define
statement as if they were copied manually.
Upvotes: 2
Reputation: 61432
Here's an illustration for the concrete problem of making an .o
file
from either a .c
file or a .cpp
file with a combined pattern rule.
An executable is also built to aid the illustration.
Makefile
.PHONY: all clean
all: test
%.o: %.c %.cpp
gcc -c $?
test: main.o hw.o
g++ -o $@ $^
clean:
rm -f test *.o
where we have:
hw.c
#include <stdio.h>
void hw(void)
{
puts("Hello from C");
}
hw.cpp
#include <iostream>
extern "C" void hw()
{
std::cout << "Hello from C++" << std::endl;
}
and:
main.cpp
extern "C" void hw(void);
int main(void)
{
hw();
return 0;
}
Make from clean and run:
$ make clean && make && ./test
rm -f test *.o
g++ -c -o main.o main.cpp
gcc -c hw.c hw.cpp
g++ -o test main.o hw.o
Hello from C++
Both hw.c
and hw.cpp
were compiled per the pattern rule.
Each one of them was compiled to the same object file, hw.o
, with the second, C++
compilation overwriting the C compilation. So the C++ object file was linked,
simply because it was the last to be built. Be clear about what you expect to
happen when the combined rule is triggered by multiple prerequisites.
Now let's update hw.c
and repeat:
$ touch hw.c
$ make && ./test
gcc -c hw.c
g++ -o test main.o hw.o
Hello from C
This time, hw.o
was compiled only from hw.c
, and linked.
Update hw.cpp
and repeat:
$ touch hw.cpp
make && ./test
gcc -c hw.cpp
g++ -o test main.o hw.o
Hello from C++
Once again, the hw.o
from C++ was linked.
The key element of the combined pattern rule is $?
, which
means all the prerequisites that are newer than the target
Upvotes: 1