卡卷网
当前位置:卡卷网 / 每日看点 / 正文

Makefile怎么入门?

作者:卡卷网发布时间:2025-01-11 16:38浏览数量:69次评论数量:0次

<>Makefile</>是make工具的配置文件,主要用于定义如何构建和项目的编译过程。Makefile是C/C++编译项目中的重要工具,尤其在多文件、多模块的项目中,为了方便复杂项目的,可以通过自动化规则提高编译效率。

这篇文章是Makefile的入门教程的介绍,包括其基本语法、常用功能、以及实际使用中的高级技巧。

Makefile的基本概念

安装make

//sudoapt-getupdate sudoapt-getinstallmake

核心功能

    自动化编译:根据文件的依赖关系自动决定哪些文件需要重新编译。提高效率:只编译发生变化的部分。多任务支持:可以定义清理、打包、等任务。

使用方法

运行make命令时,默认会读取当前目录下的<>Makefile文件</>。

make#执行默认的目标make<target>#执行指定的目标

例如:

makeclean#执行"clean"目标

Makefile的基本语法

1.目标语法

<>Makefile</>的基本语法如下:

//target:prerequisites commands

    <>target</>:目标文件或命令名称。例如可执行文件、目标文件或任务名称。<>prerequisites</>:依赖文件或目标。只有依赖文件发生变化时,target才会被重新生成。<>commands</>:生成目标的命令(必须以<>Ta</>开头)。

示例:

//hello:hello.o gcc-ohellohello.o hello.o:hello.c gcc-chello.c

在示例代码中:

1.如果hello.c被修改,则hello.o会重新生成。

2.如果hello.o被修改,则hello会重新生成。

2.变量定义

<>Makefile</>支持变量定义,用于简化配置和重复的命令。

示例1:

//CC=gccCFLAGS=-Wall-g#简单赋值CC:=$(XX)gcc当前有效//立马获取当前XX变量的值#递归赋值CC=$(XX)gcc //去递归寻找XX变量的最后一个值#条件赋值CC?=gcc //如果有CC变量,则该语句无效#追加赋值CC+=$(XX)gcc //在原来值的基础上,进行追加#使用:$(CC)获取变量的值

示例2:

//x:=jake y:=$(x)androse x:=tonly all: echo"x=$(x),y=$(y)"

<>使用变量</>(示例1)

//hello:hello.o $(CC)$(CFLAGS)-ohellohello.o

<>输出:</>(示例2)

//x=windx,y=jakeandrose

<>示例</>

//CC=gccCFLAGS=-Wall-O2 hello:hello.o $(CC)$(CFLAGS)-ohellohello.o hello.o:hello.c $(CC)$(CFLAGS)-chello.c

3.内置变量

Makefile提供了一些常用的内置变量,可以减少重复工作。

变量|功能

变量功能
$@当前目标的名称(target)。
$<第一个依赖文件的名称(prerequisite)。
$^所有依赖文件的名称。

<>代码片:</>

//CC=gccCFLAGS=-Wall-g hello:hello.o $(CC)$(CFLAGS)-o$@$^

在这里:

    $@是hello(目标)。$^是hello.o(所有依赖文件)。

4.通配符和自动化规则

Makefile支持通配符和模式匹配规则,用于简化多文件项目的编写。

<>通配符</>

    *.c:匹配所有.c文件。$(wildcard*.c):列出当前目录下所有.c文件。$(patsust%.c,%.o,$(wildcard*.c)):将所有.c文件替换为对应的.o文件。

<>自动化规则</>

使用模式规则可以自动生成目标文件:

//%.o:%.c $(CC)$(CFLAGS)-c$<-o$@

    表示所有.o文件都可以由对应的.c文件生成。

<>代码:</>

//CC=gccCFLAGS=-Wall-O0-gSRC=$(wildcard*.c)OJ=$(patsust%.c,%.o,$(SRC))hello:$(OJ)$(CC)$(CFLAGS)-o$@$^ %.o:%.c $(CC)$(CFLAGS)-c$<-o$@

5.伪目标

伪目标(phonytargets)是指不生成实际文件的目标,通常用于清理、等任务。

伪目标也是一个目标,该目标不需要生成,每一次去执行该目标,都会执行。

<>定义伪目标:</>

.PHONY:clean#将当前目标设定为伪目标,每次执行该目标都会执行命令clean: rm-f*.ohello

    使用.PHONY声明可以避免冲突(例如当前目录下存在名为clean的文件时)。

6.自动推导规则

在使用make编译.c源文件时,可以省略编译一个.c文件所使用的命令。这是因为make存在一个默认的规则,能够自动完成对.c文件的编译并生成对应的.o文件。它执行命令“cc-c”来编译.c源文件。对于上边的例子,此默认规则就使用命令“cc-cmain.c-omain.o”来创建文件“main.o”。因此对一个目标文件是“N.o”,倚赖文件是“N.c”的规则。可以省略其规则的命令行,使用make的默认命令。此默认规则称为make的隐含规则(关于隐含规则看我上传至资源中的《GUNmake中文手册》第九章[使用隐含规则]一章,有详细说明。)

我们书写Makefile时,对于一个.c文件如果使用make的隐含规则,那么它会被自动作为对应.o文件的一个依赖文件(对应是指:文件名除后缀外,其余都相同的两个文件)。因此我们也可以在规则中省略目标的倚赖.c文件。

自动推导规则_1

自动推导规则_2

我们可以看见,当app文件被创建之后,再次执行make命令时,提示:make:'app'isuptodate.,此处是make的时间戳方式,如果目标生成的时间晚于依赖,该目标是最新的,那么该目标就不需要再编译重新生成。(如果想详细了解makefile的时间戳机制,可以点击查看这篇文章,对Makefile的时间戳机制有更详细的说明。<

笨猫猫的小茶馆:Makefile时间戳

>)

项目示例

这是一个多文件C项目的示例<>Makefile</>:

项目目录

//project/ ├──main.c ├──utils.c ├──utils.h ├──Makefile```#####Makefile```ash#编译器和编译参数CC=gccCFLAGS=-Wall-g#源文件和目标文件SRC=main.cutils.cOJ=$(SRC:.c=.o)TARGET=my_program#默认目标all:$(TARGET)#链接目标文件$(TARGET):$(OJ)$(CC)$(CFLAGS)-o$@$^#编译规则(自动化规则)%.o:%.c $(CC)$(CFLAGS)-c$<-o$@#清理目标.PHONY:clean clean: rm-f$(OJ)$(TARGET)

运行说明

1.构建项目

//make

2.清理项目:

//makeclean

这么写缺失中间的流程,接下来我结合图片将makefile项目的实际流程走一遍:

<>要求</>:(虽然是简易版用于教学的,但其中的过程和项目的思路,即使在大型项目中也是一致的,不同的只是划分的层级结构、架构更为复杂而已。)

1.创建项目目录

2.include/project.h的头文件

3.jack文件夹下的文件

4.将jack.c通过编译生成jack.o文件——>然后将jack.o放入oj文件夹下

5.此处的<>Makefile</>用于main.c文件,将main.c编译转化为main.o,将其保存在oj文件夹下一

6.main.o文件生成成功并放在了一文件夹oj下,接下来,将main.ojack.o做链接作生成app文件,因此,我们需要在oj文件夹下创建<>Makefile</>文件,用于将所有在此处的.0文件链接生成可执行文件app

7.成功生成了可执行文件app

8.因为main:会自动寻址至依赖的第一个文件,结果将提示文件已存在。所以这里我们要将需要生成的文件main设为伪目标。

至此,前面的步骤我们共计完成了4步:

第一步,我们将jack文件夹下的jack.c生成了jack.o,将其放在oj文件夹下;

第二步,我们将main文件夹下的main.c生成了main.o,将其放在oj文件夹下;

第三步,在oj文件夹下,将这里所有着的.o文件最终生成了可执行文件app

最后,我们在整个项目目录下,生成一个<>Makefile</>文件,用于整个项目,这样,最终我们只需要make一次,便能够得到整体项目的可执行文件,而不需要经过上述如此繁琐的步骤。

make-C文件夹/[目标]//去到该文件夹下去执行该文件夹下的Makefile的第一个目标[目标]

因为第一个目标已存在,所以此处我们需要提前设置mainclean为伪目标。

9.最终生成可执行文件app

10.优化Makefile代码。

11.添加共享变量,在最终的Makefile文件中添加共享变量,这样的话,可供同一级目录和该目录下的所有子目录中的Makefile文件皆可以共享到最上层的Makefile文件中的共享变量。

export共享变量//当前同一级目录下的子目录都可以共享该变量

12.这时候进入了一个新人,分配任务给rose,创建rose文件夹并加入这部分模块的代码,

至此,以上为Makefile项目在开发中的实际应用(简易版)。

高级功能

条件判断

根据条件设置变量或执行不同的规则。

//DEUG=1ifeq($(DEUG),1)CFLAGS+=-gelseCFLAGS+=-O2 endif

包含Makefile

使用include将多个Makefile文件整合在一起。

//includecommon.mk

    这种方式适合大型项目,将公共配置提取到单的文件中。

一些常见问题与技巧

如何调试Makefile?

运行make时加上-n--dry-run参数,可以查看执行的命令而不正运行:

//make-n

如何提高编译效率?

使用make的并行编译选项-j,可以同时编译多个目标:

//make-j4

    其中4表示最多允许4个任务同时执行。

综上。这篇文章仅仅只介绍了makefile的简单用法,更多更详细的内容可以下载资源查看makefile手册(中文版),Makefile是一个强大的工具,适合用于从简单到复杂的编译流程。

本章主要介绍了:

    <>基础语法</>:理解目标、依赖和命令的结构。<>变量和内置变量</>:使用变量提高可读性和灵活性。<>自动化规则</>:使用通配符和模式规则减少重复代码。<>伪目标</>:定义清理、等任务。<>高级功能</>:条件判断、多文件组织、并行编译。

通过不断优化Makefile,可以显著提高项目的效率和可性,适合运用和大型项目。


END

免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。

卡卷网

卡卷网 主页 联系他吧

请记住:卡卷网 Www.Kajuan.Net

欢迎 发表评论:

请填写验证码