I'm going back to C++ and, even though I'm not a beginner in programming and OOP, I'm quite new in the C++ world and I've not mastered the art of Makefiles.I'd like to know what you think about my third Makefile and the folder structure that I use. Don't hesitate to make any comments you think necessary.Here is the folder structure of the project:out/   ---   *.exe and *.ziptmp/   ---   *.olib/|   catch/   ---   Unit testing framework|   |   inc/|   |   |   catch.hppinc/   ---   Headers|   Factorial.hppsrc/   ---   Source files|   Factorial.cpp|   main.cpptst/   ---   Tests specific source files|   FactorialTest.cpp|   MathTest.cpp|   mainTest.cppMakefileIt is designed to support unit testing (here using Catch) with the tst folder.I didn't know how to use external libraries with C++, so I created a lib folder to put Catch in. I thought libraries could be downloaded from the configure.sh script in the future. Does it sound like a professional solution for larger projects?The Makefile :CXX           := g++LD            := g++EXEC          := factorialFLAGS         := -WallCXXFLAGS      := $(FLAGS)LDFLAGS       := $(FLAGS)INC           := -I incSRC           := $(wildcard src/*.cpp)OBJ           := $(SRC:src/%.cpp=tmp/%.o)EXEC_TEST     := testFLAGS_TEST    := $(FLAGS)CXXFLAGS_TEST := $(CXXFLAGS)LDFLAGS_TEST  := $(LDFLAGS)INC_TEST      := $(INC) -I lib/catch/incSRC_TEST      := $(wildcard tst/*.cpp)OBJ_TEST      := $(filter-out tmp/main.o, $(OBJ)) $(SRC_TEST:tst/%.cpp=tmp/%.o).SUFFIXES:# --------------------------------------------------------------.PHONY: allall: out/$(EXEC)out/$(EXEC): $(OBJ)    @$(LD) $(LDFLAGS) $^ -o $@ && echo [OK]  $@# --------------------------------------------------------------.PHONY: testtest: out/$(EXEC_TEST)out/$(EXEC_TEST): $(OBJ_TEST)    @$(LD) $(LDFLAGS_TEST) $^ -o $@ && echo [OK]  $@# --------------------------------------------------------------tmp/%.o: src/%.cpp    @$(CXX) $(CXXFLAGS) -c $< $(INC) -o $@ && echo [OK]  $@tmp/%.o: tst/%.cpp    @$(CXX) $(CXXFLAGS_TEST) -c $< $(INC_TEST) -o $@ && echo [OK]  $@# --------------------------------------------------------------.PHONY: clean, clearclean clear:    @rm -f out/* && echo [CL]  out/    @rm -f tmp/* && echo [CL]  tmp/.PHONY: archive, ziparchive zip:    @zip -x out/* tmp/* lib/* -q -r out/$(EXEC)-$(shell date '+%F').zip . && echo [OK]  out/$(EXEC)-$(shell date '+%F').zipThe Makefile is to be used via all and test targets, which build the final executable and the unit testing executable respectively.I tried to avoid duplicating tmp/%.o: src/%.cpp and tmp/%.o: tst/%.cpp recipes with test target-specific variables buy it didn't work because there are variables in targets' and dependencies' names.PS: It's also my third post on the Stack Exchange Network, so please feel free to make remarks about anything that is not StackExchange-compliant.
Generic Makefile handling unit testing and folder structure
c++;makefile
I'll assume throughout this answer that you're targeting GNU Make.  It's available on all targets that matter, and it simplifies your world no end if you can avoid pandering to the idiosyncrasies of the manifold implementations of Make supplied with operating systems. Object files depend on headersThis is the biggest thing that I think could be improved; I think it's probably a whole question in itself.  Your object files naturally depend on the corresponding C++ source files, but they also need rebuilding when their headers change.  Consider including generated makefiles that tell make how the object files depend on the headers; for a suitable recipe, see the Stack Overflow question Makefile, header dependencies, and for a longer exposition, read Auto-Dependency Generation by Paul D. Smith.  I normally use something like-include $(OBJS:.o=.d)%.d: %.c    $(CC) $(CFLAGS) -MM -MT $@ -MF $@ $<More warningsIt's good to see that you're using -Wall.  I also recommendCXXFLAGS += -Wextra -Wwrite-strings -Wno-parenthesesCXXFLAGS += -Wpedantic -Warray-bounds -Weffc++`The first line above always helps; the second does sometimes improve my code (you'll want to make use of -isystem to quieten your library includes, if you want to  make the latter bearable).Output directoryRules of makefiles advises thatLife is simplest if the targets are built in the current working directory.Use VPATH to locate the sources from the objects directory, not to locate the objects from the sources directory. That's certainly something to consider, though it might already be too painful to change.  I certainly prefer out-of-tree builds, so I can clean up with rm -rf build/ and be left with just my sources.Hiding commandsI appreciate that you don't want a wall of text, but when you're debugging (or on an automated build host where you want a complete record of the build), then you might want to override this, and actually see which commands were run.  You can make the behaviour adjustable, like this:QUIET := @ECHO := @echoifneq($(QUIET),@)ECHO := @trueendifUse it for your commands:clean clear:    $(ECHO) [CL]  out/    $(QUIET)$(RM) out/*    $(ECHO) [CL]  tmp/    $(QUIET)$(RM) tmp/*I changed the order to print first, like Make does, according to the Principle of Least Surprise.  It makes it more obvious what action was in progress when any error occurs.Now, when you need to see the actual commands, you can make QUIET= to override the value and get the full output again.  IIRC, the Linux kernel uses a similar system (toggled by a KConfig setting), as does Qt's qmake (toggled with CONFIG += silent in the .pro file).Re-use Make's pre-defined commandsInstead of writing%.o: %.cpp    $(CXX) $(CXXFLAGS) -c $< $(INC) -o $@%: $(OBJ)    $(LD) $(LDFLAGS_TEST) $^ -o $@you can make the rules more like the built-in versions (that you can see with make --print-database):%.o: %.cpp    $(COMPILE.cpp) $(OUTPUT_OPTION) $<%: $(OBJ)    $(LINK.cpp) $(OUTPUT_OPTION) $^ $(LOADLIBES) $(LDLIBS)Adapted to use QUIET and ECHO, that's%.o: %.cpp    $(ECHO) [OK]  $@    $(QUIET)$(COMPILE.cpp) $(OUTPUT_OPTION) $<%: $(OBJ)    $(ECHO) [OK]  $@    $(QUIET)$(LINK.cpp) $(OUTPUT_OPTION) $^ $(LOADLIBES) $(LDLIBS)You'll need to ensure that your include path is in CXXFLAGS, and you might need target-dependent flags:CXXFLAGS += $(INC)tmp/%: CXXFLAGS=$(CXXFLAGS_TEST)All makefiles should have....DELETE_ON_ERROR:Without this, a failed command could leave a part-written output that a subsequent make believes is up-to-date.FinallyHere's a tyni tyop:.PHONY: clean, clearLose that , - you've said that clean, is a phony target, not clean as you intended.