patsubst in GNU make returns nothing - c++

I am trying to have my cpp source files and my object files in separate directories, so I'm trying to use Make's patsubst to replace the paths. After nothing was compiling, I made a phony target to simply print out the relevant variables and I discovered that patsubst was returning nothing. This doesn't make a lot of sense to me, as from what I can tell, targets that don't match the pattern should pass through unchanged, so even if my patterns are malformed I should still be seeing something get returned.
My variables are declared like this:
SRC_DIR := source/
SRC := $(wildcard $(SRC_DIR)*.cpp)
OBJ_DIR := obj/
OBJ := $(PATSUBST $(SRC_DIR)%.cpp, $(OBJ_DIR)%.o, $(SRC))
My phony target that just prints out the above variables looks like this:
.PHONY: print
print:
#echo $(SRC_DIR)
#echo $(SRC)
#echo $(OBJ_DIR)
#echo $(OBJ)
and the result of running make print is this:
user#athena:~/proj$ make print
source/
source/main.cpp source/util.cpp
obj/
user#athena:~/proj$
Other things I've tried
I've tried SRC_DIR and OBJ_DIR having trailing slashes and not having them, I've tried $(SRC:$(SRC_DIR)%.cpp=$(OBJ_DIR)%.o) which did work, and $(OBJ) would have both main.o and util.o, but then my static rule ($(OBJ): $(OBJ_DIR)%.o : $(SRC_DIR)%.cpp) would only trigger for main.cpp, and wouldn't try to compile util.cpp, which I'm considering a completely separate issue?
I hope I'm just doing something dumb and there's a simple fix, but I've been racking my brain and I can't see what would be causing patsubst to just be blank. Any help would be greatly appreciated.

Like (virtually) all programming languages, makefiles are case-sensitive. $(FOO) is not the same as $(foo), and $(PATSUBST ...) is not the same as $(patsubst ...).
In fact, $(PATSUBST ...) is nothing and expands to the empty string.

Related

Makefile - No rule to make target `PATH/TO/file.o`

I'm really new to makefile and I'm struggling to make it compile all the .cpp files inside the src folder.
right now the makefile looks like this:
SRC_DIR = src
OBJ_DIR = build/obj
INCLUDE_DIR = $(SRC_DIR)/inc
SRC_DIRS = $(wildcard $(SRC_DIR) $(SRC_DIR)/* $(INCLUDE_DIR)/*)
C_FILES = $(filter %.cpp, $(wildcard $(SRC_DIRS)/*.cpp))
OBJ_FILES = $(addprefix $(OBJ_DIR)/, $(notdir $(C_FILES:.cpp=.o)))
INCLUDE_PATH = -I$(INCLUDE_DIR)
CXXFLAGS = $(INCLUDE_PATH)
CXX = g++
CFLAGS = -Wall -g
CC = gcc
$(OBJ_DIR)/%.o: $(SRC_DIRS)/%.cpp
pile: $(OBJ_FILES)
test:
#echo $(C_FILES)
#echo $(OBJ_FILES)
and what I want to achieve with each rule is:
pile: when calling make pile it should check for all the .o files inside build/obj.
$(OBJ_DIR)/%.cpp: find the equivalent .cpp file inside the source folder and compile it.
I suppose that there's something wrong with my second rule, but I can't really tell why cause the test rule is printing all the files.. :/
thank you in advance for any help.
Looks like SRC_DIRS could be an array which will not be happy with that matcher function.
Try changing:
$(OBJ_DIR)/%.o: $(SRC_DIRS)/%.cpp
to
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
There are many problems here but the most fundamental is that you are not actually defining a rule when you write this line:
$(OBJ_DIR)/%.o: $(SRC_DIRS)/%.cpp
A rule consists of targets, prerequisites and a recipe. Here you have not provided a recipe, so you haven't told make how to actually build anything.
The other issue is as mentioned by #Ryan-Miller; you can't use multiple directories in a single rule like this. But you can just avoid the complexity anyway if all your source files are in a single directory.
If that's not what you want please make your question clear as to ALL the different things you need. You wrote "$(OBJ_DIR)/%.cpp: find the equivalente .cpp file inside the source folder and compiles it". How exactly are you defining "the equivalent .cpp file"? Computer programming is all about the details!

patsubst in makefile doesnt replace the full filepath

Im currently trying to get my makefile independend from my folder structure. So far i worked with a single specific folder containing all my .cpp files. My .o files are all placed in a seperate OBJ/ folder. However i now want my makefile to automatically grab all .cpp files from all subdirectories (any depth if possible) but still place all .o files the one same OBJ folder. This is how my makefile looks at the moment:
CC = g++ -g
SRC = Src/
OBJ = Obj/
BIN = Bin/
INC = -I Lib/GLFW/include/\
-I Lib/GLAD/include/\
-I Lib/STB/\
-I Lib/GLM/\
-I Src/Header/
LIB = -L Lib/GLFW/lib-mingw-w64 -lglfw3 -lopengl32 -lglu32 -lgdi32
EXE = $(BIN)Test.exe
SOURCEFILES = $(wildcard $(SRC)**/*.cpp)
OBJECTFILES = $(patsubst $(SRC)%.cpp,$(OBJ)%.o,$(SOURCEFILES))
all: $(SOURCEFILES) $(EXE)
$(EXE) : $(OBJECTFILES)
$(CC) -o $# $^ $(LIB)
$(OBJ)%.o: $(SRC)%.cpp
$(CC) -c $< $(INC) -o $#
It somewhat does what i want, but for some reason it currently is required to have the same folder structure of my SRC/ directory in OBJ/ aswell: If my .cpp file is SRC/foldername/name.cpp my makefile wants to create the .o as OBJ/foldername/name.o. I want it to be OBJ/name.o for all files regardless of the structure of SRC/ . What do i need to change to achieve that?
My second question is about the include path. As it can be seen in the makefile, all my header files are in a single directory Src/Header/. Is it possible to somehow also automatically get and link the right .h files from Src/ and it's subdirectories?
If you want to flatten paths, you can use notdir.
Unfortunately, because %.o is "magic", you can't just wrap it in a $(notdir).
By the way, as a matter of style, I'd leave the trailing slash out of those variables and use it in the expressions instead; it'll be much easier to read, and more flexible too.
This works for me:
SRC=srcPath
OBJ=objPath
SOURCEFILES = $(wildcard $(SRC)/**/*.cpp)
OBJECTFILES = $(addprefix $(OBJ)/, $(notdir $(patsubst $(SRC)/%.cpp, %.o, $(SOURCEFILES))))
all:
echo $(OBJECTFILES)
More pleasing alternatives surely exist, but the point is that you can use notdir to build your solution.
Flattening your object files in one single directory is not necessarily a very good idea. Your Makefile is getting more complex (see below) and there is a name collision possibility if, by accident, you have two source files with the same base name.
Anyway, it is what you want, and here is a possible solution:
SRC = Src
OBJ = Obj
SOURCEFILES = $(wildcard $(SRC)/**/*.cpp)
# $(1): full path to source file
define CompileRule
$$(OBJ)/$$(patsubst %.cpp,%.o,$$(notdir $(1))): $(1)
$$(CC) -c $$< $$(INC) -o $$#
endef
$(foreach f,$(SOURCEFILES),$(eval $(call CompileRule,$(f))))
It iteratively instantiates custom compilation rules for each of your source files. See the GNU make manual for a complete explanation.
I am not sure I fully understand your second question but if you want to find all header files in Src and build the list of -I<dir> compile options, you can probably try something like:
HEADERFILES := $(wildcard $(SRC)/**/*.h)
HEADERDIRS := $(sort $(dir $(HEADERFILES)))
INCLUDES := $(patsubst %,-I%,$(HEADERDIRS))
But it is very sub-optimal because every directory containing header files will be involved as -I<dir> in the compilation of every source file.
Last but not least, your next step could be "how do I automatically get the list of all header files a source file depends on?". If it is, you should probably have a look at this post about Auto-Dependency Generation.

Substitution reference with .cpp and .c files [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I know there a lot of questions about mixing .cpp and .c files into one makefile, but I haven't seen the issue of mixed substitution reference addressed. I am having issues with it.
My makefile is structure is based on this answer:
LIB=mylib.so
CPPSRCS += hello.cpp
CSRCS += goodbye.c
OBJS = $(CSRCS:.c=.o) $(CPPSRCS:.cpp=.o)
# Separate rules for .cpp and .c files, link together to form library.
# All pretty standard stuff and I am sure it will work if we goodbye.o and
# hello.o are present.
This doesn't work, and I get the old no rule to make target error. What am I doing wrong? How can I do substitution reference on two types of files into one variable?
In order to have a makefile work for both C and C++, you need separate rules for each language - although some rules are the same.
Another issue would be the linker. A C only project will use one linker and not the other.
I'm dumping my makefile here (it's from this project).
As you can see from this example, there are two different build rules, one for objects created with C file and another for objects created with C++. When the first one fails, the second one is attempted, so sharing a list of objects is made possible.
Also, you might notice that the C++ rule has this line $(eval CCL = $(CPP)) which sets the linker variable (CCL) to the C++ linker in projects where C++ is used. This way, when the build rule is called, it uses the correct linker.
Another thing to look at is the way this code deals with lists and extension substitution. Notice the use of the foreach, addsuffix and basename functions... this is distinctly more complex then the $(CSRCS:.c=.o) you suggested.
I would recommend you add a rule that displays the make variables, so you can debug any that have gone astray (see the demo), it a great way to learn as well as resolve issues.
A few words of warning about the makefile I'm pasting here...
It works for both C and C++ (mixed) projects and it's almost "plug and play", but you must to change the folder names and target files to fit your folder structure.
Also, notice that it will delete the whole of your project if you define the temporary folder as the project folder (it's defined as tmp for a reason, as it makes cleanup real easy).
In the future I might update it so any src subfolders are automatically added, but at the moment I need that extra control to exclude some folders.
This makefile is mostly a work of laziness... I hate updating makefiles all the time, so I have a low-cost makefile that mostly calculates everything on it's own... unless I change the project's folder structure or need different libraries.
NAME=demo
OUT_ROOT=./tmp
TMP_ROOT=./tmp
SRC_ROOT=.
SRC_EXTRA_FOLDERS=src src/http
LIBS=-pthread -lssl -lcrypto
INCLUDE=/usr/local/include
CC=#gcc
CPP=#g++
DB=#lldb
OPTIMIZATION=O3
#auto computed values
BIN = $(OUT_ROOT)/$(NAME)
SRCDIR = $(SRC_ROOT) $(foreach dir, $(SRC_EXTRA_FOLDERS), $(addsuffix /,$(basename $(SRC_ROOT)))$(dir))
SRC = $(foreach dir, $(SRCDIR), $(wildcard $(addsuffix /, $(basename $(dir)))*.c*))
BUILDTREE =$(foreach dir, $(SRCDIR), $(addsuffix /, $(basename $(TMP_ROOT)))$(basename $(dir)))
OBJS = $(foreach source, $(SRC), $(addprefix $(TMP_ROOT)/, $(addsuffix .o, $(basename $(source)))))
CCL = $(CC)
# the C flags
CFLAGS=-Wall -g -$(OPTIMIZATION) -std=c11 $(foreach dir,$(INCLUDE),$(addprefix -I, $(dir))) $(foreach dir,$(SRCDIR),$(addprefix -I, $(dir)))
CPPFLAGS= -Wall -$(OPTIMIZATION) -std=c++11 $(foreach dir,$(INCLUDE),$(addprefix -I, $(dir))) $(foreach dir,$(SRCDIR),$(addprefix -I, $(dir)))
$(NAME): build
build: $(OBJS)
$(CCL) -o $(BIN) $^ -$(OPTIMIZATION) $(LIBS)
$(TMP_ROOT)/%.o: %.c
$(CC) -o $# -c $^ $(CFLAGS)
$(TMP_ROOT)/%.o: %.cpp
$(CPP) -o $# -c $^ $(CPPFLAGS)
$(eval CCL = $(CPP))
clean:
-#rm $(BIN)
-#rm -R $(TMP_ROOT)
-#mkdir -p $(BUILDTREE)
execute:
#$(BIN)
run: | clean build execute
db: | clean build
$(DB) $(BIN)
vars:
#echo "BIN: $(BIN)"
#echo ""
#echo "SRCDIR: $(SRCDIR)"
#echo ""
#echo "SRC: $(SRC)"
#echo ""
#echo "BUILDTREE: $(BUILDTREE)"
#echo ""
#echo "OBJS: $(OBJS)"
#echo ""
#echo "CFLAGS: $(CFLAGS)"
#echo ""
#echo "CPPFLAGS: $(CPPFLAGS)"
As par Toby Speight's suggestion, I added the pipe sign (|) to mark the prerequisites as ordered, for all the concurrency people out there.

Generic Makefile

I am looking for a generic makefile, which will will build all C++ files in the current directory and all sub-directories (e.g, source, test files, gtest, etc)
I have spent a few hours trying out several and finally settled on the solution from make file with source subdirectories.
I need to make three changes to it:
Gtest uses *.cc for its C++ files and I have others which use *.cpp
I need to be able to define multiple search paths.
Add compiler flags, like -W all
I have managed to break the makefile, shown below, such that running make gives me
make: *** No rule to make target %.cpp=%.o', needed bymyProgram'.
Stop.
How can I make it do those three things?
# Recursively get all *.cpp in this directory and any sub-directories
SRC = $(shell find . -name *.cc) $(shell find . -name *.cpp)
INCLUDE_PATHS = -I ../../../ -I gtest -I dummies
#This tells Make that somewhere below, you are going to convert all your source into
#objects
# OBJ = src/main.o src/folder1/func1.o src/folder1/func2.o src/folder2/func3.o
OBJ = $(SRC:%.cc=%.o %.cpp=%.o)
#Tells make your binary is called artifact_name_here and it should be in bin/
BIN = myProgram
# all is the target (you would run make all from the command line). 'all' is dependent
# on $(BIN)
all: $(BIN)
#$(BIN) is dependent on objects
$(BIN): $(OBJ)
g++
#each object file is dependent on its source file, and whenever make needs to create
# an object file, to follow this rule:
%.o: %.cc
g++ -c $(INCLUDE_PATHS) $< -o $#
[Update] Thanks for the help so far. To address a few of the comments, I have no control over the mixed *.cc and *.cpp fiel extensions, and I can say that there won't ever be a source file in the directory tree which I do not wish to include in the build.
I am still having trouble with the SRC, as no input files are found. I guess that I should look more into the find command as it has been a while since I used Linux.
That is a rather poor makefile: it does not build header dependencies for you, so you are likely to end up with corrupted builds.
I shamelessly recommend this one.
Etan points out your problem. But you don't have to perform two replacements, just:
OBJ := $(addsuffix .o,$(basename $(SRCS)))
And, you should always be using :=, not =, for assignment when using the shell function.

What does `OBJECTS = $(SOURCES:.cpp=.o)` mean in a makefile

I am going over this tutorial and it has something like this
# File names
EXEC = run
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
.....
%.o: $(SRCPATH)/%.cpp $(INC)
$(CC) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
I am not sure if I understand the document and would appreciate it if someone could explain the last two statements. Here are my three questions regarding Makefile
Question 1 :
Whats the difference between
SOURCES = $(wildcard *.cpp)
and
SOURCES = $(*.cpp)
It says that the second case only works if .cpp files exist since they do not therefore it wont work. My question is why does the first one work ?
Question 2:
What does the 'wildcard *' mean ?
what does the last statement OBJECTS = $(SOURCES:.cpp=.o) mean ?
Question 3:
What does %.o mean when it is placed as a target ? Whats the difference between
*.o , %.o and wildcard *.cpp
SOURCES = $(*.cpp)
SOURCES = *.cpp
SOURCES = $(wildcard *.cpp)
The first one is an error, the second expands too late (not on definition), the third searches for all files with suffix .cpp in the source directories.
The builtin-function wildcard is used to force wildcard-expansion where it does not naturally occur.
OBJECTS = $(SOURCES:.cpp=.o)
That means OBJECTS is assigned the value of SOURCES, after substituting every .cpp at the end of an item with .o.
And %.o as a target means you are defining a rule for creating .os from something else.
References: GNU make manual
See here for a good basic makefile: https://stackoverflow.com/a/26579143
All of your questions are answerable via a reading of the GNU Make Manual.
The section on wildcards in the GNU Make Manual is worth reading for what I believe the author of that page was trying to explain about not using *.cpp as it may not do what you want. (The authors point about make ignoring modification times because of the bare glob is, however, entirely incorrect.)
That section continues into the section on the wildcard function. Which is just a make-expanded globbing function to control time of expansion (variable definition time instead of variable use time).
$(SOURCES:.cpp=.o) is a Substitution Reference.
%.o as a target is a Pattern Rule.
*.o is a glob.
$(wildcard *.cpp) (not wildcard *.cpp) was covered earlier.