1
votes

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?

2
One question per question pleaseLightness Races in Orbit
It is one question just split in 2 parts. I want to make my makefile folder structure independend and i cant get it to work. I honestly dont see how posting everything twice and ask for the include flag in a seperate thread makes any sense.Eric
They're completely different questions and this is a Q&A not a forum. CheersLightness Races in Orbit
Be aware: make's wildcard function uses traditional shell globbing, it does not understand advanced zsh-style globbing. So for example, ** and * mean exactly the same thing to make and match only files in a single directory. make globbing doesn't support ** to mean "all matches in subdirectories recursively".MadScientist

2 Answers

0
votes

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.

1
votes

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.