Makefile loop through sourcefiles

42 Views Asked by At

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 
1

There are 1 best solutions below

2
MadScientist On BEST ANSWER

As G.M. suggests you want to use VPATH or vpath. 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:

sources := $(wildcard src/*.cpp) $(wildcard src/*/*.cpp) $(wildcard include/*.cpp) $(wildcard include/*/*.cpp)
object_files := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(sources)))

VPATH := $(sort $(dir $(sources)))

  ...

$(OBJDIR)%.o: %.c
        $(CC) -c $< -o $@ $(FLAGS)

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.