GNU makefile rules and dependencies - c++

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'.

Related

How can I use different rules in Makefile for two groups of files?

I have one Makefile to build an executable and a library. Executable consists of a lot of source files and library consists of one .cpp file. The difference between compilation of executable and library is -fPIC option.
There is a compilation rule:
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $#
all: $(TARGET) $(TARGET_LIB)
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
$(TARGET_LIB): $(LIBOBJS)
$(CXX) $(LDFLAGS) -fPIC -shared -o $# $^
I tried to add compilation rule for library and got this:
lib.o : lib.cpp
$(CXX) -fPIC -c $(CXXFLAGS) $< -o $#
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $#
all: $(TARGET) $(TARGET_LIB)
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
$(TARGET_LIB): $(LIBOBJS)
$(CXX) $(LDFLAGS) -fPIC -shared -o $# $^
Unfortunately, only lib is compiled in this case. Second rule is omitted.
How can I use a rule for one file and different rule for group of other files?
If you just run make without a target, the first target gets built. So just put all back at the top and it should work fine.

Combing object files generated out of C and C++ projects

I am trying to compile two projects together to create one executable. The first project is written in C and it uses the following portion of the makefile to generate the corresponding object files.
obj/%.o : %.c .dirs
$(CC) $(MKDEPEND) -w -c -o $# $(CFLAGS) $(INCDIRS) $<
The second project is written in C++ and it uses the following portion of the Makefile to generate the object file.
obj/%.o : %.cpp .dirs
$(CXX) $(MKDEPEND) -w -c -o $# $(CFLAGS) $(INCDIRS) $<
When I try to create the final executable, I receive an "undefined reference to function" for my C objects. What am I doing wrong? Any help is appreciated.
$(TARGET) : $(OOBJS) $(SUBTARGETS)
$(CXX) -w -o $(TMP_TARGET) $(OOBJS) $(LIBS) $(LFLAGS) $(SUBTARGETS) && mv -f $(TMP_TARGET) $#

Do the flags get called when I make this program?

I recently got feedback that my Makefile doesn't call the required flags. This is a snippet of my Makefile.
CXX = g++
CXXFLAGS = -Wall
all: testFacility testCode testRunway testSiteNumber airport distance
testFacility: testFacility.cpp Facility.o gcdistance.o
$(CXX) -o $# $^
Does the flag "-Wall" get called when I type Make?
No, it needs to be referenced directly:
$(CXX) $(CXXFLAGS) -o $# $^
You probably want to define something to compile all those .cpp files too:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
testFacility: testFacility.o Facility.o gcdistance.o
$(CXX) $(CXXFLAGS) -o $# $^

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 not updating one particular file

I have a makefile which works fine for all other files, but not for the main.cpp file. When I change the main.cpp file, it does not update main.o.
here is the makefile:
CXX = g++
SRCF = main.cpp Animal.cpp
SRC = $(addprefix src/, $(SRCF))
VER = Debug
CXXFLAGS = -Wall -std=c++17
EXE = Animal
OBJF = $(subst .cpp,.o, $(SRCF))
OBJ = $(addprefix src/obj/, $(OBJF) )
#PKG = `pkg-config --libs --cflags sdl2`
$(VER)/$(EXE) : $(OBJ)
$(CXX) $(CXXFLGS) -o $# $< $(PKG)
src/obj/%.o:src/%.cpp src/%.h
$(CXX) $(CXXFLGS) -c -o $# $< $(PKG)
clean:
rm -rf $(EXE) $(OBJ)
print-% : ; #echo $* = $($*)
When I change Animal.h or Animal.cpp it updates Animals.o and the Animal executable. But why does it not work for main ?? I have specified how to update main.o in this line :-
src/obj/%.o:src/%.cpp src/%.h
$(CXX) $(CXXFLGS) -c -o $# $< $(PKG)
Please help me and thanks it advance :)
In the Introduction to Pattern Rules section of GNU Make's manual:
In order for the pattern rule to apply, its target pattern must match the file name under consideration and all of its prerequisites (after pattern substitution) must name files that exist or can be made.
Therefore, if there is no src/main.h (or can't be made), the following pattern rule will not match against src/obj/main.o:
src/obj/%.o: src/%.cpp src/%.h
$(CXX) $(CXXFLGS) -c -o $# $< $(PKG)
You need an additional pattern rule without the src/%.h prerequisite:
src/obj/%.o: src/%.cpp
$(CXX) $(CXXFLGS) -c -o $# $< $(PKG)