creating implicit rules with multiple prerequisites in a makefile - makefile

I have a makefile that has lots of similar looking statements:
ABC_01.exe: ABC_01.o ../constant.o
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll
ABC_02.exe: ABC_02.o ../constant.o
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll
ABC_03.exe: ABC_03.o ../constant.o
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll
ABC_04.exe: ABC_04.o ../constant.o
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll
I would like to know if I can create an implicit rule
%.exe:%.o ???
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll
so that I don't have to repeat the rule for each executable target.

No problem:
ABC_%.exe: ABC_%.o ../constant.o
gcc $^ -o $# $(SOMEPATH)/bin/constant.dll

Related

Makefile with `ifeq` test for specific file

I am trying to set an if test for a specific file in my Makefile to compile it with different flags:
.f90.o:
ifeq ($<,main.f90)
#echo ok $<
$(F90) -c $< -o $#
else
#echo nope $<
$(F90) $(F90FLAGS) $(DEBUG) $(INCL) -c $< -o $#
endif
..and despite my efforts I am getting only:
nope main.f90
mpif90 -O2 -g -fbacktrace -fPIC -c main.f90 -o main.o
The ifeq conditional you have used is processed by Make at parse time, not when the recipe is executed. The macro $< is empty when your script is parsed so your recipe only ever contains the latter two lines.
One solution is to provide two recipes, one for your special case and then a pattern recipe for the rest:
main.o:main.f90
$(F90) -c $< -o $#
.f90.o:
$(F90) $(F90FLAGS) $(DEBUG) $(INCL) -c $< -o $#

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

Makefile with generic intermediate rules

I have a makefile that works that looks like this:
TARGET:=prog
SOURCES:=a.c b.c
CFLAGS:=-Wall -g -O2
OBJECTS:=$(SOURCES:%.c=%.o)
$(TARGET): $(OBJECTS)
gcc -o $# $^
%.o: %.c
gcc $(CFLAGS) -c -o $# $<
clean:
rm -f $(TARGET) $(OBJECTS)
The only variables that the user needs to change are the target name and the sources required to build it. The objects that need to be generated are automatically determined from the sources. I would like to extend this to support multiple targets, each with its own list of sources. I'm having trouble getting the syntax right, though. This is the general idea:
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
OBJECTS_$#=$(SOURCES_$#:%.c=%.o)
$(TARGETS): $(OBJECTS_$#)
gcc -o $# $^
%.o: %.c
gcc $(CFLAGS) -c -o $# $<
clean:
rm -f $(TARGET) $(OBJECTS)
But I can't get the object list to be generated correctly. I'm also unsure how to write the clean rule to clean all of the objects. Is this possible?
There are two primary ways that I see to do this.
The first involves dynamically creating the target/prerequisite mappings using the $(eval) function.
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
$(TARGETS):
gcc -o $# $^
$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o))$(eval $t: $(OBJECTS_$t)))
The second involves using Secondary Expansion.
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
.SECONDEXPANSION:
$(TARGETS): $$(OBJECTS_$$#)
gcc -o $# $^
$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o)))
In either case the clean target becomes:
clean:
rm -f $(TARGETS) $(foreach t,$(TARGETS),$(OBJECTS_$t))

variable error in makefile

I have Makefile in Ubuntu12.10 as below.
when I run it by make command, it shows as
g++ -c -o myprog1.o myprog1.cpp
It seems the variables CFLAGS and CINCLUDE do not work.
Can any one help me to check it?
Thanks,
RM = rm -f
CC = gcc
AR = ar rc
CFLAGS= -Wall -g -O2 -std=c++11 -fPIC
CINCLUDE= -I. -I../include
OBJECTS= myprog1.o myprog2.o
STATIC_LIB = libctest.a
$(STATIC_LIB): $(OBJECTS)
$(AR) $(STATIC_LIB) $(OBJECTS)
%.o : %.c
$(CC) -c $(CFLAGS) $(CINCLUDE) $< -o $#
clean:
$(RM) $(OBJECTS)
$(RM) $(STATIC_LIB)
The problem is that you have a make rule for %.o : %.c but not for %.o : %.cpp. When you run the make, the implicit make rule for '%.cpp' runs, but the implicit rule doesn't contain references to CFLAGS or CINCLUDE.
Since your source is in c++, you probably want to add another rule for c++ compilation and set up the CXX variables appropriately.
CXXFLAGS = $(CFLAGS)
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $(CINCLUDE) $< -o $#

What do $< and $# represent in a Makefile?

Can anybody please explain the meaning of $< and $# in a Makefile?
$< evaluates to the first "prerequisite" in the make rule, and $# evaluates to the "target" in the make rule.
Here's an example:
file.o : file.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
In this case, $< will be replaced with file.c and $# will be file.o.
These are more useful in generic rules like this:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
See this manual for more info.
$# is the target of the current rule.
$< is the name of the first prerequisite ("source") of the current rule.
So for example:
.c.o:
$(CC) -c $(CFLAGS) -o $# $<
This will expand to a command something like:
gcc -c -Wall -o foo.o foo.c
See also the GNU make manual ยง 10.5.3, "Automatic Variables".

Resources