一、相关概念
Makefile是什么?
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。
Make与Makefile的关系
make是一个命令工具,用来解释Makefile中的指令。
在Makefile文件中描述了整个工程所有文件的编译顺序、编译规则
Makefile命名规则:Makefile或makefile
CMake是什么?
CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。能够输出各种各样的makefile或者project文件,能测试编译器所支持的C特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C 的 projects/workspaces),然后再依一般的建构方式使用。
cmake与CMakeLists的关系
cmake是一个命令工具,可以用来生成makefile。需要根据CMakeLists.txt中的内容生成,CMakeList.txt就是写给cmake的规则。
总结:
make是一个命令工具,Makefile是一个文件,make执行的时候,去读取Makefile文件中的规则,需要自己实现makefile
cmake是一个命令工具,CMakeList.txt是一个文件,cmke执行的时候,去读取CMakeList.txt文件中的规则,需要自己实现CMakeList.txt
二、Makefile 基本语法
目标:依赖
命令
例:
a:
echo "hello world"
ls ./
clean:
echo "hello clean"
目标:一般指要编译的目标,也可以是一个动作
依赖:指执行当前目标所要依赖的条件,如:其他目标、某个文件、某个库等。一个目标可以存在多个依赖。
命令:该目标下需要执行的具体命令,可以没有,也可以存在多条;当存在多条时,每条命令一行。
make常用选项
make[-f file][options][target]
Make默认在当前目录中寻找GNUmakefile、makefile、Makefile的文件作为make的输入文件。
-f 可以指定除上述文件名之外的文件作为输入文件
-v 显示版本号
-n 只输出命令,但不执行,一般用来测试
-s 只执行命令,但不显示具体命令,此处可在命令中使用@符抑制命令输出
-w 显示执行前执行后的路径
-C dir 指定makefile所在的目录
没有指定目标时,默认使用第一个目标;如果指定,则执行对应的命令
三、Makefile中的变量
系统变量
$* 不包括拓展名的目标文件名称
$+ 所有的依赖文件,以空格分隔
$< 表示规则中的第一个条件
$? 所有时间戳比目标文件晚的依赖文件,以空格分离
$@ 目标文件的完整名称
$^ 所有不重复的依赖文件,以空格分隔
$% 如果目标是归档成员,则该变了表示目标的归档成员名称
系统常量(可用 make -p查看)
AS 汇编程序的名称 默认为as
CC C编译器名称 默认为cc
CPP C预编译器名称 默认为cc -E
CXX C++编译器名称 默认为g++
RM 文件删除程序别明 默认 rm -f
自动变量
@ 就指代test。
a.txt b.txt:
touch $@
#等同于下面的写法
a.txt:
touch a.txt
b.txt:
touch b.txt
< 就指代p1。
a.txt: b.txt c.txt
cp $< $@
#等同于下面的写法
a.txt: b.txt c.txt
cp b.txt a.txt
?就指代p2。
^ 就指代 p1 p2 。
* 就表示 f1。
(@F) 分别指向 @是 src/input.c,那么(@F) 的值为 input.c。
(<F) 分别指向 $< 的目录名和文件名。
自定义变量
定义:变量名=变量值
使用:{变量名}
四、Makefile中的函数
伪目标:.PHONY:clean
声明目标为伪目标之后,makefile将不会判断目标是否存在或该目标是否需要更新
%.o:%.c
.o 依赖于对应的.c
wildcard
$(wildcard ./*.c) 获取当前目录下所有的.c文件
patsubst
$(patsubst %.c, %.o, ./*.c) 将对应的c文件名替换成.o文件名
替换后缀名
替换后缀名的函数写法是:变量名 + 冒号 + 后缀名替换规则
min: $(OUTPUT:.js=.min.js)
执行shell命令
FILE=test
A:=$(shell ls ../)
B:=$(shell pwd)
C :=$(shell if [ ! -f $(FILE) ];then touch $(FILE);fi;)
a:
echo $(A)
echo $(B)
echo $(C)
clean:
$(RM) $(FILE)
五、Makefile中编译动/静态链接库 .dll/.lib .so/.a 库文件
动态链接库:不会把代码编译到二进制文件中,而是在运行时才去家在,所以只需要维护一个地址
静态链接库:会把库中的代码编译到二进制文件中,当程序编译完成后,库文件可删除
-fPIC 产生位置无关的代码
-shared 共享
-l(小L) 指定动态库
-I(大i) 指定头文件目录,默认当前目录
-L 手动指定库文件搜索目录,默认只链接共享目录
#动态库
SoTest.c lisSoTest.so
gcc -shared -fPIC SoTest.c -o libSoTest.so
gcc -lSotest -L./ test.c -o test
gcc -lSotest -L./usr main.c -o main
#静态库
aTest.c libaTest.a
gcc -c aTest.c -o aTest.o
ar -r libaTest.a aTest.o
六、Makefile中赋值
Makefile中,都是先展开所有变量,再调用指令
Makefile一共提供了四个赋值运算符 (=、:=、?=、+=)
VARIABLE = value
# 在执行时扩展,允许递归扩展。
VARIABLE := value
# 在定义时扩展。
VARIABLE ?= value
# 只有在该变量为空时才设置值。
VARIABLE += value
# 将值追加到变量的尾端。
命令行传参 make -f Makefile FLAG=123 如果有Makefile ,则可写成 make FLAG=123
七、Makefile中的条件判断和循环
ifeq 判断是否相等,相等返回true,不相等返回false
ifneq 判断是否不相等,相等返回true,不相等返回false
ifdef 判断变量是否存在,存在返回true,不存在返回false
Ifndef 判断变量是否不存在,不存在返回true,存在返回false
Ifeq ($(A),123)
else
endif
Ifdef A
else
endif
#ifeq,ifneq 与条件之间要有空格,不然会报错
#可以只有if,没有else,
#但是没有 elseif的用法,如果要实现 elseif,就要写嵌套
makefile 中只有一个循环 foreach,只支持 GNU Make ,其它平台的make ,可以用shell 中的循环来实现
TARGET:=a b c d
FILE:=$(foreach v, $(TARGET),$v.txt)
all:
#foreach
echo $(FILE)
#for in
for v in $(TARGET);\
do touch $$v.txt;\
done;\
#用shell
$(shell for v in $(TARGET); do touch $$v-txt;done)
八、make install
make 1
make install 2 3 4
make clean 5
1:将源文件编译成二进制可执行文件(包括各种库文件)
2:创建目录,将可执行文件拷贝到指定目录(安装目录)
3:加全局可执行的路径
4:加全局的启停脚本
5:重置编辑环境,删除无关文件
make install 也就是把生成的文件类似于放入:/usr/local/bin/
反汇编指令:objdump -DC main>main.txt