Makefile Learn

一、什么是Makefile

makefile官方手册

二、编译过程&原理

hello.c -> 预处理(cpp) -> hello.i -> 编译器(ccl) -> hello.s -> 汇编器(as) -> hello.o -> 链接器(ld) -> hello可执行二进制目标程序

文件后缀 后缀含义 文件后缀 后缀含义
.a 静态库文件 .c C语言源程序文件
.h C语言头文件 .i 预处理文件
.o 目标文件可用于链接 .s 汇编文件
.so 动态(共享)库文件

1. 预处理指令

gcc -E [C源文件]            //不输出任何预处理文件
gcc -E [C源文件] -o [输出的预处理文件]  //输出指定名称的预处理文件

2. 生成汇编语言指令

gcc -S [C源文件]           //不输出任何汇编文件
gcc -S [C源文件] -o [输出的汇编文件]  //输出指定名称的汇编文件

3. 生成目标文件指令

gcc -c [C源文件]           //不输出任何目标文件
gcc -c [C源文件] -o [输出的目标文件]  //输出指定名称的目标文件

4. 直接由源码生成可执行文件

gcc [C源文件]           //直接输出 "a.out" 文件,使用./a.out可执行目标文件
gcc [C源文件] -o [输出的目标文件]  //指定输出的目标文件名称
//虽然没有写 -E -S -c 等命令,但不意味着上述过程没有执行

5. 生成静态库文件

  1. 编译成.o文件

    gcc -c [.c] -o [自定义文件名]

  2. 编译静态库

    ar -r [lib自定义库名称.a] [.o] [.o]

  3. 编译成可执行文件

    gcc [.c] [.a] -o [自定义输出文件名]
    gcc [.c] -o [自定义输出文件名] -l[库名] -L[库所在路径]

  4. 链接静态库和C源文件生成可执行文件

    gcc [C源文件] [静态库文件] -o [自定义输出文件名]

6. 生成动态库文件

  1. 编译输出.o文件

    gcc -c -fpic [.c] [.c] ...

  2. 编译动态库

    gcc -shared [.o] [.o] ... -o [lib自定义库名.so]

  3. 链接动态库和C源文件生成可执行文件

    gcc [.c] -o [自定义可执行文件] -l[库名] -L[库路径] -Wl , -rpath=[库路径]

三、Makefile基本格式、规则、伪目标

1. 基本格式

targets(目标文件) : prerequisties(依赖项)
[tab]command(shell命令)
targets可以是一个[lable]
命令前加一个 @ 可以不打印命令

2. Makefile规则

make会在当前目录下找到一个名为Makefile的文件。
找到后会查找第一个目标文件(targets),并把这个文件作为最终的目标文件。
如果target文件不存在,或者是target文件依赖的.o文件(prerequities)的文件修改时间要比target这个文件新,就会执行后面所定义的命令command来生成target这个文件。
如果target以来的.o文件(prerequisties)也存在,make会在当前文件中找到target为.o文件的依赖项,如果找到,再根据那个规则生成.o文件。

3. 伪目标

"伪目标"不是一个文件,只是一个标签。我们要显示地指明这个"目标"才能让其生效。
"伪目标"的取名不能和文件名重名,否则不会执行命令
为了避免和文件重名的这种情况。我们可以使用一个特殊标记, .PHONY来显示地指明一个目标是"伪目标",向make说明,不管是否有这个文件,这个目标就是"伪目标"。

.PHONY : clean

四、Makefile变量

1. 变量的定义

c := src/main.c   #只是一个字符串
obj := objs/main.o

2. 变量的引用

  • 可以使用()或者{}
$(obj) : ${cpp}       #目标文件$(obj) 依赖文件${cpp}

3. 预定义变量

  • $@ : 目标(target)的完整名称,所有的目标文件
  • $< : 第一个依赖文件(prerequisties)的名称
  • $^ : 所有的依赖文件(prerequisties),以空格分开,不包含重复的依赖文件

五、Makefile常用符号

1. =

  • 简单的赋值运算符
  • 将右边的值分配给左边
  • 如果在后面的语句中重新定义了该变量,则使用新的值

2. :=

  • 立即赋值运算符
  • 用于在定义变量时立即求值
  • 该值在定义后不再更改
  • 即使在后面的语句中重新定义了该变量,变量值也不会再改变

3. ?=

  • 默认赋值运算符
  • 如果该变量已经定义,则不进行任何操作
  • 如果该变量尚未定义,则求值并分配

4. +=

  • 将右边的值加空格累加到左边的变量中

5. \

  • 续行符,可以多行实际为一行

六、Makefile的常用函数

函数调用,很像变量的使用,也是 "$" 来标识的,其语法如下:

$(fn  arguments1 , argument2 , ...) or ${fn  arguments1 , argument2 , ...}
# fn:函数名
# arguments:函数参数,参数间以逗号,分隔 , 而函数名和参数之间以空格分隔

1. shell

$(shell <command> <arguments>)
  • 名称:shell命令函数 ——shell
  • 功能:调用shell的命令
  • 返回:函数返回shell命令的执行结果

例子

#shell 指令 , 在src文件夹下找到全部的.cpp文件
cpp_src := $(shell find src -name *.cpp)

2. subst

$(subst <from>,<to>,<text>)
  • 名称:字符串替换函数——subst
  • 功能:把字符串中的字符串替换成
  • 返回:函数返回被替换后的字符串
name1 := test1
name2 := test2

$(subst test,${name1},{name2})
#将name2中的test替换为test1,最后输出的结果为test12

3. patsubst

$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换函数——patsubst
  • 功能:通配符%,表示任意长度的字符串,从text中取出pattern,替换成replacement
  • 返回:函数返回被替换后的字符串

例子

name1 := test123

$(patsubst test,right,$(name1))
#将name1中的test替换为right并返回

4. foreach

$(foreach <var>,<list>,<text>)
  • 名称:循环函数——foreach
  • 参数:临时变量不会影响外部变量的值
  • 功能:把字串中的元素逐一取出来,执行包含的表达式
  • 返回: 所返回的每个字符串组成的整个字符串(以空格分隔)
name1 := myname

name2 := $(foreach item,$(name1),-L$(item))
#将name1中的字符串取出加上-L

5. dir

$(dir <names...>)
  • 名称:取目录函数——dir
  • 功能:从文件名序列中取出目录部分。目录部分是指最有一个反斜杠("/")之前的部分。如果没有反斜杠,那么返回"./"
  • 返回:返回文件名序列的目录部分

示例

$(dir src/foo.c hacks)
#返回值是"src/ ./"

6. notdir

$(notdir <names...>)
  • 功能:传入变量或列表,将其中的元素的路径去掉

7. filter

$(filter <names...>)
  • 功能:根据参数过滤掉某些文件

8. basename

$(basename <names...>)
  • 功能:去掉后缀

更多makefile函数参见:makefile函数

七、Makefile编译

1. Makefile编译步骤

1.1 预处理
1.2 编译成汇编语言
1.3 编译成.o文件
1.4 链接成可执行文件或库

2. 编译选项

编译选项

  • -m64:指定编译为64位应用程序
  • -std=:指定编译标准,例如:-std=c++11、-std=c++14
  • -g:包含调试信息
  • -w:不显示警告
  • -O:优化等级,通常使用:-O3
  • -I:加在头文件路径前
  • -fpic:产生的没有绝对地址,全部使用相对地址,代码可以被加载到内存的任意位置,且可以正确的执行。

链接选项

  • -l:加在库名前面
  • -L:加在库路径前面
  • -Wl,<选项>:将逗号分隔的<选项>传递给链接器
  • -rpath=:"运行"的时候,去找的目录。运行的时候,要找.so文件,会从这个选项里指定的地方去找
posted on 2025-11-27 16:41  77&&yr  阅读(0)  评论(0)    收藏  举报