I am currently trying to setup my first Makefile in Windows for simple c++ projects to be able to use it for every single project i create with only a few changes needing to be done. Here i get my sourcefiles from all folders:
sources := $(wildcard src/*.cpp) $(wildcard src/*/*.cpp) $(wildcard include/*.cpp) $(wildcard include/*/*.cpp)
which gives me following output:
src/main.cpp src/core/console.cpp src/core/filehandler.cpp src/core/framework.cpp src/core/globals.cpp src/core/textureeditor.cpp src/ui/buttonfuncs.cpp src/ui/interface.cpp src/ui/userinterfaces.cpp
Now i want to compile my files into object files like so:
$(OBJDIR)%.o: $(sources)
@echo compiling $< to $@
@$(CC) -c $< -o $@ $(FLAGS)
It outputs:
compiling src/main.cpp to obj/main.o
compiling src/main.cpp to obj/console.o
compiling src/main.cpp to obj/filehandler.o
compiling src/main.cpp to obj/framework.o
compiling src/main.cpp to obj/globals.o
compiling src/main.cpp to obj/textureeditor.o
compiling src/main.cpp to obj/buttonfuncs.o
compiling src/main.cpp to obj/interface.o
compiling src/main.cpp to obj/userinterfaces.o
which makes clear that it takes the right object files but doesnt take the right file from sources.
Is there a solution to iterate through sources or maybe delete the first element of sources every time this is run? Or maybe a better solution to this?
Side note: .o files always match up with .cpp files in the list as the .o names are being generated from the sources list.
I tried to get foldernames into srcs_dir:
srcs_dir = $(foreach wrd,$(sources),$(dir $(wrd)))
and running it like so:
$(OBJDIR)%.o: $(srcs_dir)%.cpp
@echo compiling $< to $@
@$(CC) -c $< -o $@ $(FLAGS)
with following output:
make: *** No rule to make target obj/main.o', needed by debug'. Stop.
Entire Makefile:
#defining project settings
project_name := Nimble
version := 0.0.1
#defining compiler settings
INCLUDE_PATHS := $(foreach wrd,$(wildcard src/*/),-I $(dir $(wrd))) \
$(foreach wrd,$(wildcard include/*/),-I $(dir $(wrd)))
LIBS := -lraylib -lopengl32 -lgdi32 -lwinmm -llua54
CC := g++
CPP := c++20
DEBUGFLAGS_O := -std=$(CPP) -Wno-missing-braces -w -g -Wall -m64 $(INCLUDE_PATHS)
RELEASEFLAGS_O := -std=$(CPP) -Wno-missing-braces -w -O3 -Wall -m64 $(INCLUDE_PATHS)
#defining paths
OUTPATH_DEBUG := bin/debug/$(project_name)
OUTPATH_RELEASE := bin/release/$(project_name)
OBJDIR := obj/
SRCDIR := src/
#getting headers
headers := $(wildcard src/*.h) $(wildcard src/*/*.h) $(wildcard include/*.h) $(wildcard include/*/*.h)
#getting sourcefiles
sources := $(wildcard src/*.cpp) $(wildcard src/*/*.cpp) $(wildcard include/*.cpp) $(wildcard include/*/*.cpp)
srcs_dir = $(foreach wrd,$(sources),$(dir $(wrd)))
#object_files := $(sources:.cpp=.o)
srcs = $(foreach wrd,$(sources),$(notdir $(wrd)))
object_files := $(foreach wrd,$(srcs:.cpp=.o),$(OBJDIR)$(wrd))
print:
@echo Object Files:
@echo $(object_files)
@echo Sources:
@echo $(sources)
@echo srcs:
@echo $(srcs)
@echo include paths:
@echo $(INCLUDE_PATHS)
@echo headers:
@echo $(headers)
@echo srcs_dir:
@echo $(srcs_dir)
debug: FLAGS := $(DEBUGFLAGS_O)
release: FLAGS := $(RELEASEFLAGS_O)
release: $(object_files)
@$(CC) obj/*.o -o $(OUTPATH_RELEASE) -s -L lib/ $(LIBS)
@xcopy graphics\\ bin\\release\\graphics\\ /s /Y
debug: $(object_files)
@$(CC) obj/*.o -o $(OUTPATH_DEBUG) -L lib/ $(LIBS)
@xcopy graphics\\ bin\\debug\\graphics\\ /s /Y
$(OBJDIR)%.o: $(sources)
@$(CC) -c $< -o $@ $(FLAGS)
clean:
@echo > Cleaning Object files
@cd obj/ && del *.o
@echo > Cleaning
As G.M. suggests you want to use
VPATHorvpath. In a pattern rule the stem (the part that matches the%) must match the identical string in the target and the prerequisite. There is no way to say "this, plus random other subdirectories".To use VPATH you would do something like this:
Most make functions, like
$(dir ...)and$(notdir ...), accept a list of words to operate on so you don't need to use a loop and pass them one at a time.Also, please don't add
@prefixes to your recipes until they fully work, else you're just throwing away important debug information.