[make] 第一章 make 介绍

1. 概述

静态库:多个.o文件的集合,Linux中静态库文件的后缀为".a",静态库中的各个成员(.o文件)没有特殊的存在格式,仅仅是一个.o文件的集合,可以使用“ar”工具维护和管理静态库。

共享库:也是多个.o文件的集合,但是这些.o文件由编译器按照一种特殊的方式生成(Linux中,共享库文件格式通常为“ELF”格式,共享库已经具备了可执行条件)。模块中各个成员的地址(变量引用和函数引用)都是相对地址,使用此共享库的程序在运行时,共享库被动态加载到内存并和主程序在内存中进行连接,多个可执行程序可共享库文件的代码段(多个程序可以共享的使用库中的某一个模块,共享代码但不共享数据)。此外,共享库的成员对象可被执行(由libdl.so提供支持)。

2. GNU make介绍

make在执行时,需要一个命名为“Makefile”的文件,这个文件告诉make以何种方式编译源代码和链接程序。

make通过比较对应文件(规则的目标和依赖)的最后修改时间,来决定文件是否需要更新,对需要更新的文件,make就会执行数据库中所记录的相应命令(在make读取Makefile以后会建立一个编译过程的描述数据库,此数据库中记录了所有各个文件之间的相互关系,以及他们的关系描述)来重建它,对于不需要重建的文件make什么也不做。此外可以通过make的命令选项来指定需要重新编译的文件。

2.1 Makefile文件简介

在执行make之前,需要一个命名为“Makefile”的特殊文件来告诉make需要做什么(完成什么任务),该怎么做,通常,make工具主要被用来进行工程编译和程序链接。

当使用make工具进行编译时,工程中以下几种文件在执行make时将会被编译(重新编译)

  • 所有的源文件没有被编译过,则对各个C源文件进行编译并进行链接,生成最后的可执行文件
  • 每一个在上次执行make之后修改过的C源代码文件在本次执行make时将会被重新编译
  • 头文件在上一次执行make之后被修改,则所有包含此头文件的C源文件在本次执行make时将会被重新编译

2.2 Makefile 规则介绍

# 注释
规则的目标:规则的依赖
[Tab]规则的命令行

# 书写时,可以就爱你各一个较长行使用反斜线(\)来分解为多行,但是反斜线后不能有空格
  • 规则的目标:最后需要生成的文件名或者为了实现这个目的而必须的中间过程文件名
    • 可以是.o文件,也可以是最后的可执行程序的文件名。还可以是一个make执行的动作的名称,如“clean”,这样的目标为“伪目标”
    • 一个目标可以没有依赖而只有动作(“伪目标”)
  • 规则的依赖:生成规则目标所需要的文件名列表。
    • 通常一个目标依赖于一个或者多个文件
  • 规则的命令行:是规则所要执行的动作(任意的shell命令或者是可以在shell下执行的程序),它限定了make执行这条规则时所需要的动作
    • 一个规则可以有多个命令行,每一条命令占一行
    • 每个命令行必须以[Tab]字符开始,[Tab]字符告诉make次行是一个命令行,但并不是所有的以[Tab]出现的行都是命令行,但make程序会把出现在第一条规则之后的所有以[Tab]字符开始的行都作为命令行来处理
    • 命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述

2.3 make 如何工作

默认情况下,make执行的是Makefile中第一个规则,此规则的第一个目标称之为“最终目的”或者“终极目标

  1. 当在shell提示符下输入“make”时,make读取当前目录下的Makefile文件,并将Makefile文件中的第一个目标最为其执行的“终极目标,开始处理第一个规则”
  2. make在执行“终极目标”所在规则的命令行之前,首先需要处理“终极目标”的所有依赖文件(多个.o文件)的更新规则
    • 目标.o文件不存在,使用其描述规则创建它
    • 目标.o文件存在,目标.o文件所依赖的.c源文件、.h文件中任何一个比目标.o文件“更新(更改时间的比较)”,则根据规则重新编译生成它
    • 目标.o文件存在,目标.o文件比它的任何一个依赖文件(.c文件、.h文件)“更新”,则什么也不做
  3. 完成对“终极目标”的依赖文件的处理后,make程序将处理"终极目标"所在的规则
    • 终极目标文件不存在,则执行规则以创建终极目标文件
    • 终极目标文件存在,其依赖文件中有一个或者更多个文件比它“更新”,则根据规则重新链接生成终极目标文件
    • 终极目标文件存在,它比任何一个它的依赖文件“更新”,则什么也不做

在Makefile中一个规则的目标如果不是“终极目标”所依赖的(或者“终极目标”的依赖文件所依赖的),那么这个规则就不会被执行

更新或创建终极目标的过程中,如果任何一个规则执行出现错误,make就立即报错并退出

2.4 指定变量

# 第一种情况
edit : main.o yilai1.o yilai2.o yilai3.o
	cc -o edit main.o yilai1.o yilai2.o yilai3.o
# 上述参数列表出现了两次,需要增加或删除时,需要更改两处,维护困难

# 第二种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
# 通过使用变量来代替参数列表

2.5 自动推导规则

在使用make编译.c源文件时,编译.c源文件规则的命令可以不用明确给出,因为make本身存在一个默认的规则,能够自动完成对.c文件的编译并生成对应的.o文件。在Makefile中我们只需要给出需要重建的目标文件名(一个.o文件),make会自动为这个.o文件寻找合适的依赖文件(对应的.c文件,文件名除后缀外,其余都相同的两个文件),而且使用正确的命令来重建这个目标文件

对于一个目标文件是fileName.o,依赖文件是fileName.c的规则,完全可以忽略其规则的命令行,由make自身决定使用默认命令,此默认规则称为make的隐含规则

# 第一种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : main.c def1.h
	cc -c main.c
yilai1.o : yilai1.c def2.h
	cc -c yilai1.c
yilai2.o : yilai2.c def2.h
	cc -c yilai2.c
yilai3.o : yilai3.c def3.h def4.h
	cc -c yilai3.c

# 第二种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o : def2.h
yilai2.o : def2.h
yilai3.o : def3.h def4.h

2.6 另类风格的Makefile

根据依赖而不是目标对规则进行分组(不推荐,容易造成混乱)

建议:单目标、多依赖

# 第一种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o : def2.h
yilai2.o : def2.h
yilai3.o : def3.h def4.h

# 第二种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o yilai2.o : def2.h
yilai3.o : def3.h def4.h

2.7 清除工作目录过程文件

# 第一种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o : def2.h
yilai2.o : def2.h
yilai3.o : def3.h def4.h
# 会在当前目录下生成如yilai1.o等的中间文件

# 第二种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o : def2.h
yilai2.o : def2.h
yilai3.o : def3.h def4.h

clean :
	rm $(objects)
# 通过clean清除中间文件,只保留终极目标文件(如果目录中有名为clean文件时,则无法执行)

# 第三种情况
objects = main.o yilai1.o yilai2.o yilai3.o
edit : $(objects)
	cc - o edit $(objects)
main.o : def1.h
yilai1.o : def2.h
yilai2.o : def2.h
yilai3.o : def3.h def4.h

.PHONY : clean
	-rm $(objects)
	# 通过“.PHONY”特殊目标将”clean“声明为伪目标,避免出现同名文件时,所在规则无法执行 \
	# 此外在命令前使用”-“,意思是忽略执行该命令是的执行错误
原文地址:https://www.cnblogs.com/aaronbin/p/15552943.html