Embedded system - Makefile basics

1. What is Makefile

  Makefile is a compilation rule file in the project project, which defines which files are compiled first, which files need to be compiled later, and the link order of files and other compilation rules. make is a command to execute Makefile under UNIX and Linux systems. The process from source file to executable file is called compilation, and the arrangement of compilation sequence is called build.
The relationship between make and Makefile
  make is a command tool used to explain the instructions in the Makefile. The compilation sequence and compilation rules of all files in the entire project are described in the Makefile file.
What is cmake
  You may have heard of several Make tools, such as GNU Make, QT's qmake, Microsoft's MSnmake, BSD Make (pmake), Makepp and so on. These Make tools follow different norms and standards, and the format of the Makefile they execute varies widely. This brings up a serious problem: if the software wants to be cross-platform, it must be guaranteed to be able to compile on different platforms. And if you use the above Make tool, you have to write a Makefile for each standard, which will be a crazy job.
  CMake is a tool designed to address the above problems: it first allows developers to write a platform-independent CMakeList.txt file to customize the entire compilation process, and then further generates the required localized Makefile and project files according to the target user's platform. Such as a Makefile for Unix or a Visual Studio project for Windows. So as to achieve "Write once, run everywhere". Obviously, CMake is a more advanced compilation and configuration tool than the above-mentioned make. Some well-known open source projects that use CMake as a project architecture system include VTK, ITK, KDE, OpenCV, OSG, etc.

  1. The process of using CMake to generate Makefile and compile it under the linux platform is as follows: Write the CMake configuration file CMakeLists.txt;
  2. Execute the command cmake PATH or ccmake PATH to generate Makefile. Among them, PATH is the directory where CMakeLists.txt is located. (The difference between ccmake and cmake is that the former provides an interactive interface);
  3. Compile with the make command

Two, Makefile basic syntax

Makefile基本语法:
目标:依赖
Tab 命令  #注意:一定是要“Tab键”,空格不行
  • Target: generally refers to the target to be compiled, it can also be an action
  • Dependency: The preconditions that the execution of the current target depends on, including other targets, a specific file or library (a target can have multiple dependencies)
  • Command: the specific command that needs to be executed to achieve the goal, it can be empty; there can also be multiple, if there are multiple, each command is on a separate line

make common options

  First, understand the basic usage of the make command

make [-f file] [options] [target]
执行make命令,默认在当前目录中寻找GUNmakefile、makefile文件,作为make命令的输入文件
 - -f 可指定上述文件名之外的文件作为输入文件
 - -v 显示版本号
 - -n 只输出命令,但并不执行,一般用于调试或测试
 - -s 只执行命令,但不显示具体命令,此处可在命令中用@符号抑制命令输出
 - -w 显示执行前、后的路径
 - -C [dir] 指定makefile的目录
 
 没有指定目标时,默认使用第一目标
 如果指定,则执行对应的命令
Common make commands
make 按默认配置編译
make -j8           8个进程同时编译,缩短总的时间
make world         编译所有能够编译的(postgresql 经常同时編译文档及附加模块(contrib)
make check         回归测试,用于安装完成后测试功能完整性,不能以 root 身份运行

make install       安装程序
make install-docs  安装文档(info、man手册)
make install-world 安装所有可安装的

make uninstall     删除安装的文件(生成的目录无法删除)

make clean         清除 make 生成的文件,但保留 configure 生成的文件
make distclean     将源码恢复为原始状态,即同时删除 make 与 configure 阶段生成的文件

make -C 指定源文件目录,仅安装程序的特定部分;
        如只安装客户端应用和接口:
		make -C src/bin install; 
		make -C src/include install; 
		make -C src/interfaces install; 
		make -C doc install

3. Reference and assignment of Makefile variables

3.1 Custom variables

  Several assignment and reference methods in Makefile: =, :=, ? =, +=, and assignment operations are generally for variables. Variables in the Makefile can be named arbitrarily. In principle, try to be familiar with the name.
(1) = Recursive variable assignment, the left side is the variable name, and the right side is the value of the variable. The advantage is that the variable can be assigned multiple times

xxx@XXX:~/test$ cat Makefile
var1=1
var2=$(var1)
var2=2
print:
	echo $(var2)

xxx@XXX:~$ make
echo 2
2

(2) := Expansion variable assignment. When defining a variable, the value on the right side of the variable is immediately replaced with the variable value. The previous variable cannot use the subsequent variable, that is, once the variable is assigned, even if it is assigned again later, it will not overwrite the previous one. defined variable value

xxx@XXX:~/test$ cat Makefile
var1=012
var2:=$(var1)
var1=345
print:
	echo $(var2)

xxx@XXX:~/test$ make
echo 012
012

(3) ?= Conditional assignment, used to judge whether the variable on the left has been assigned, if yes, the assignment will not be performed; if not, assign the variable:

xxx@XXX:~/test$ cat Makefile 
var1=012
var2=$(var1)
var2 ?=345
print:
	echo $(var2)
	
xxx@XXX:~/test$ make
echo 012
012

(4) += is generally used to add target file compilation operations, for example:

#新增目标前
objs=main.o add.o
main=$(objs)
#此时需要新增一个sub.o文件
objs=main.o add.o 
objs+=sub.o 
main=$(objs)

3.2 System variables (automatic variables)

  Common Automatic Variable Types

automatic variable name explain
$@ Indicates the target filename for the rule. If the target is a document file (in Linux, the .a file is generally a document file, also known as a static library file), then it represents the file name of the document; in the multi-target mode rule, it represents the trigger rule Executed file name
$% When the target file is a static library file, it represents a member name of the static library; if the target file is not a static library file, its value is empty
$< The filename of the first dependency of the rule. If an object file is rebuilt using the implicit rule, it represents the first dependent file added by the implicit rule.
$? A space-separated list of all dependent files newer than the target file. If the object file is a static library file, it represents a library file (.o file).
$^ Represents a list of all dependent files, separated by spaces. If the target is a static library file, it can only represent the names of all library members (.o files). A file that repeatedly appears in a target's dependencies variable " " only records its first reference. That is to say the variable "^" only records its first reference. That is to say the variable "" Onlyrecorditsfirstreference.Thatis to say,the variable "^"willremoveduplicate dependent files.
$+ Like "$^", but it preserves duplicate occurrences of dependent files. It is mainly used in the cross-reference occasion of the library when the program is linked.
$* In pattern rules and static pattern rules, stands for "stem". The "stem" is the part represented by the "%" in the target pattern (the "stem" also contains the directory part when a directory is present in the filename).

3.3 System constants (built-in variables)

CURDIR := /home/zht # 记录当前路径
SHELL = /bin/sh
MAKEFILE_LIST :=  Makefile
.DEFAULT_GOAL := all
MAKEFLAGS = p
HOSTARCH := x86_64
CC = cc 		# C语言编译器的名称
CPP = $(CC) -E  # C语言预处理器的名称 $(CC) -E
CXX = g++       # C++语言的编译器名称
RM = rm -f		# 删除文件程序的名称
CFLAGS			# C语言编译器的编译选项,无默认值
CPPFLAGS  		# C语言预处理器的编译选项,无默认值
CXXFLAGS		# C++语言编译器的编译选项,无默认值
......

Four, Makefile mode rules

pattern rules

  Pattern rules are similar to ordinary rules, except that in pattern rules, the target name needs to contain the pattern character "%" (one), and the target containing the pattern character "%" is used to match a file name, and "%" can match Any non-empty string. "%" can also be used in the dependent file of the rule, and the value of the pattern character "%" in the dependent file is determined by the "%" in the target.
  For example: For the pattern rule "%.o : %.c", it means that all .o files depend on the corresponding .c files. We can use pattern rules to define implicit rules. It should be noted that the matching and replacement of the pattern character "%" occurs after the expansion of all variable and function references in the rule. The expansion of variables and functions generally occurs when make reads the Makefile, while the matching of the "%" in the pattern rule And replacement happens when make is executed.

Makefile pseudo-target

  There is a kind of pseudo-target in the Makefile, we generate many files to compile files, we should also provide a "target" to clean them up for a complete recompile. (Use this target with "make clean"), call the corresponding rule, to clean up many compiled files (eg: *.o files) because we don't generate the "clean" file. "Pseudo-target" is not a file, but a label. Since "pseudo-target" is not a file, make cannot generate its dependencies and decide whether to execute it. We can only make this "goal" work by explicitly specifying it. Of course, the name of the "false target" cannot be the same as the file name, otherwise it will lose the meaning of "false target".
  Of course, in order to avoid this situation with the same name as the file, we can use a special tag ".PHONY" to explicitly indicate that a target is a "pseudo-target", explaining to make that no matter whether there is this file or not, this target is " false target".
.PHONY : clean
As long as there is this statement, no matter whether there is a "clean" file, to run the "clean" target, only "make clean" is like this. So the whole process can be written like this:
.PHONY: clean
clean:
rm *.o temp
  Pseudo-targets generally have no dependent files. However, we can also specify dependent files for pseudo-targets. False targets can also be used as "default targets", as long as they are placed first. For example, if your Makefile needs to generate several executable files in one go, but you just want to simply type make, and all target files are written in one Makefile, then you can use the "pseudo-target" feature:

  all : prog1 prog2 prog3
    .PHONY : all

    prog1 : prog1.o utils.o
            cc -o prog1 prog1.o utils.o

    prog2 : prog2.o
            cc -o prog2 prog2.o

    prog3 : prog3.o sort.o utils.o
            cc -o prog3 prog3.o sort.o utils.o 

Five, compile the dynamic link library

Dynamic link library: When compiling and linking, the code of the library file is not added to the executable file, and the library file is loaded by the link file when the program is executed;
Windows static library: xxx.lib Windows dynamic library: xxx.dll
linux static library : libxxx.a linux dynamic library: libxxx.so
Parameters:
-fPIC generate position-independent code
-shared share
-l (lowercase L) specify dynamic library
-I (uppercase i) specify header file directory, default current directory
-L manually specify Library file search directory, by default only links to shared directories

code preparation

├── dynamic_lib.c
└── dynamic_lib.h
dynamic_lib.c文件:

#include "dynamic_lib.h"
int add(int a, int b)
{
    
    
	int c;
	c = a + b;
	return c ;
}

dynamic_lib.h file:

#pragma onece
int add(int a, int b);
compile

Generate dynamic library files:

gcc -fPIC -shared dynamic_lib.c -o libdynamic_lib.so
Call the dynamic library file

Write a new code to call the dynamic library:

#include "dynamic_lib.h"
int main()
{
    
    
    int a = 0, b = 2, c;
    c = add(a, b);
    return 0;
}

Compile call: gcc lib_test.c -o lib_test -L ../dynamic_lib/ -ldynamic_lib -I ../dynamic_lib/
Note: When specifying a dynamic library, remove the head and tail

Sixth, compile the static link library

code preparation

├── static_lib.c
└── static_lib.h
static_lib.c代码:

#include "static_lib.h"
int add(int a, int b)
{
    
    
	int c;
	c = a + b;
	return c ;
}

static_lib.h code:

#pragma onece
int add(int a, int b);
compile

The compilation process is divided into two steps. First, the .o file is generated, and then it is archived as a .a static library file according to the .o file,
gcc -c static_lib.c
and then it is archived as a static library file, so that a static library libstatic_lib.a is generated.
ar crv libstatic_lib.a static_lib.o
Usage reference of the ar command: jump address

call static link library

Test code lib_test.c:

#include "static_lib.h"
int main()
{
    
    
    int a = 0, b = 2, c;
    c = add(a, b);
    return 0;
}

Compile:gcc lib_test.c -o lib_test -L ../static_lib/ -lstatic_lib -I ../static_lib/

Guess you like

Origin blog.csdn.net/weixin_43229184/article/details/127536496