Difference between revisions of "Make"
Line 43: | Line 43: | ||
Above example also contains a target which simply triggers a command execution: The clean target does not build anything but automates cleaning up target and intermediate build results. | Above example also contains a target which simply triggers a command execution: The clean target does not build anything but automates cleaning up target and intermediate build results. | ||
− | == | + | == Advanced usage == |
The simple example does miss out on many benefits of using make. | The simple example does miss out on many benefits of using make. | ||
Line 132: | Line 132: | ||
LIBS = | LIBS = | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | == Tips and Tricks == | ||
== Common Pitfalls == | == Common Pitfalls == |
Revision as of 09:20, 26 October 2017
Make is a build automation tool that automatically builds arbitrary targets (in most cases program executables or libraries) from a list of prerequisites (which can be files or other targets). Make is controlled by reading files called Makefiles which specify how to derive the target. While make is a standard UNIX tool today in most cases people refer to the GNU make implementation which provides a lot of extensions.
The main benefits of using a build automation tool are:
- Automation :-) of repetitive command execution
- Consistent build results preventing errors
- Easier configuration for different tool chains
- Formulate complex build settings with possibly various targets from the same source tree
- Automatic matching of prerequisites
- Speed up compilation by rebuilding only changed source files targets and parallel build support
Any serious software development effort sooner or later has to use a automated build tool. While make is the standard build tool on Linux systems there are various alternatives available, sometimes standalone and sometimes as a frontend to make.
Basic usage
A Makefile consists at its core of rules:
target … : prerequisites …
recipe
Each rule is made of the target, which is either a real build result as a executable or library or just a label without a build result. After colon is a list of prerequisites, make will search either for a file for every prerequisite or tries to match a rule to build it. Finally the recipe is a command or list of commands to generate the target. A recipe consists of any shell command but may also contain make variables or macros.
A simple Makefile might look like that:
myProg: main.o kbd.o command.o display.o
cc -o myProg main.o kbd.o command.o display.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
clean :
rm edit main.o kbd.o command.o display.o
By calling make without any arguments it will search for any file called makefile or Makefile and pick the first target in the file (indicated in this example by myProg:). The default target (the first one in the file) is matched first. Next make searches for the prerequisites, in this example a list of object files to link the executable. Next it either tries to find the object file or execute a rule to build it. In our case there is an explicit rule to build every object file. In case the object file was already build or is a primary source file make will check if the prerequisites are newer than the build result and automatically rebuild this file. This works in a recursive fashion: A target depends on prerequisites which themselves depend on prerequisites and so on. Make will automatically figure out which parts need to be executed in which order to get it right.
Above example also contains a target which simply triggers a command execution: The clean target does not build anything but automates cleaning up target and intermediate build results.
Advanced usage
The simple example does miss out on many benefits of using make. The following example is a generic makefile for a C/C++ software project making use of some advanced features of make providing the following benefits:
- Automatic dependency tracking
- Multiple tool chain specific build configurations
- Generic build rules
- Is based on naming conventions
- Uses dedicated build result directories allowing to build multiple tool chain variants in the same source tree
TAG = ICC
#CONFIGURE BUILD SYSTEM
TARGET = myProg-$(TAG)
BUILD_DIR = ./$(TAG)
SRC_DIR = ./src
MAKE_DIR = ./
Q ?= @
#DO NOT EDIT BELOW
include $(MAKE_DIR)/include_$(TAG).mk
INCLUDES += -I./src/includes
VPATH = $(SRC_DIR)
OBJ = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.c))
OBJ += $(patsubst $(SRC_DIR)/%.cc, $(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.cc))
OBJ += $(patsubst $(SRC_DIR)/%.cpp, $(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.cpp))
CPPFLAGS := $(CPPFLAGS) $(DEFINES) $(INCLUDES)
${TARGET}: $(BUILD_DIR) $(OBJ)
@echo "===> LINKING $(TARGET)"
$(Q)${LINKER} ${LFLAGS} -o $(TARGET) $(OBJ) $(LIBS)
$(BUILD_DIR)/%.o: %.c
@echo "===> COMPILE $@"
$(Q)$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
$(Q)$(CC) $(CPPFLAGS) -MT $(@:.d=.o) -MM $< > $(BUILD_DIR)/$*.d
$(BUILD_DIR)/%.o: %.cc
@echo "===> COMPILE $@"
$(Q)$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
$(Q)$(CXX) $(CPPFLAGS) -MT $(@:.d=.o) -MM $< > $(BUILD_DIR)/$*.d
$(BUILD_DIR)/%.o: %.cpp
@echo "===> COMPILE $@"
$(Q)$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
$(Q)$(CXX) $(CPPFLAGS) -MT $(@:.d=.o) -MM $< > $(BUILD_DIR)/$*.d
tags:
@echo "===> GENERATE TAGS"
$(Q)ctags -R
$(BUILD_DIR):
@mkdir $(BUILD_DIR)
ifeq ($(findstring $(MAKECMDGOALS),clean),)
-include $(OBJ:.o=.d)
endif
.PHONY: clean distclean
clean:
@echo "===> CLEAN"
@rm -rf $(BUILD_DIR)
@rm -f tags
distclean: clean
@echo "===> DIST CLEAN"
@rm -f $(TARGET)
@rm -f tags
An example tool chain configuration looks like the following (the file is named include_ICC.mk):
CC = icc
CXX = icpc
LINKER = $(CXX)
CFLAGS = -O3 -xAVX -std=c99
CXXFLAGS = -O3 -xAVX
LFLAGS = -vec-report0
DEFINES = -D_GNU_SOURCE
INCLUDES =
LIBS =
Tips and Tricks
Common Pitfalls
Debugging makefile errors appears difficult to beginners. It is important to understand that a makefile is not evaluated like a standard programming questions. Instead all instructions are read in and evaluated creating a state machine which is then executed.
Links and more Information
- GNU make info pages Probably the most complete and exhaustive documentation on make. Includes many examples.