what does % mean in a makefile rule - c++

So i know that the pattern rule %.o : %.cpp is for making any file.o from a file.cpp
But what I want is different. Let's say I want to make a file1.o from folder1/file1.cpp, and a file2.o from folder2/file2.cpp.
What i thought about doing was :
file1=folder1/file1
file2=folder2/file2
%.o: $(%).cpp
But that doesn't work. Do anyone have an idea on how to do that apart from manually doing :
file1=folder1/file1
file2=folder2/file2
file1.o: $(file1).cpp
file2.o: $(file2).cpp

The meaning of % in GNU Make is documented in the seciton on Defining and Redefining Pattern Rules.
If the target name is foo.o, then % is foo. I don't want to go into any more depth on the meaning of % here.
In your case, the dependencies between the object files and the source files cannot be expressed easily using a single simple rule. I would advise making the rules explicit instead of using a pattern-based rule.
file1.o : folder1/file1.cpp
file2.o : folder2/file2.cpp
You'll need to add the commands to build those targets too.
file1.o : folder1/file1.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $^
file2.o : folder2/file2.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $^

Related

Any way to use variables as rules and prerequisites in GNU Make?

I'm trying to set up my Makefile in such a way that I can define all of the inputs and outputs in some variables so I only have to write a single rule to compile the project. This allows me to minimize Makefile code and still have control over what is in my project. This is the relevant snippet of code:
ROOT_OBJS= \
$(B)/main.o \
$(B)/src1.o
ROOT_SRC= \
$(SRC)/main.cpp \
$(SRC)/src1.cpp
$(TARGET) : $(ROOT_OBJS)
$(LD) $(LD_FLAGS) $^ -o $#
$(ROOT_OBJS) : $(ROOT_SRC)
$(CXX) $(CFLAGS) $< -o $#
This mostly works except for the $< part in the second rule, it always uses main.cpp. Is there any fix to this or am I going about this the wrong way?
EDIT: for clarification, this is the output I expect:
g++ main.cpp -o main.o
g++ src1.cpp -o src1.o
This is the output I get:
g++ main.cpp -o main.o
g++ main.cpp -o src1.o
I am aware this is because $< takes the first dependency, I thought make would be smart enough to figure it out because the .o behavior is what I want.
$^ is not what I am looking for. I want gcc to make a separate object file for each cpp file.
$< always takes the first prerequisite. Since your rule expands to
$(B)/main.o $(B)/src1.o : $(SRC)/main.cpp $(SRC)/src1.cpp
$(CXX) $(CFLAGS) $< -o $#
$(SRC)/main.cpp is always that first prerequisite. There is no magical connection between $(B)/main.o and $(SRC)/main.cpp as far as make is concerned.
If you want your rules to make this connection, you have to code it into the rules. There are several ways to get this right. The most straight forward is to write separate rules for each target:
$(B)/main.o : $(SRC)/main.cpp
$(CXX) $(CFLAGS) $< -o $#
$(B)/src1.o : $(SRC)/src1.cpp
$(CXX) $(CFLAGS) $< -o $#
You can also use a pattern rule like this:
$(B)/%.o : $(SRC)/%.cpp
$(CXX) $(CFLAGS) $< -o $#
Here, $< does the right thing because $(SRC)/%.cpp is parameterized with the pattern, so it will expand to the correct source file.
The biggest gun you have is generating the individual rules:
STEMS := main src1
$(foreach stem,$(STEMS), \
$(eval $(B)/$(stem).o: $(SRC)/$(stem).cpp ; $(CXX) $(CFLAGS) $< -o $#))
Here I loop over all the words in $(STEMS) with the $(foreach) intrinsic function call and generate one rule per iteration with the $(eval) function call. This is GNU Make syntax, only, other make implementations are likely not to have these features. However, it is the most general and flexible way to tell make what to do. GNU Make's function call syntax is turing complete, so you can perform any calculations you need to come up with the correct rules. Readability will suffer, though, so use this with care.

Looping makefile with multiple main functions

I am trying to write a makefile that can create one executable per main function.
I have a list of files: main1.cpp, main2.cpp, and main3.cpp. They each contain an int main() function. Obviously I can't build these into one exec, which is not the goal here, so how can I build each one of these into its own executable? This is one solution:
main1: main1.cpp
$(CC) -o $# $^
main2: main2.cpp
$(CC) -o $# $^
main3: main3.cpp
$(CC) -o $# $^
But there MUST be a better way to do this. Is there some type of looping feature to makefiles that will make this process easier? Like a for loop?
A mixture of wildcard, patsubst and static pattern rules, plus the standard make variables for C++ compilation and linking:
SRCS := $(wildcard main*.cpp)
EXES := $(patsubst %.cpp,%,$(SRCS))
$(EXES): %: %.cpp
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $# $< $(LDLIBS)
But as make knows already how to make all this you could as well get rid of your Makefile and just type make main1...
While it's not a very sophisticated makefile, your solution is fine for three simple programs. You could make it more generic and support building all three targets at the same time with an "all" target.
all: main1 main2 main3
main1: main1.cpp
$(CC) -o $# $^
main2: main2.cpp
$(CC) -o $# $^
main3: main3.cpp
$(CC) -o $# $^

makefile picks the same source file again and again for different objects

I am trying to write a makefile, suppose I have 4 source files in a directory src/app/:
src/app/file1.cpp
src/app/file2.cpp
src/app/file3.cpp
src/app/file4.cpp
and I want to create different object files (i.e. file1.o, file2.o etc.) into another directory called obj/. In the makefile, I am defining the variables like this:
$(SRC) := $(wildcard src/app/*.cpp)
$(OBJ) := $(addprefix obj/,$(notdir $(SRC:.cpp=.o)))
and my commands are like this:
all: $(OBJ)
$(OBJ): $(SRC)
$(CC) $(CFLAGS) -I/src/app/app.h -c $< -o $#
so when I run make, I see these operations:
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file1.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file2.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file3.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file4.o
You can see, the object files have different names but the source file is the same. How do I fix it ?
Please note that I can't use %.o: %.cpp since I have other targets in my makefile for different purposes.
If you can't use
obj/%.o: src/app/%.cpp
then the second simplest way is to add $(OBJ): to the front:
$(OBJ): obj/%.o: src/app/%.cpp
It's called "static pattern rules" - look it up in the GNU Make manual.
I have found a way to solve this (thanks to Zereges for the idea):
$(RGAOBJ): $(RGASRC)
$(CC) $(CFLAGS) -I/src/app/app.h -c \
$(addprefix src/app/,$(notdir $(#:.o=.cpp))) -o $#
I think there is a better way to do.
So any other pointer will be helpful.
The $< variable picks up the first dependency. It is used with generic targets which have variable targets and produce different results. The compile target would match a pattern as target and have a generic dependency. The first target doesn't change in your case.
Your constraint of not being able to use a generic rule is entirely defeating the purpose of the $< variable. A somewhat naive work-around is to translate the destination name back into the source, e.g.,
$(OBJ): $(SRC)
$(CC) $(CFLAGS) -I/src/app/app.h -c $(#:%.o=%.cpp) -o $#
The problem with that approach is that no all object files depend on all source files. As a result, every time one of the source files is changed all object files are produced. For tiny projects and source that may be viable. On anything which I'd consider a real project neither of these conditions holds.
My understanding on your statement on not being able to use pattern rules is that you already have rules for the same pattern but you need to build some targets with some special rules. A work around for that situation is to build targets with a custom suffix which actually build something different and just use a marker file to prevent unnecessary rebuilds. For example:
all: $(OBJ:%=%.custom)
%.o.custom: %.cpp
$(CC) $(CFLAGS) -W -I/src/app/app.h -c $< -o $(#:%.custom=%) && touch $#

GNU makefile rules and dependencies

I've been doing a lot of reading on how to write makefiles to build an application on Linux but I'm massively confused about the many different ways to apparently achieve the same goal.
This is what I have come up with so far to build an archive.
SHELL = /bin/sh
CXX = g++
DEBUG = -g
CXXFLAGS = -std=c++11 -Wall -pedantic #-Wextra
CPPFLAGS = -I. \
-I./include
SOURCES = foo1.cpp \
foo2.cpp \
foo3.cpp
OBJECTS = $(SOURCES:.cpp=.o)
The following rule successfully compiles each source file into an object file and then creates an archive:
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
%.o: src/%.cpp ./include/%.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
This also does the same thing:
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
$(OBJECTS) : %.o:src/%.cpp
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
However, this fails with an error that there is no rule to make target 'foo1.o:%.h
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
$(OBJECTS) : %.o:src/%.cpp %.o:%.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
Can someone please explain why it doesn't work and which approach is best?
The first option lists the header files as dependencies but the second option doesn't. That is my motivation for the third option.
How do I list the headers as dependencies using options 2 or 3?
TIA
The feature you're using in try #2 and try #3 is static pattern rules and the syntax looks like this:
<targets...> : <target-pattern> : <prerequisites...>
There can only be two colons, not three. You should write your try #3 above as:
$(OBJECTS) : %.o : src/%.cpp %.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
Note one critical thing: this rule will FAIL if you ever create any .cpp file which does not have an associated .h file. Just sayin'.

GNU make kind-of-double colon

I've got a little problem understanding following gmake syntax:
OBJ = foo.o bar.o
$(OBJ): %.o: %.cpp
$(CC) -c -MMD -MP $(INCLUDES) $(CFLAGS) $< -o $#
#sed (...create empty targets in file...)
I'm not sure what $(...): %.o: %.cpp does!?
I think it might translate the "%.o: %.cpp" in correct %.cpp dependencies - does it? Google is not much of a help here - it finds just the usual double colon (target::) which is something different!
Any advice? Thanks!
This is a static pattern rule.
$(OBJ) is a list of targets. The %.o : %.cpp means "for each target in the list that matches %.o, it is dependent on %.cpp" (where the % is substituted accordingly).