The goal of this article is to help you write simple Makefiles and understand common Makefiles. Make is an old build tool, which is incredible in today’s rapidly evolving technology landscape. Make plays a significant role in large software projects. I first encountered it while learning the Linux kernel, and the Android system is also built using make along with Python and other scripts. Therefore, mastering make knowledge is your first step into these systems. You must give make enough attention; don’t think that mastering C/C++ or Java, the main programming languages, will allow you to conquer the world. When you are lost in a sea of Makefiles and various .py, .sh scripts, lacking knowledge of build systems can be frustrating.
The advantage of make is that you can inform it about the relationships between different elements in your program. After that, make will determine which steps need to be recompiled based on these relationships and timestamps to produce the program you need. This is what we refer to as incremental compilation.
Typically, make operates based on a Makefile/makefile, which contains a set of rules for compiling the program. A rule can be divided into three parts: target, prerequisites, and commands.
target: prereq1 prereq2
commands
The file only contains one main.c
#include <stdio.h>
int main(int argc, char** argv)
{printf(“hello, makefile!\n”);}
First Makefile
#first makefile
hello-makefile: main.c
gcc -o hello-makefile main.c
Interpretation:
This Makefile consists of a single task (rule), where the target is an executable file called hello-makefile, the prerequisite is the main.c file, and the command is a gcc compilation command. The execution result is as follows:
$ make gcc -o hello-makefile main.c
Second Makefile
#final target hello-makefile: main.o
gcc -o hello-makefile main.o
#main.o
main.o: main.c
gcc -c main.c
Interpretation:
This breaks the above steps into two parts. To generate hello-makefile, it depends on a prerequisite, which is main.o, and then main.o is defined as a target with its own rule. Typically, a Makefile is composed of multiple such different rules.
The execution result is as follows:
$ make gcc -c main.c
gcc -o hello-makefile main.o
The basic syntax of a Makefile is structured from top to bottom, as shown in the above Makefile, starting with the top-level target (usually called all) and placing some work targets like clean at the bottom of the file.
Special Symbols
The hash symbol (#) is used for comments.
The backslash (\) acts as a line continuation character, consistent with common shell wildcards.
The asterisk (*) represents any number of any characters.
The question mark (?) represents a single arbitrary character.
.PHONY
Phony targets help avoid name conflicts. They appear in the following context:
.PHONY: clean
clean: rm -f *.o
Common .PHONY targets include:
all – executes all tasks to compile the application
install – installs the program from the compiled binaries
clean – clears generated binaries
distclean – clears all generated files
TAGS – builds a tags table for use by editors
check – performs any tests related to the program
Variables
$(variable)
${}
If the variable name is a single character, parentheses are not required.
VPATH
Tells make to look in specified directories if not found in the current directory. For example:
VPATH = src include
C++ Indicators
Sometimes you need to provide parameters to tell gcc to do something, such as adding the -I option to inform it to start implicit compilation rules:
CPPFLAGS = -I include
Include Keyword
Sometimes you need to call other makefiles; you can include them using the include keyword:
include /home/linc/workspace/lab/OpenCV-android-sdk-2.4.11/sdk/native/jni/OpenCV.mk
When compiling the Android framework source code, many scripts and additional compilation files need to rely on Makefile writing, such as inheriting third-party application compilation as system applications, referencing so libraries, and package names.
For example:LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Module name should match apk name to be installed. LOCAL_MODULE := LocalModuleName LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) include $(BUILD_PREBUILT)