I have this layout:
project/
Makefile
core/
a.cpp
a.hpp
utl/
b.cpp
b.hpp
obj/
And I would like to have all the .o files in the obj folder, so that I can then make a shared library from those object files. But since my .cpp files are in different directories I have no clue how to automate this. There are multiple directories not only these two. Any hint is appreciated.
My attempt fails because I assume that Make automatic rule for .o (which I wanted to use) wants a .cpp in the same directory where .o is supposed to be?
# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))
# remove the path
SRC_WITHOUT_PATH = $(notdir $(SRC))
# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(SRC_WITHOUT_PATH:%.cpp=./obj/%.o)
# error is no rule to make target obj/a.o
You can make a shred library from object files, even if they're in different directories. So that's not really a reason to put them elsewhere.
However, a better reason is just to keep the source directories tidy and make it simple to clean up (just remove the obj
directory).
Putting object files from source files in different directories into a single directory is problematic: if you have two source files with the same name they'll overwrite each other. One common way to work around this is to keep the directory structure for source files but put it below a new top-level directory; GNU make supports that easily:
# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))
# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(addprefix obj/,$(SRC:.cpp=.o))
obj/%.o : %.cpp
@mkdir -p $(@D)
$(COMPILE.cpp) -o $@ $<
If you really, really want to have all the object files in the same directory you'll have to get fancier, because make uses simple string matching for targets so you have to write a new rule for every relationship where the target and prerequisite names are different: basically that means a new rule for every separate source directory.
You can avoid this by using the VPATH feature of GNU make, like this:
# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))
# remove the path
SRC_WITHOUT_PATH = $(notdir $(SRC))
# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(SRC_WITHOUT_PATH:%.cpp=obj/%.o)
# Give all the source directories to make
VPATH = $(sort $(dir $(SRC))
obj/%.o : %.cpp
$(COMPILE.cpp) -o $@ $<