Makefile学习

定义

Makefile 是一个工程文件的编译规则,描述了整个工程的编译和链接等规则

使用场景

  • 数学计算库 math 中的函数,我们得手动添加参数 -Im;

  • 小型数据库 SQLite 中的函数,我们得手动添加参数 -lsqlite3;

  • 线程,我们需要去手动添加参数 -lpthread。

  • 多个文件链接

Makefile 支持多线程并发操作,会极大的缩短我们的编译时间,并且当我们修改了源文件之后,编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译,不增加或者是删除工程中的文件,Makefile 基本上不用去修改。

规则

依赖的关系和执行的命令,格式如下:目标和依赖文件之间要使用冒号分隔开,命令的开始一定要使用 Tab键

targets : prerequisites
    command   
#targets:规则的目标,可以是 Object File(一般称它为中间文件),也可以是可执行文件或一个标签;
#prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可有可无
#command:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。

Makefile只有行注释:#

make 执行的是 Makefile 中的第一规则(Makefile 中出现的第一个依赖关系),此规则的第一目标称之为“最终目标”.如:

main:main.o test1.o test2.o   # 最终生成main可执行文件, 其中main.o、test1.o、test2.o文件是依赖文件
gcc main.o test1.o test2.o -o main
main.o:main.c test.h #得到main.o
gcc -c main.c -o main.o
test1.o:test1.c test.h #得到test1.o
gcc -c test1.c -o test1.o
test2.o:test2.c test.h #得到test2.o
gcc -c test2.c -o test2.o
工作流程:

在这里插入图片描述

清除工作

一般会在Makefile文尾处会添加一个clean规则,如下面用于内核编程的Makefile:


bj-m := myko.o

KERNELDR := ~/linux-4.4.72/

PWD := $(shell pwd)

modules:
		$(MAKE) -C $(KERNELDR) M=$(PWD) modules

moduels_install:
		$(MAKE) -C $(KERNELDR) M=$(PWD) modules_install

clean:
		rm -rf *.o *~ core .depend .*.cmd  *.mod.c .tmp_versions

clean 是独立的,它只是一个伪目标所以我们在执行 make 的时候也不会执行下面的命令。在shell 中执行 “make clean” 命令即可执行下面定义的命令

变量

格式:key=value ,调用:$(key) 或 ${key}

赋值方式:
  • 简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。(局部)

  • 递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。(全局)

  • 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。(判空)

  • 追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。(追加)

系统变量
变量用途
$@表示规则的目标文件名
$%当目标文件是一个静态库文件时,代表静态库的一个成员名
$<规则的第一个依赖的文件名
$?所有目标文件更新的依赖文件列表,空格分隔
$^代表的是所有依赖文件列表,使用空格分隔
$+类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。
$*在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分(当文件名中存在目录时, “茎”也包含目录部分)。
$(@D)表示文件的目录部分(不包括斜杠)。如果 “$@” 表示的是 “dir/foo.o” 那么 “$(@D)” 表示的值就是 “dir”。如果 “$@” 不存在斜杠(文件在当前目录下),其值就是 “.”
$(@F)表示的是文件除目录外的部分(实际的文件名)。如果 “$@” 表示的是 “dir/foo.o”,那么 “$@F” 表示的值为 “foo.o”
test:test.o test1.o test2.o
         gcc -o $@ $^ #等同于gcc -o test test.o test1.o test2.o
test.o:test.c test.h
         gcc -o $@ $<
test1.o:test1.c test1.h
         gcc -o $@ $<
test2.o:test2.c test2.h
         gcc -o $@ $<  #等同于gcc -o test2.o test2.c

编译环境

当采用模块话开发时,比如h文件放在include文件目录下,c文件放在src目录下,而Makefile放在上一级目录

那么此时make肯定是找不到文件的,那么就需要对它指定路径 :

VPATH=src include
#或者采用vpath (小写)
#vpath %.c src
#vpath %.h include
main:main.o list1.o list2.o
    gcc -o $@ $<
main.o:main.c
    gcc -o $@ $^
list1.o:list1.c list1.h
    gcc -o $@ $<
list2.o:list2.c list2.h
    gcc -o $@ $<

VPTH表示指定make的路径搜索为当前目录下的src目录下和当前目录的include目录下

隐含规则

即make会智能处理的规则,不需要手动定义也可完成的默认规则,如下代码

test:test.o
    gcc -o test test.o
test.o:test.c
	 #gcc -o test.o test.c  #这里注释了后没有手动生成test.o文件,但是makefile会默认执行 gcc -o test.o test.c

经过上面又可简化为如下代码

test:test.o

test.o:test.c

从而代替了 gcc -o test.o test.c ----> gxx -o test test.o

注意:隐含条件只能省略中间目标文件重建的命令和规则,但是最终目标的命令和规则不能省略

伪目标

定义:.PHONY:clean \n clean: 或clean:

区别是当make工作目录下存在一个clean文件时就会发生冲突从而导致停止执行

也可以认为是解决文件名冲突的一个解决方案

关键字

  • @符号 : 不在控制台显示该命令,或make -s 所有命令不显示打印,如下

@echo hello -------输出-------> hello

echo hello -------输出-------> echo hello

  • include : 暂停读取当前的 Makefile,而是去读 “include” 包含的文件,读取结束后再继读取当前的 Makefile 文件
  • $(MAKE) : make嵌套执行,如下
subsystem:
    cd subdir && $(MAKE) #到subdir目录下 执行make命令
    #$(MAKE) -C subdir  #另一种写法
  • export :用于make嵌套执行时的变量传递

make参数

参数选项功能
-b,-m忽略,提供其他版本 make 的兼容性
-B,–always-make强制重建所有的规则目标,不根据规则的依赖描述决定是否重建目标文件。
-C DIR,–directory=DIR在读取 Makefile 之前,进入到目录 DIR,然后执行 make。当存在多个 “-C” 选项的时候,make 的最终工作目录是第一个目录的相对路径。
-dmake 在执行的过程中打印出所有的调试信息,包括 make 认为那些文件需要重建,那些文件需要比较最后的修改时间、比较的结果,重建目标是用的命令,遗憾规则等等。使用 “-d” 选项我们可以看到 make 构造依赖关系链、重建目标过程中的所有的信息。
–debug[=OPTIONS]make 执行时输出调试信息,可以使用 “OPTIONS” 控制调试信息的级别。默认是 “OPTIONS=b” ,“OPTIONS” 的可值为以下这些,首字母有效:all、basic、verbose、implicit、jobs、makefile。
-e,–enveronment -overrides使用环境变量定义覆盖 Makefile 中的同名变量定义。
-f=FILE,–file=FILE, --makefile=FILE指定文件 “FILE” 为 make 执行的 Makefile 文件
-p,–help打印帮助信息。
-i,–ignore-errors执行过程中忽略规则命令执行的错误。
-I DIR,–include-dir=DIR指定包含 Makefile 文件的搜索目录,在Makefile中出现另一个 “include” 文件时,将在 “DIR” 目录下搜索。多个 “-i” 指定目录时,搜索目录按照指定的顺序进行。
-j [JOBS],–jobs[=JOBS]可指定同时执行的命令数目,没有 “-j” 的情况下,执行的命令数目将是系统允许的最大可能数目,存在多个 “-j” 目标时,最后一个目标指定的 JOBS 数有效。
-k,–keep-going执行命令错误时不终止 make 的执行,make 尽最大可能执行所有的命令,直至出现知名的错误才终止。
-l load,–load-average=[=LOAD],–max-load[=LOAD]告诉 make 在存在其他任务执行的时候,如果系统负荷超过 “LOAD”,不在启动新的任务。如果没有指定 “LOAD” 的参数 “-l” 选项将取消之前 “-l” 指定的限制。
-n,–just-print,–dry-run只打印执行的命令,但是不执行命令。
-o FILE,–old-file=FILE, --assume-old=FILE指定 "FILE"文件不需要重建,即使是它的依赖已经过期;同时不重建此依赖文件的任何目标。注意:此参数不会通过变量 “MAKEFLAGS” 传递给子目录进程。
-p,–print-date-base命令执行之前,打印出 make 读取的 Makefile 的所有数据,同时打印出 make 的版本信息。如果只需要打印这些数据信息,可以使用 “make -qp” 命令,查看 make 执行之前预设的规则和变量,可使用命令 “make -p -f /dev/null”
-q,-question称为 “询问模式” ;不运行任何的命令,并且无输出。make 只返回一个查询状态。返回状态 0 表示没有目标表示重建,返回状态 1 表示存在需要重建的目标,返回状态 2 表示有错误发生。
-r,–no-builtin-rules取消所有的内嵌函数的规则,不过你可以在 Makefile 中使用模式规则来定义规则。同时选项 “-r” 会取消所有后缀规则的隐含后缀列表,同样我们可以在 Makefile 中使用 “.SUFFIXES”,定义我们的后缀名的规则。“-r” 选项不会取消 make 内嵌的隐含变量。
-R,–no-builtin-variabes取消 make 内嵌的隐含变量,不过我们可以在 Makefile 中明确定义某些变量。注意:“-R” 和 “-r” 选项同时打开,因为没有了隐含变量,所以隐含规则将失去意义。
-s,–silent,–quiet取消命令执行过程中的打印。
-S,–no-keep-going, --stop取消 “-k” 的选项在递归的 make 过程中子 make 通过 “MAKEFLAGS” 变量继承了上层的命令行选项那个。我们可以在子 make 中使用“-S”选项取消上层传递的 “-k” 选项,或者取消系统环境变量 “MAKEFLAGS” 中 "-k"选项。
-t,–touch和 Linux 的 touch 命令实现功能相同,更新所有的目标文件的时间戳到当前系统时间。防止 make 对所有过时目标文件的重建。
-v,version查看make的版本信息。
-w,–print-directory在 make 进入一个子目录读取 Makefile 之前打印工作目录,这个选项可以帮助我们调试 Makefile,跟踪定位错误。使用 “-C” 选项时默认打开这个选项。
–no-print-directory取消 “-w” 选项。可以是 用在递归的 make 调用的过程中 ,取消 “-C” 参数的默认打开 “-w” 的功能。
-W FILE,–what-if=FILE, --new-file=FILE, --assume-file=FILE设定文件 “FILE” 的时间戳为当前的时间,但不更改文件实际的最后修改时间。此选项主要是为了实现对所有依赖于文件 “FILE” 的目标的强制重建。
–warn-undefined-variables在发现 Makefile 中存在没有定义的变量进行引用时给出告警信息。此功能可以帮助我们在调试一个存在多级嵌套变量引用的复杂 Makefile。但是建议在书写的时候尽量避免超过三级以上的变量嵌套引用。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值