The GNU Make (styled
make) is a program dedicated to the automation of executing shell commands. GNU Make is one specific program that falls under the Make family. Make remains popular among Unix-like and POSIX-like operating systems, including those derived from the Linux kernel, Mac OS X, and BSD.
GNU Make is especially notable for being attached to the GNU Project, which is attached to the popular GNU/Linux operating system. GNU Make also has compatible versions running on various flavors of Windows and Mac OS X. It is also a very stable version with historical significance that remains popular. It is for these reasons that GNU Make is often taught alongside C and C++.
To compile with make, create a Makefile in your project directory. Your Makefile could be as simple as:
# Set some variables to use in our command # First, we set the compiler to be g++ CXX=g++ # Then, we say that we want to compile with g++'s recommended warnings and some extra ones. CXXFLAGS=-Wall -Wextra -pedantic # This will be the output file EXE=app SRCS=main.cpp # When you call `make` at the command line, this "target" is called. # The $(EXE) at the right says that the `all` target depends on the `$(EXE)` target. # $(EXE) expands to be the content of the EXE variable # Note: Because this is the first target, it becomes the default target if `make` is called without target all: $(EXE) # This is equivalent to saying # app: $(SRCS) # $(SRCS) can be separated, which means that this target would depend on each file. # Note that this target has a "method body": the part indented by a tab (not four spaces). # When we build this target, make will execute the command, which is: # g++ -Wall -Wextra -pedantic -o app main.cpp # I.E. Compile main.cpp with warnings, and output to the file ./app $(EXE): $(SRCS) @$(CXX) $(CXXFLAGS) -o $@ $(SRCS) # This target should reverse the `all` target. If you call # make with an argument, like `make clean`, the corresponding target # gets called. clean: @rm -f $(EXE)
NOTE: Make absolutely sure that the indentations are with a tab, not with four spaces. Otherwise, you'll get an error of
Makefile:10: *** missing separator. Stop.
To run this from the command-line, do the following:
$ cd ~/Path/to/project $ make $ ls app main.cpp Makefile $ ./app Hello World! $ make clean $ ls main.cpp Makefile
When you start having more files, make becomes more useful. What if you edited a.cpp but not b.cpp? Recompiling b.cpp would take more time.
With the following directory structure:
. +-- src | +-- a.cpp | +-- a.hpp | +-- b.cpp | +-- b.hpp +-- Makefile
This would be a good Makefile:
CXX=g++ CXXFLAGS=-Wall -Wextra -pedantic EXE=app SRCS_GLOB=src/*.cpp SRCS=$(wildcard $(SRCS_GLOB)) OBJS=$(SRCS:.cpp=.o) all: $(EXE) $(EXE): $(OBJS) @$(CXX) -o $@ $(OBJS) depend: .depend .depend: $(SRCS) @-rm -f ./.depend @$(CXX) $(CXXFLAGS) -MM $^>>./.depend clean: -rm -f $(EXE) -rm $(OBJS) -rm *~ -rm .depend include .depend
Again watch the tabs. This new Makefile ensures that you only recompile changed files, minimizing compile time.