前言
官网:http://www.gnu.org/software/make/ 偏底层的还是使用Makefile,之后做驱动,还是把makefile捡一捡,应用层多使用cmake:https://blog.csdn.net/weixin_44705391/article/details/115268898 makefile可以很好的帮我们管理工程,但是大型的工程很难编写makefile,用autotools通过config的方式来帮助生成makfile文件,autotools看文章:https://blog.csdn.net/weixin_44705391/article/details/122760799
基本规则
工程编译是make这个程序提供的功能,具体可阅读make的源代码,makefile是make需要的对工程管理的文件,make按照makefile来编译工程。
make的作用:
1.工程文件组织,编译工程
2.安装及卸载程序(make install等)
基本遵循一个规则:
目标:依赖
命令 //命令前面一定要时tab
make命令后面的参数来自于makefile文件,比如make clean,make install等,make会将目标作为参数执行。
第一个目标往往是all,也可以是其他名字,make不带参数执行就等于make all,当makefile文件中没有all目标时,其不带参数的情况下,默认执行第一个目标。
比如以下makefile,看注释:
hello:main.o fun1.o #make不带参数默认执行此目标
gcc main.o fun1.o -o hello
main.o:main.c
gcc -c main.c
fun1.o:fun1.c
gcc -c fun1.c
clean: #目标不带依赖
rm fun1.o main.o hello
install:
cp hello /usr/local/hello
uninstall:
rm /usr/local/hello
make变量
用户自定义变量
定义用= (可能会被之后的值影响)
也可以用:= (不会被之后的值影响)
?= 如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略。(实验可以看出:所谓的没有赋值过其实就是这个变量没有被定义过)
+= 用来给一个已经赋值的变量接续赋值,把这次的值加到原来的值的后面,(在shell makefile等文件中,可以认为所有变量都是字符串)(注意:+=续接的内容和原来的内容之间会自动加一个空格隔开)。
变量的使用:$(var)
=和:=的不同:
A=abc
B=$(A)def
A=gh0000000
all:
@echo $(B)
用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量引用的值时不能只往前面看,还要往后面看。
用:=来赋值的,则是就地直接解析,只用往前看即可。
预定义变量
AR 库文件维护程序,默认ar
AS 汇编程序,默认as
CC c编译器
CXX c++编译器
ARFLAGS ar选项,无默认值
ASFLAGS 汇编程序选项,无默认值
CFLAGS c编译器选项,无默认值
CXXFLAGS c++编译器选项,无默认值
自动变量
$@ 目标文件名
$< 第一个依赖文件名
$^ 不重复依赖的文件集合
$* 不包含扩展名的目标文件名称
$? 所有时间戳比目标文件晚的依赖文件
环境变量
(1)makefile中用export导出的就是环境变量。一般情况下要求环境变量名用大写,普通变量名用小写。
(2)整个工程中所有Makefile之间可以共享的全局变量。注意:定义了一个环境变量会影响到工程中别的Makefile文件,因此要小心。
Makefile中使用通配符
(1)* 若干个任意字符
(2)? 1个任意字符
(3)[] 将[]中的字符依次去和外面的结合匹配
还有个%,也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,又叫做规则通配符。
关于通配符,Makefile还有一些wildcard等比较复杂的通配符用法,具体参考《跟我一起学Makefile》即可。
其他
其他选项
伪目标(.PHONY)
没有依赖的目标可以将他声明为伪目标
注释:#
静默执行:@(命令前加此符号)
引用其他makefile
include指令
makefile嵌套
make -C ./路径
make install -C ./路径
条件判断
ifeq($(CC),gcc)
gcc $^ -o $@
else
$(CC) -o hello
endif
makefile管理命令
-Cdir 读入指定目录下面的makefile
-f file 读入当前目录下的file文件为makefile
-i 忽略所有命令执行错误
-I dir 指定被包含的makefile所在目录
这些命令可以在命令行下执行,也可以添加到makefile文件中:
比如重命名makefile为richard.mk
可以make clean -f richard.mk执行,也可以将此语句添加到其他makfile文件中
函数
makefile有预定义的函数
我们简单介绍一下uboot用到的函数:
1.origin
告诉你变量是哪里来的,其出生状况如何
函数语法:
$(origin )
为变量的名字,而不是引用,所以一般没有"$"字符在前。
origin 函数通过返回值来告诉你 的出生情况。下面用实例说明:
1.变量未定义
origin 函数返回 “undefined” 。
如下面的 Makefile 代码:
2.变量为环境变量
返回 “enviroment” 。
3.变量是自定义变量
返回 “default”。
如@echo $(origin CC)
4.变量被定义在 Makefile 文件中
返回 “file” 。
5.变量来自命令行
返回 “command line” 。
6.变量被 override 被重新定义过
返回 “override”。
如override SHELL = /bin/sh
all:
@echo $(origin SHELL)
上面,SHELL 原本是个环境变量,但在 Makefile 里被 override 指示符重定义过。
7.变量是自动化变量(如 @,< 等)
返回 “automatic” 。
如@echo $(origin @)
2.wildcard
列出目录下所有符合条件的文件,如wildcard *.c
3.addprefix
添加前缀,如OBJS := $(addprefix $(obj),$(OBJS)),将obj的内容作为OBJS的前缀,将其重新赋值给OBJS
4.dirname、lastword
例子:
dir2:=$(shell pwd)/$(lastword $(MAKEFILE_LIST))
name:=$(lastword $(MAKEFILE_LIST))
dir=$(shell dirname $(dir2))
all:
@echo $(dir2)
@echo $(name)
@echo $(dir)
输出:
/mnt/hgfs/share/rich.c
rich.c
/mnt/hgfs/share
5.subst
$(subst FROM, TO, TEXT),即将字符串TEXT中的子串FROM变为TO。
6.findstring
在字符串中查找子串$(findstring <find>,<in> )
7. notdir、dir
notdir用于去掉文件的绝对路径,只保留文件名。
dir取目录
depend
C 源码的开头经常有一系列被包含的头文件,例如 stdio.h。有一些是系统级的头文件,有一些是你正在写的项目的头文件:
#include <stdio.h>#include "foo.h"int main(…
要确定在你的 foo.h 被改变之后,这个文件也会被重新编译,就要在你的 Makefile 这样写:
foo: foo.c foo.h
当你的项目变得越来越大,你自己的头文件越来越多的时候,要追踪所有这些头文件和所有依赖它的文件会是一件痛苦的事情。如果你改变了其中一个头文件,却忘了重新编译所有依赖它的源文件,结果会是很失望的。
这就是depend 的作用,如果不使用这个功能, 则当你修改一个头文件时, 必须重新把所有的源文件都编译一次, 使用depend ,就可只编译包含此头文件的源文件,可大大节省时间。
gcc 有一个选项可以分析你的源文件然后产生一个头文件的列表和它的依赖关系: -MM。
如果你把下面的内容加到你的 Makefile 里面:
depend: gcc -E -MM *.c > .depend
然后运行 make depend,就会产生一个 .depend,里面包含了目标文件,C 文件和头文件的列表:
foo.o: foo.c foo.h
如果你改变了 foo.h,下一次运行 make 的时候,所有依赖 foo.h 的文件就会被重新编译。
每一次你增加一个头文件的时候,别忘了运行一次 make depend。