How to expand makefile variable in prerequisites list? - c++

I am having an issue defining a prerequisites for my targets while using file lists in variables the problem is as follows:
in my makefile:
... some basic defines
SOURCES=HelloC.cpp \
HelloS.cpp \
HelloI.cpp \
main.cpp
SOURCES_CLIENT=Hello_Client_impl.cpp \
HelloC.cpp
OBJECTS_SERVER_DIR=obj_s/
OBJECTS_CLIENT_DIR=obj_c/
OBJECTS_SERVER=$(addprefix $(OBJECTS_SERVER_DIR),$(SOURCES:.cpp=.o))
OBJECTS_CLIENT=$(addprefix $(OBJECTS_CLIENT_DIR),$(SOURCES_CLIENT:.cpp=.o))
EXECUTABLE_SERVER=server
EXECUTABLE_CLIENT=client
all: dirs server_exe client_exe
dirs:
#echo create dirs
$(CREATE_DIR) $(OBJECTS_SERVER_DIR)
$(CREATE_DIR) $(OBJECTS_CLIENT_DIR)
server_exe: $(EXECUTABLE_SERVER)
client_exe: $(EXECUTABLE_CLIENT)
$(EXECUTABLE_SERVER): $(OBJECTS_SERVER)
$(CXX) $^ $(LFLAGS) $(LIBS) -o $#
$(EXECUTABLE_CLIENT): $(OBJECTS_CLIENT)
$(CXX) $^ $(LFLAGS) $(LIBS) -o $#
# problematic line 1
$(OBJECTS_SERVER): $(SOURCES)
$(CXX) -c $(CPPFLAGS) -o $# $<
# problematic line 2
$(OBJECTS_CLIENT): %.o : %.cpp
$(CXX) -c $(CPPFLAGS) -o $# $<
Running it (as dry run) I will get:
$ make -n
echo create dirs
mkdir -p obj_s/
mkdir -p obj_c/
g++ -c -Wall -I. -I/usr/include/ -I/usr/include/orbsvcs/ -I/usr/include/tao/ -I/usr/include/tao/PortableServer/ -o obj_s/HelloC.o HelloC.cpp
g++ -c -Wall -I. -I/usr/include/ -I/usr/include/orbsvcs/ -I/usr/include/tao/ -I/usr/include/tao/PortableServer/ -o obj_s/HelloS.o HelloC.cpp
g++ -c -Wall -I. -I/usr/include/ -I/usr/include/orbsvcs/ -I/usr/include/tao/ -I/usr/include/tao/PortableServer/ -o obj_s/HelloI.o HelloC.cpp
g++ -c -Wall -I. -I/usr/include/ -I/usr/include/orbsvcs/ -I/usr/include/tao/ -I/usr/include/tao/PortableServer/ -o obj_s/main.o HelloC.cpp
g++ obj_s/HelloC.o obj_s/HelloS.o obj_s/HelloI.o obj_s/main.o -L/usr/lib64/ -lTAO_PortableServer -lTAO_AnyTypeCode -lTAO -lACE -o server
make: *** No rule to make target `obj_c/Hello_Client_impl.cpp', needed by `obj_c/Hello_Client_impl.o'. Stop.
problematic line 1 will not expand and will always keep the first source file (HelloC.cpp) as a parameter while the second one is defined with prefix. How can I handle this so that it compiles? I would like to have source files in root dir and object files in obj_c and obj_s directories

EDIT: I originally answered the wrong question in haste, sorry about that. Anyway, the static pattern rule is the way to go, but you have to factor in the prefix. Instead of
$(OBJECTS_CLIENT): %.o : %.cpp
Use
$(OBJECTS_CLIENT): $(OBJECTS_CLIENT_DIR)%.o : %.cpp

Related

Simplifying the Makefile

I use this Makefile to build a small C++ application:
BIN_CPP=Main
CPP=g++
INCLUDES_APR=/usr/local/apr/include/apr-1
LIB_SRC = $(wildcard My*.cpp)
LIB_OBJ = $(LIB_SRC:.cpp=.o)
RM=rm
all: Main
MyClass.o: MyClass.cpp
$(CPP) -I$(INCLUDES_APR) -c $< -o $#
MyModel.o: MyModel.cpp
$(CPP) -I$(INCLUDES_APR) -c $< -o $#
libMyLibrary.so: $(LIB_OBJ)
$(CPP) -fPIC -shared -o $# $^
Main.o: Main.cpp
$(CPP) -o $# -c $^ -I$(INCLUDES_APR)
Main: libMyLibrary.so Main.o
$(CPP) $^ -o $# -L/usr/local/apr/lib -L. -lapr-1 -lMyLibrary
.PHONY: clean
clean:
$(RM) -f *.o *.so $(BIN_CPP)
When I remove then first two targets and extend the libMyLibrary.so one, it fails:
# MyClass.o: MyClass.cpp
# $(CPP) -I$(INCLUDES_APR) -c $< -o $#
# MyModel.o: MyModel.cpp
# $(CPP) -I$(INCLUDES_APR) -c $< -o $#
libMyLibrary.so: $(LIB_OBJ)
$(CPP) -fPIC -shared -o $# $^ -I$(INCLUDES_APR)
and the error message is this:
g++ -c -o MyClass.o MyClass.cpp
In file included from MyClass.cpp:1:
MyClass.hpp:3:10: fatal error: apr_general.h: No such file or directory
3 | #include <apr_general.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
make: *** [<builtin>: MyClass.o] Error 1
The -I$(INCLUDES_APR) is missing from the automake output. What is wrong with this build file?
By removing the explicit rules, you are relying on GNU make's built-in rules to compile your files, which is good. But GNU make's built-in rules can't possibly know about your local variable INCLUDES_APR, so when it compiles the source files that variable is not used.
You should add the -I flag to the standard variable CPPFLAGS (the "CPP" here stands for "C preprocessor", not "C++"), which is what make uses to compile in its built-in rules.
Example:
BIN_CPP=Main
CPP=g++
INCLUDES_APR=/usr/local/apr/include/apr-1
CPPFLAGS=-I$(INCLUDES_APR)
LIB_SRC = $(wildcard My*.cpp)
LIB_OBJ = $(LIB_SRC:.cpp=.o)
RM=rm
all: Main
libMyLibrary.so: $(LIB_OBJ)
$(CPP) -fPIC -shared -o $# $^
Main: Main.o libMyLibrary.so
$(CPP) $< -o $# -L/usr/local/apr/lib -L. -lapr-1 -lMyLibrary
.PHONY: clean
clean:
$(RM) -f *.o *.so $(BIN_CPP)
Possible make output
g++ -I/usr/local/apr/include/apr-1 -c -o Main.o Main.cpp
g++ -I/usr/local/apr/include/apr-1 -c -o MyClass.o MyClass.cpp
g++ -I/usr/local/apr/include/apr-1 -c -o MyModel.o MyModel.cpp
g++ -fPIC -shared -o libMyLibrary.so MyClass.o MyModel.o
g++ Main.o -o Main -L/usr/local/apr/lib -L. -lapr-1 -lMyLibrary

Makfile usees same cpp file to generate objects [duplicate]

This is a part of my makefile :
SRC = ./
DIRS = src libs/maths libs/struct
BIN_DIR = ./bin/
SRC_DIRS= $(foreach dir, $(DIRS), $(addprefix $(SRC), $(dir)))
SRC_TEST= $(sort $(SRC_DIRS))
SRCS = $(foreach msrc, $(SRC_DIRS), $(wildcard $(msrc)/*.c))
DEL_PRE = $(foreach target, $(SRCS), $(notdir $(target)))
ADD_PRE = $(foreach target, $(DEL_PRE), $(addprefix $(BIN_DIR), $(target)))
OBJS = $(ADD_PRE:.c=.o)
.PHONY: all clean re
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LDLIBS)
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
When i use make all, i have in output :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c src/main.c
gcc -o bin/pears.o -c src/main.c
gcc -o bin/outil.o -c src/main.c
gcc -o bin/verif.o -c src/main.c
But i would like to have for each target, it assigned dependency :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c libs/maths/cosin.c
gcc -o bin/pears.o -c libs/maths/pears.c
gcc -o bin/outil.o -c libs/struct/outil.c
gcc -o bin/verif.o -c libs/struct/verif.c
How can i fix it ?
This seems like a very common misconception; I just answered effectively this same question yesterday. I'm not sure where it comes from or how to combat it.
This rule:
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
does not somehow magically combine the contents of the OBJS variable and the SRCS variable to figure out how they match up. The variable references are simply expanded, and the result is this:
bin/main.o bin/cosin.o ... : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
which is the same as if you'd written this:
bin/main.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
bin/cosin.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
...
Now, you can hopefully see why you compile the same file: in every rule you have the same prerequisites, so $< is always the first one, which is always src/main.c.
There are multiple ways to work this but if you really want to have all the source files from different directories compiled into object files in the same directory your job is harder, because there's no common pattern that will match them all. In this case the simplest thing to do is use VPATH for directory search: replace the above rule with this:
$(BIN_DIR)/%.o : %.c
$(CC) -o $# -c $<
then tell make how to find your source files, like this:
VPATH := $(sort $(dir $(SRCS))
Be aware this method can't be used for any source files that are themselves generated output that make is expected to create.

Building shared libraries with Makefile

I have a project that I want to build a shared library for it. The following Makefile works:
libfastpd.so: fastpd.cpp
$(CXX) -std=c++11 -fPIC -c fastpd.cpp -o fastpd.o
$(CXX) -std=c++11 -fPIC -c graph.cpp -o graph.o
$(CXX) -std=c++11 -fPIC -c LinkedBlockList.cpp -o LinkedBlockList.o
$(CXX) -std=c++11 -fPIC -c maxflow.cpp -o maxflow.o
$(CXX) -std=c++11 -shared -Wl,-soname,libfastpd.so -o libfastpd.so fastpd.o graph.o LinkedBlockList.o maxflow.o
clean:
rm *.o *.so
Then I came across this recipe in Cogswell et al.'s C++ Cookbook: https://www.oreilly.com/library/view/c-cookbook/0596007612/ch01s18.html
and decided to improve my Makefile based on that:
# Specify extensions of files to delete when cleaning
CLEANEXTS = o so
# Specify the source files, the target files,
# and the install directory
SOURCES = fastpd.cpp graph.cpp LinkedBlockList.cpp maxflow.cpp
OUTPUTFILE = libfastpd.so
INSTALLDIR = ./
.PHONY: all
all: $(OUTPUTFILE)
# Build lib*.so from all the *.o;
# subst is the search-and-replace
# function demonstrated in Recipe 1.16
$(OUTPUTFILE): $(subst .cpp,.o,$(SOURCES))
$(CXX) -shared -fPIC $(LDFLAGS) -o $# $^
.PHONY: install
install:
mkdir -p $(INSTALLDIR)
cp -p $(OUTPUTFILE) $(INSTALLDIR)
.PHONY: clean
clean:
for file in $(CLEANEXTS); do rm -f *.$$file; done
# Generate dependencies of .ccp files on .hpp files
include $(subst .cpp,.d,$(SOURCES))
%.d: %.cpp
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
Running this file I obtained the following error:
/usr/bin/ld: fastpd.o: relocation R_X86_64_32 against `.rodata' can
not be used when making a shared object; recompile with -fPIC
fastpd.o: error adding symbols: Bad value
Checking the terminal output, I observed that the following commands were executed:
g++ -c -o fastpd.o fastpd.cpp
g++ -c -o graph.o graph.cpp
g++ -c -o LinkedBlockList.o LinkedBlockList.cpp
g++ -c -o maxflow.o maxflow.cpp
No -fPIC!
My question is: Which lines of the Makefile execute these commands and how to add -fPIC to them?
Any references to good ressources to understand the entire Makefile above would be very much appreciated as well!
Thank you very much in advance for your help!
Which lines of the Makefile execute these commands... ?
The short answer is none. The rule...
$(OUTPUTFILE): $(subst .cpp,.o,$(SOURCES))
$(CXX) -shared -fPIC $(LDFLAGS) -o $# $^
only specifies the link time dependencies and command. The -fPIC option needs to be specified when you compile the source file but you haven't provided any rule to build a .o from a .cpp so make falls back on its implicit rule which (for the purposes of this example) is essentially...
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
So the obvious solution is to add -fPIC to CXXFLAGS...
CXXFLAGS += -fPIC

What is the diferrence between $(objs): %.o : %.cpp and $(objs): $(objs:.o=.cpp) in Makefile

I have add.c sub.c in current directory and compile them through makefile.
I do the following:
program 1:
objs=$(patsubst %.cpp, %.o, $(wildcard *.cpp))
$(objs): %.o : %.cpp
g++ -o $# -c $<
program 2:
objs=$(patsubst %.cpp, %.o, $(wildcard *.cpp))
$(objs): $(objs:.o=.cpp)
g++ -o $# -c $<
Program 1 compiles successfully. But program 2 gets the following command:
g++ -o sub.o -c sub.cpp
g++ -o add.o -c sub.cpp
So what's the diferrence between these two programs?
The rule in makefile 1 is equivalent to
sub.o: sub.cpp
g++ -o $# -c $<
add.o: add.cpp
g++ -o $# -c $<
which works correctly.
The rule in makefile 2 expands to
sub.o add.o: sub.cpp add.cpp
g++ -o $# -c $<
Which says that each of those two targets depends on both source files. Note that the automatic variable $< expands to the first prerequisite, which in this case is sub.cpp. So that's the only source file that the rule uses, even when attempting to build add.o.

GCC linking a static library

I have seen questions like these on SO but everyone has different answers and directory structures that aren't working for me.
My makefile:
CC = g++
DEBUG = -g -std=c++11
TARGET = main
OBJECT_FILES = BingResultSet.o main.o
INC_PATH = -I HTTPClientLib/include
LIB_PATH = -L HTTPClientLib/lib/
start: clean BingResultSet.o main.o
$(CC) $(DEBUG) $(INC_PATH) $(LIB_PATH) $(OBJECT_FILES) -o $(TARGET)
rm -f *.o
BingResultSet.o: BingResultSet.cpp BingResultSet.h
$(CC) $(DEBUG) $(INC_PATH) $(LIB_PATH) -c BingResultSet.cpp
main.o: main.cpp
$(CC) $(DEBUG) $(INC_PATH) $(LIB_PATH) -c main.cpp
clean:
rm -f $(OBJECT_FILES) $(TARGET)
My file structure:
/Desktop/DataMiner/.cpp, .h, and makefile
/Desktop/DataMiner/HTTPClientLib/include/HTTPClient.h
/Desktop/DataMiner/HTTPClientLib/lib/HTTPClient.a
What's the correct way to link my static lib in my makefile?
Here's my $0.02:
there was no static library involved. Assuming you meant the .o files
you mix dependencies and build rules, instead, avoid repeating build rules:
$(TARGET): $(OBJECT_FILES)
$(CXX) $(DEBUG) $(INC_PATH) $^ -o $# $(LIB_PATH)
%.o: %.cpp
$(CXX) $(DEBUG) $(INC_PATH) -c $< -o $#
You used CC for a C++ compiler. That's strange. Use CXX
You used LDFLAGS when you were just compiling
You hardcoded the source and destination paths. Instead use the automatic variables ($^, $< for source; $# for destination)
You tried to hardcode header dependencies. That's error-prone and messes up source specification (you don't want $^ to list .h files in your command line...). Instead, use gcc -MM¹ to generate the dependencies for you!
Next, do a conditional include of those dependencies:
.depends:
$(CXX) -MM $(CXXFLAGS) -c *.cpp > $#
-include .depends
It's usually handy to keep the .o files so you can speed up builds. Of course, this was not a good plan until you generated the header dependencies automatically. If you insist, you can comment the .PRECIOUS target. Intermediate targets are automatically deleted by GNU Make
Here's the integrated offering I ended up with:
CXX = g++
TARGET = main
OBJECT_FILES = BingResultSet.o main.o
INC_PATH = -I HTTPClientLib/include
LIB_PATH = -L HTTPClientLib/lib/
CPPFLAGS = -g -std=c++11
CPPFLAGS+= $(INC_PATH)
# standard derived flags:
CXXFLAGS+=$(CPPFLAGS)
LDFLAGS+=$(LIB_PATH)
start: .depends $(TARGET)
$(TARGET): $(OBJECT_FILES)
$(CXX) $(CXXFLAGS) $^ -o $# $(LDFLAGS)
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
rm -f .depends $(OBJECT_FILES) $(TARGET)
# to keep the .o files:
.PRECIOUS: $(OBJECT_FILES)
.depends:
$(CXX) -MM $(CXXFLAGS) -c *.cpp > $#
-include .depends
On a very simple sample set of files you get:
$ make clean
rm -f .depends BingResultSet.o main.o main
$ make
g++ -MM -g -std=c++11 -I HTTPClientLib/include -c *.cpp > .depends
g++ -I HTTPClientLib/include -c BingResultSet.cpp -o BingResultSet.o
g++ -I HTTPClientLib/include -c main.cpp -o main.o
g++ -I HTTPClientLib/include BingResultSet.o main.o -o main -L HTTPClientLib/lib/
$ cat .depends
BingResultSet.o: BingResultSet.cpp BingResultSet.h
main.o: main.cpp BingResultSet.h
test.o: test.cpp
¹ (or similar, see man-page)