玩转Makefile文件

本文主要参考陈皓跟我一起写 Makefile (PDF 重制版)

这篇教程讲得还是蛮清楚的,本文主要是实战总结。

在线文档:概述 - 《跟我一起写Makefile》 - 书栈网 · BookStack

参考视频:

makefile从入门到项目编译实战_哔哩哔哩_bilibili

初学者,容易搞混Makefile和Shell的语法。。。。。。 

基本的内容可直接查阅《跟我一起写Makefile》,本文重点记录容易搞错容易忘记的地方。 

为什么需要Makefile

Makefile是用来管理工程的。

在一个正式的软件项目中,由很多个.c和.h文件构成,此时如果直接在命令行编译,就会像这样:gcc a.c b.c c.c d.c e.c f.c g.c -o exe 每次编译都要输入一堆东西很麻烦,这个问题严重影响工作效率,怎么办?Makefile来解决。

makefile 关系到了整个工程的编译规则。

一个工程中的源文件不计数,其按类型、功能、 模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译, 哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。

makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译, 极大的提高了软件开发的效率。

make 是一个命令工具,是一个解释 makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的 make,Visual C++的 nmake, Linux 下 GNU 的 make。可见,makefile 都成为了一种在工程方面的编译方法。

一般来说,无论是C还是C++,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即Object File,这个动作叫做编译(compile),每个源文件都应该对应于一个中间目标文件( .o 文件或.obj 文件)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。

附:.o和.a文件是什么关系?

我们知道中间目标文件有很多,需要被链接,当我们把这些.o文件全都一个一个地分散着给别人,显然是不太安全的,并且不大优雅的,所以,通常将这些.o文件打个包,然后发给别人。

【一站式解惑】Linux中.a、.so和.o文件以及-I,-L,LIBRARY_PATH,LD_LIBRARY_PATH等-腾讯云开发者社区-腾讯云 (tencent.com)

什么是.so文件?怎么生成、有什么特性-CSDN博客

链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),链接时,主要是链接函数和全局变量。

在编译时,编译器只检测程序语法和函数、变量是否被声明。而在链接程序时,链接器会在所有的Object File中找寻对应的全局变量以及函数的实现,如果找不到,那到就会报链接错误码(Linker Error)。

补充一个.ko文件
【Linux 内核】linux中.so、.ko、.a、.o文件区别_.so .ko-CSDN博客

bin、hex、exe、elf文件类型到底有何区别?如何解读hex文件和elf文件?...相关内容都在这里!-CSDN博客

嵌入式开发中的.bin文件和.elf文件的区别_bin elf-CSDN博客

elf文件解析以及和bin文件的区别_elf文件和bin文件的区别-CSDN博客

gcc命令

gcc命令 – C/C++语言编译器 – Linux命令大全(手册) (linuxcool.com)

gcc常用的两个参数

-c,compile;

-o,output;

另外,用gcc来执行.o文件,会直接链接成可执行文件。

make命令

make命令的参数选项(执行make时可以添加哪些选项)_make 参数-CSDN博客

比较重要的几个参数:

-C,make时,默认的是执行当前目录下的Makefile,但是如果Makefile在别的目录里,可以加-C,在读取 Makefile 之前,进入到目录 DIR,然后执行 make。也可以理解成,执行指定路径目录下的Makefile。一般开启了-C,就会默认开启-w(小写),可以显示进入了目标路径,执行完Makefile后又会回到原处。

-f,make时默认识别名叫Makefile的文件,如果不叫这名字,而是xxx,可以用-f xxx指定文件名。

-n,只打印执行的命令,但是不执行命令。可以让我们看到执行的过程,方便调试。

-s,静默输出,只执行命令,不显示命令。和-n相反。

-w,在 make 进入一个子目录读取 Makefile 之前打印工作目录,这个选项可以帮助我们调试 Makefile,跟踪定位错误。使用 "-C" 选项时默认打开这个选项。

make静默输出

make执行时make 默认会打印每条命令,再执行。这个行为被定义为回声。

make静默输出的两种方式

  1. 一开始执行make时加-s选项,这样会禁止所有的命令回显
  2. Makefile里执行命令时在命令前面加上@,这样可以精准到每一条命令;

makefile嵌套

参考:

多级目录的makefile编写及参数传递_不同makefile传递值-CSDN博客

Makefile学习笔记系列3:具有子目录层次结构的makefile写法_makefile 包含子目录-CSDN博客

多层级的makefile编写——递归调用makefile_makefile 循环调用makefile-CSDN博客

每个目录下的makefile只负责本目录下的文件的编译。

嵌套执行makefile,其实就是在上层makefile中执行下层的makefile,有两种方式:

1、先cd进入子路径,然后make;

2、直接在上层makefile中执行make,但是用-C指定子makefile的路径;

有时候我们需要向子 make 传递变量,
这个时候使用“export”来导出要传递给子 make 的变量即可,如果不希望哪个变量传递给子make 的话就使用“unexport”来声明不导出:
export VARIABLE ……    //导出变量给子 make 。

unexport VARIABLE……    //不导出变量给子 make。
有两个特殊的变量:“SHELL”和“MAKEFLAGS”,这两个变量除非使用“unexport”声明,
否则的话在整个make的执行过程中,它们的值始终自动的传递给子make。

makefile可用的环境变量

linux环境下, 执行命令make -p可以查看makefile可用的环境变量。

Ubuntu--查看Makefile内置变量_make 查看变量-CSDN博客

然后ctrl+shift+f打开终端界面的搜索框,搜索目标变量名。

另外注意,我们可以在执行make的时候,给makefile传递全局变量

比如:

make HOSTNAME=admin.cc

Makefile 环境变量 - Makefile中使用系统环境变量 - Makefile 简明教程 | 宅学部落 (zhaixue.cc)

如果传递的变量是系统环境变量,那么系统环境变量就会被这个同名变量覆盖。

带你一文搞懂Linux PATH-云社区-华为云 (huaweicloud.com)  

一些常见的环境变量

makefile中常见的环境变量_makefile 环境变量-CSDN博客 

Makefile中常见的Q是啥?

在makefile,约定俗成地将Q绑定到@,用来实现命令的静默输出,Quiet...

自动化变量(规则变量)

$@:表示目标文件的名称,包含扩展名
$^:表示所有的依赖文件,以空格隔开,不重复
$<:表示第一个依赖文件的名称
$+:表示所有的依赖文件,空格隔开,可以重复
$*:表示目标文件的名称,不包含扩展名
$?:依赖项中,所有比目标文件新的依赖文件 

深入理解Makefile中的自动化变量-百度开发者中心 (baidu.com)

函数

【makefile笔记】patsubst和wildcard函数使用小结-CSDN博客

指定头文件路径 

在mcu开发中,一般都会在keil上指定头文件所在的位置,那么在linux中怎么指定头文件的位置呢?

一般是通过在Makefile里面将头文件路径添加到CFLAGS这个全局变量里。

GCC编译器CFLAGS、LDFLAGS详解-CSDN博客

系统自带的库里的头文件,一般都不需要指定路径,只需要在Makefile中添加自定义的一些头文件即可。

看一个文件有没有参与编译,就在里面打印一大堆乱七八糟的东西,如果编译时没有报错,就说明没有参与编译。

编译时是报语法错误,比如逗号没写、头文件没找到等等;链接时才会报找不到对应的变量或者函数;

在编译时,编译器只检测程序语法和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成 Object File。而在链接程序时,链接器会在所有的 Object File 中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在 VC 下,这种错误一般是:Link 2001 错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的 Object File。

编译时,所有的头文件都会在源文件中展开,然后编译生成.o文件,链接时,主要是链接函数和全局变量。所以,我们可以使用这些中间目标文件(.o 文件或 .obj 文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File), 在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便。所以,我们要给中间目标文件打个包,在 Windows 下这种包叫“库文件”(Library File),也就是 .lib 文件,在 UNIX 下,是 Archive File,也就是 .a 文件。

问题总结

01

make时遇到一个问题:

百度后,有说是格式的问题,注意Tab的使用,修改后仍然提示。

Makefile missing separator. Stop.怎么解决_limanjihe的博客-CSDN博客_makefile missing separator

其实,这句话的意思就是缺少分隔,通常都是格式的问题,这里还提示了是第1行。

我不存在Tab键的问题,而是在第一行的目标和依赖之间,没有用冒号隔开,而是直接空格。

make.defs

make使用总结(9)-Makefile编写_make.defs-CSDN博客

Makefile不能能和shell一样,直接写命令,会报错

makefile并不是命令的集合,makefile的目的只有一件事,那就是生成最终目标。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值