make deletes object files after using them - makefile

when I use a completely generic rule to create executable files without specifying the rule name (I put it below) GNU Make 4.2.1 (running on wsl) creates relocatable files under the folders I specify, and after creating the executable, it removes them.
I also put whole makefile code at the end.
Here is the generic code that I mentioned above:
# executable rule 1
%: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)%.o
#echo executable rule 1
$(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
when I call this rule, from the shell, following lines are executed:
creating ./mains/obj/ ./sources/obj/
gcc -c -o sources/obj/testUtil.o sources/testUtil.c -I./headers/
gcc -c -o sources/obj/timeUtil.o sources/timeUtil.c -I./headers/
gcc -c -o sources/obj/quickSortVersions.o sources/quickSortVersions.c -I./headers/
gcc -c -o sources/obj/quickSortSubFns.o sources/quickSortSubFns.c -I./headers/
gcc -c -o sources/obj/experimentSetUp.o sources/experimentSetUp.c -I./headers/
gcc -c -o sources/obj/stringUtil.o sources/stringUtil.c -I./headers/
gcc -c -o mains/obj/main.o mains/main.c -I./headers/ -lm
executable rule 1
gcc -o main sources/obj/testUtil.o sources/obj/timeUtil.o sources/obj/quickSortVersions.o sources/obj/quickSortSubFns.o sources/obj/experimentSetUp.o sources/obj/stringUtil.o mains/obj/main.o -I./headers/ -lm
rm sources/obj/testUtil.o sources/obj/stringUtil.o sources/obj/quickSortSubFns.o sources/obj/quickSortVersions.o mains/obj/main.o sources/obj/timeUtil.o sources/obj/experimentSetUp.o
I didn't understand why it puts rm command at the end.
instead when I do this, It worked as I expected:
(here main, testMain, and rangen are some executable file names that I wanted for shell to advice me when I type make and hit tab)
# executable rule 2
main testMain rangen: %: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)%.o
#echo executable rule 2
$(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
and also when I add those rules below, even if I still use executable rule 1 and and even those below rules are not refered anywhere and not used anywhere, It works as I expected:
# I even dont use those rules! They are refered nowhere
objects: $(OBJECTS)
#echo not refered rule
mainObjects: $(MAIN_OBJECTS)
# #echo not refered rule
Here is the whole makefile:
# https://www.gnu.org/software/make/manual/make.html
# https://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/
# make file is designed for the following file tree:
# ./
# | headers/ # a folder containing some headers designed by me.
# | mains/ # a folder containing .c files with int main(int,char**){} definitions.
# | sources/ # a folder containing .c files that are commonly used by main files.
# | makefile # this file.
# this makefile has rules
# to create the folders
# ./sources/obj/
# ./mains/obj/
# to compile relocatables
# from ./sources/*.c to ./sources/obj/*.o
# from ./mains/*.c to ./mains/obj/*.o
# and link relocatables in ./sources/obj/*.o with each one of ./mains/obj/*.o
# into an executable with same name with the associated main file.
# common source folder
SRC_DIR=./sources/
# header folder
HDR_DIR=./headers/
# common relocatable folder
OBJ_DIR=$(SRC_DIR)obj/
# folder with main files
MAIN_SRC_DIR=./mains/
# folder with main files' relocatables
MAIN_OBJ_DIR=$(MAIN_SRC_DIR)obj/
# ./mains/obj/ ./sources/obj/
ADDITIONAL_FOLDERS=$(MAIN_OBJ_DIR) $(OBJ_DIR)
# paths to c files with int main(int,char**){} definitions.
MAIN_SOURCES=$(wildcard $(MAIN_SRC_DIR)*.c)
# paths to common c files
SOURCES=$(wildcard $(SRC_DIR)*.c)
# paths to headers
HEADERS=$(wildcard $(HDR_DIR)*.h)
# paths to common relocatable files
OBJECTS=$(patsubst $(SRC_DIR)%.c, $(OBJ_DIR)%.o, $(SOURCES))
# paths to relocatables with int main(int,char**){} definitions.
MAIN_OBJECTS=$(patsubst $(MAIN_SRC_DIR)%.c, $(MAIN_OBJ_DIR)%.o, $(MAIN_SOURCES))
# prerequisites to create executable files.
PREQS_for_EXECUTABLES=folders $(OBJECTS)
IDIR =$(HDR_DIR)
CC=gcc
CFLAGS=$(patsubst %,-I%,$(IDIR))
DEPS=$(HEADERS)
LIBS=-lm
# create necessary folders
folders:
#(mkdir $(ADDITIONAL_FOLDERS) 1>/dev/null 2>/dev/null && echo creating $(ADDITIONAL_FOLDERS) \
|| echo folders $(ADDITIONAL_FOLDERS) already created)
# compiles relocatable requested as ./soruces/obj/*.o
$(OBJ_DIR)%.o: $(SRC_DIR)%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
# compiles relocatable requested as ./mains/obj/*.o
$(MAIN_OBJ_DIR)%.o: $(MAIN_SRC_DIR)%.c
$(CC) -c -o $# $< $(CFLAGS) $(LIBS)
EXECUTABLES=$(patsubst $(MAIN_SRC_DIR)%.c, %, $(MAIN_SOURCES))
.PHONY: clean
clean:
rm -rf $(EXECUTABLES) $(ADDITIONAL_FOLDERS)
# link one of main files from $(MAIN_OBJ_DIR) with ./sources/obj/*.o files
# into an executable with same name with the main file
# executable rule 1
%: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)%.o
#echo executable rule 1
$(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
# # # main, testMain, and rangen were my main file names.
# # I added them here because I want for shell to advice them when I type make and hit tab.
# executable rule 2
main testMain rangen: %: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)%.o
#echo executable rule 2
$(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
# executable rule 3
# test: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)test.o
# #echo executable rule 3
# $(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
# main: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)main.o
# #echo executable rule 3
# $(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
# rangen: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)rangen.o
# #echo executable rule 3
# $(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)
# it behaves different when I use executable rule 2 or 3 instead of executable rule 1
# or when I add those lines to file
# # I even dont use those rules! They are refered nowhere
# objects: $(OBJECTS)
# #echo not refered rule
# mainObjects: $(MAIN_OBJECTS)
# # #echo not refered rule
# in short, if I use executable rule 1, it removes relocatable files after using them.
# if I use executable rule 2 or 3, or if I turn above rules (objects, mainObjects) on,
# even if they are not refered anywhere, it works as I expected.
I see that this is a similar post, But I still don't understand why the following rule doesn't interprete the object files as intermediate.
main testMain rangen: %: $(PREQS_for_EXECUTABLES) $(MAIN_OBJ_DIR)%.o
#echo executable rule 2
$(CC) -o $# $(wordlist 2, $(words $^), $^) $(CFLAGS) $(LIBS)

Related

Makefile with different source types doesn't notice make.depend

I want my Makefile to accept different source file types. It does, but it does not recompile when I alter an include file. Here's the Makefile:
C_SOURCES := $(wildcard *.c)
CPP_SOURCES := $(wildcard *.cpp)
CC_SOURCES := $(wildcard *.cc)
ALL_SOURCES := $(notdir $(C_SOURCES) $(CPP_SOURCES) $(CC_SOURCES))
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
ALL_OBJECTS := $(notdir $(C_OBJECTS) $(CPP_OBJECTS) $(CC_OBJECTS))
#############################################################
all: a.out
a.out: $(ALL_OBJECTS)
g++ -o $# -g $^
%.o: %.cpp
g++ -c $# -g $^
%.o: %.cc
g++ -c $# -g $^
%.o: %.c
g++ -c $# -g $^
clean:
rm -f a.out
rm -f *.o
make.depend: $(ALL_SOURCES)
g++ -MM $^ > $#
-include make.depend
The lines starting with *.o: are a recent addition -- I wondered if it might help. No effect.
make.depend is doing its job: I checked it out, and its dependencies are correct. (For my MCVE I have one source file main.cpp which includes date.h.)
main.o: main.cpp date.h
The output of $(info $(ALL_OBJECTS)) is main.o.
So: how can I get it to recognize changes to includes?
It would be helpful, when asking questions, to show an example of running the commands and what is printed. Given the makefile you provide I'd be surprised of make actually ran any commands at all, other than generating the depend file.
That's because this:
C_OBJECTS := ${C_SOURCES: .c =.o}
is invalid syntax. Or more precisely, it doesn't do what you want to do. It replaces the literal string _____.c__ (where the _ are whitespace... SO won't let me just use spaces) at the end of each word in C_SOURCES with .o. Of course you don't have any of those, so basically your ALL_OBJECTS variable contains just your source files (since no changes are made by the substitution).
You can use:
$(info $(ALL_OBJECTS))
to see what happens here.
This needs to be written:
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
Whitespace in makefiles is very tricky. You definitely have to be careful where you put it and you can't add it anywhere you like.
Also I have no idea why you're using notdir since all your files are in the current directory.
And technically it's incorrect to compile .c files with the g++ compiler front-end.
ETA also your pattern rules are incorrect: you're missing the -o option to the compiler; they should all be the equivalent of:
%.o: %.c
g++ -c -o $# -g $^
Better is to use the standard make variables, then you can customize the behavior without rewriting all the rules:
CFLAGS = -g
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
Update Just use the comprehensively enginerred automatic dependency file generation #MadScientist describes at http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/. This works with both GCC and clang (due to clang's explicit goal to be commandline compatible to GCC).
For completeness' sake, my original answer:
The generated dependency rules must depend on the sources determined by the dependeny rule generating rule. This requires the -MT parameter to gcc.
I have included this as an example in a slightly cleaned up version of your GNUmakefile:
#############################################################
ALL_CFLAGS = -g
ALL_CXXFLAGS = -g
#############################################################
.PHONY: all
all: all-local
#############################################################
bin_PROGRAMS += test-cxx
test_cxx_OBJECTS += main.o
test_cxx_OBJECTS += main-c.o
test-cxx: $(test_cxx_OBJECTS)
$(LINK.cc) $(ALL_CXXFLAGS) -o $# $^
ALL_OBJECTS += $(test_cxx_OBJECTS)
#############################################################
%.o: %.cpp
$(COMPILE.cpp) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.cc
$(COMPILE.cc) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.c
$(COMPILE.c) $(ALL_CFLAGS) -o $# -c $<
#############################################################
%.dep: %.cpp
$(COMPILE.cpp) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.cc
$(COMPILE.cc) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.c
$(COMPILE.c) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
ALL_DEPS = $(ALL_OBJECTS:.o=.dep)
-include $(ALL_DEPS)
#############################################################
.PHONY: all-local
all-local: $(bin_PROGRAMS)
.PHONY: clean
clean:
rm -f $(bin_PROGRAMS)
rm -f *.dep
rm -f *.o
#############################################################
The *.dep generating rules will recursively examine all included source files, and list them all in the generated *.dep file.
Using a separate *.dep file for each object file means that if you change only one source file, only the *.dep files needing regeneration will actually be regenerated.
The *.dep generating rule creates a *.dep.tmp file first, and only moves that to *.dep if generating the *.dep.tmp file has been successful. So if for some reason generating the *.dep.tmp file fails (e.g. you might be including a non-existing header file), you will not have a newly generated (and thus considered up to date) empty *.dep file being included by make.

Makefile does not find rules despire of available files

Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o

gcc output directory for submakes

I`m having a makefile with Sub makes. I want to place the Output of the submakes in one Directory. Can anyone explain me how to do this right?
-root |
|-stub
|-test
|-source
|-out
|-makefile
all of my submakes shall place their *.o files in out. I`m getting Errors there is no File or Directory ./out/**.o if i add ../out to the Objectfile.
here is my submakefile
# makefile to generate UNIT-tests
# sub makefile for location stub
# define any directories containing header files other than /usr/include
# TODO
# define any libraries to link into executable:
# if I want to link in libraries (libx.so or libx.a) I use the -llibname
# option, something like (this will link in libmylib.so and libm.so:
LIBS =
# TODO define the C source files
SRCS = $(STUBS)
# define the C object files
#
# This uses Suffix Replacement within a macro:
# $(name:string1=string2)
# For each word in 'name' replace 'string1' with 'string2'
ODIR=../out
OBJ = $(SRCS:%.c=%.o)
# define the C compiler to use
CC = gcc
# define any compile-time flags
#compile without link
CFLAGS = -O0 -Wall -c -g -fmessage-length=0 -fprofile-arcs -ftest-coverage
#TODO Linkerflags
LFLAGS = --coverage
# define the executable file,
all: $(TARGET) $(OBJ)
$(CC) $(OBJ) $(CFLAGS) -o $(TARGET) $(LFLAGS) $(OBJ)
#echo +++ build of stub finished +++
clean:
$(RM) *.o *~ $(MAIN)
# DO NOT DELETE THIS LINE -- make depend needs it

Makefile adds itself as target

I have a Makefile for a C++ program that uses automatic dependency generation. The %.d recipe is taken from the GNU Make manual.
The problem is that somehow "Makefile" is being added as a target and then an implicit rule is causing it to assume it's an executable and using my src/%.cpp rule to try to compile src/Makefile.cpp. When looking at the debug info, this always happens right after the include is executed.
No need to remake target `build/Sprite.d'.
Considering target file `Makefile'.
Looking for an implicit rule for `Makefile'.
...
Trying pattern rule with stem `Makefile'.
Trying implicit prerequisite `Makefile.o'.
Looking for a rule with intermediate file `Makefile.o'.
I know include causes the given Makefiles to be rebuilt if necessary. Does it also try to rebuild the current Makefile? If so how do I stop it, and if not, then why is "Makefile" being added as a target?
Also, the include is executed, causing the .d files to be remade even if I specify a target on the command line, such as make clean. Is there any way to stop that from happening?
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src/
INCLUDE_DIR = include/
BUILD_DIR = build/
SOURCES = $(wildcard $(SOURCE_DIR)*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
include $(DEPENDENCIES)
%.o: $(BUILD_DIR)stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
$(BUILD_DIR)%.d: $(SOURCE_DIR)%.cpp $(BUILD_DIR)stamp
# echo Generate dependencies for $ $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' $#; \
rm -f $#.$$$$
$(BUILD_DIR)stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)
Make will always try to remake the Makefile before executing the Makefile. To do so, make will look for rules which can be used to recreate the Makefile. Make will look for quite a few implicit rules and other obscure methods to (re)create the Makefile.
In your case, make somehow decided that the pattern rule %.o: $(BUILD_DIR)/stamp should be used to recreate the Makefile, which failed.
To prevent make from remaking the Makefile you can write a rule with an empty recipe:
Makefile: ;
Read the chapter Remaking Makefiles in the make manual for more explanation.
About the included Makefiles: Included Makefiles will always be included, regardless of the target. If the included makefiles are missing (or older than their prerequisites) then they will first be (re)created. That means a make clean will first generate the .d Makefiles, only to delete them again.
You can prevent the including for specific goals by wraping the include directive in a conditional:
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
Here is your entire Makefile with some fixes. I marked the places where I changed something.
# Makefile
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1/,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
# -------> only include if goal is not clean <---------
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
# ---------> fixed this target <--------------
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
# ---------> and this target <---------------
$(BUILD_DIR)/%.d: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
# echo Generate dependencies for $#;
#set -e; rm -f $#; \
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
$(BUILD_DIR)/stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)

makefile aliases

Please explain $# $^ $ in the makefile below
LIBS = -lkernel32 -luser32 -lgdi32 -lopengl32
CFLAGS = -Wall
# (This should be the actual list of C files)
SRC=$(wildcard '*.c')
test: $(SRC)
gcc -o $# $^ $(CFLAGS) $(LIBS)
This is what these two symbols mean:
$# is the target i.e. test
$^ is the list of pre-requisites for the rule (which in this case is the expanded wild card list as specified in SRC=$(wildcard '*.c'))
All such variables are explained in the Automatic variables page of the GNU make manual.
SRC=$(wildcard '*.c')
This just all your source file name ending with .c ie file1.c, file2.c file3.c etc.
in
test: $(SRC)
gcc -o $# $^ $(CFLAGS) $(LIBS)
$ is a way to define variables in Makefile
$# is your target, in your case it is "test".
$^ is the list of all the prerequisites of the rule, including the names of the directories in which they were found
$< is the list of all dependencies
ref: https://www.gnu.org/software/make/manual/make.html#Automatic-Variables

Resources