makefile编译第一讲

更多精彩内容在公众号。关注公众号,加v,免费送你两本makefile电子书。轻松掌握makefile

在C和C++中,首先要把源文件编译成中间代码文件,在windows下就是obj文件,linux下就是.o文件:object file。这个动作叫做编译,然后再把大量的object file合成执行文件。这个动作叫做链接(link)

编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在 C/C++文件中) ,只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对

应于一个中间目标文件(O 文件或是 OBJ 文件)

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

所以整个过程大致分为2个步骤:

1 源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。 如果函数未被声明,编译器会给出一个警告,但可以生成 ObjectFile。

2而在链接程序时,链接器会在所有的 Object File 中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error) ,在 VC下,这种错误一般是:Link 2001 错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的 Object File.

下面我们就来看下makefile的语法规则。

makefile的语法规则如下

target:prerequisites

command

target也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签(Label)

prerequisites 就是,要生成那个 target 所需要的文件或是目标

command 也就是 make 需要执行的命令。 (任意的 Shell 命令)

说白了,其实就是整个工程里面的文件依赖关系,target 这一个或多个的目标文件依赖于 prerequisites 中的文件,其生成规则定义在 command 中。说白一点就是说, prerequisites 中如果有一个以上的文件比 target 文件要新的话,command 所定义的命令就会被执行。这就是 Makefile 的规则。

一个工程中的源文件不计其数,按照不同的功能分类在若干的目录里面,makefile定义了一系列的规则,来制定那些文件需要先编译,那些文件后编译,那些文件重新编译。makefile最大的好处就是自动化编译。一旦写好,只需要一个make命令,整个过程都自动编译。极大提高开发的效率。我们先来看个简单的例子:
如果一个工程里面有1个头文件calc.h和2个C文件main.c,calc.c
main.c的内容如下:
#include "stdio.h"
#include "calc.h"
int main()
{
    int n,k;
    int c;
    n=3;
    k=4;
    c=calculate(n,k);
    printf("the value is %d\n",c);
}
calc.c的内容如下:
#include "calc.h"

int calculate(int n,int k)
{
    return n*k;
}
calc.h的内容如下:
#ifdef CALC_H
#define CALC_H
int calculate(int n,int k);
#endif
为了完成对工程文件案的编译,并生成执行文件main,按照如下的方式编译文件
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# gcc main.c calc.c -o main
但是如果我对main.c做了修改。就需要把所有源文件都重新编译一遍,即使其他文件没有任何变化。也要跟着重新编译。一个大的软件项目上千个源文件组成,编译一次耗时很长。一个源文件修改导致全部重新编译肯定不合理。我们可以这样优化下:
gcc -c main.c
gcc -c calc.c
gcc main.o calc.o -o main
如果编译之后有对main.c做了修改,重新编译之需要两步:
gcc -c main.c
gcc main.o calc.o -o main
这样比之前的要省事一些了,但还是有问题,在calc.c和main.c都包含了calc.h。如果我对calc.h做了改动。所有包含calc.h的文件都得改动。而且还得到处去找那些包含了calc.h。还是很麻烦。比如在calc.h中增加了一个宏定义。并且在man.c和calc.c中都有用到这个变量。那么一旦calc.h修改了宏定义变量的值。calc.c和main.c都必须重新编译。
#define max_value 40

那么我们需要一种什么样的编译方式才能最省事呢:
1 如果这个工程没有被编译过,那么我们的所有C文件都要编译并被链接
2 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并连接目标程序
3 如果这个工程的头文件被修改了,那么我们需要编译引用了这几个头文件的C文件并链接目标程序。
能达到上述目的的就是makefile文件了。在工程的文件路径下新建一个Makefile文件。其中内容如下:
main:main.o calc.o
    gcc -o main main.o calc.o
main.o:main.c calc.h
    gcc -c main.c
calc.o:calc.c calc.h
    gcc -c calc.c
clean:
    rm *.o
    rm main
执行make命令
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o

来看下Makefile的规则:
1 第一条规则的目标为main。而为了得到main,必须先得到main.o calc.o这2个文件。所以make会进一步查找这2个条件为目标的规则。
2 第二条规则和第三套规则的目标三main.o和calc.o。main.o依赖于main.c和calc.h。为了得到main.o必行执行gcc -c main. Calc.o依赖于calc.c和calc.h。为了得到calc.o必须执行gcc -c calc.c
3 最后的clean操作清除执行过程中产生的临时文件。当用make命令执行的时候,clean下的命令不会执行,要以make clean方式单独执行。执行后,所有*.o和main都被删除。
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 40
drwxr-xr-x 2 root root 4096 Nov 10 09:15 .
drwxr-xr-x 3 root root 4096 Nov  8 10:35 ..
-rw-r--r-- 1 root root  118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root   94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root 1056 Nov 10 09:15 calc.o
-rwxr-xr-x 1 root root 7396 Nov 10 09:15 main
-rw-r--r-- 1 root root  182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root 1196 Nov 10 09:15 main.o
-rw-r--r-- 1 root root  142 Nov 10 09:15 Makefile
执行make clean
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make clean
rm *.o
rm main
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 24
drwxr-xr-x 2 root root 4096 Nov 10 09:29 .
drwxr-xr-x 3 root root 4096 Nov  8 10:35 ..
-rw-r--r-- 1 root root  118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root   94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root  182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root  142 Nov 10 09:15 Makefile

下面我们来修改calc.h中的内容,#define max_value 50
看下编译内容。由于calc.c和main.c都包含了calc.h因此calc.c和main.c都会编译
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o

如果只修改calc.c中的内容。calc.c修改如下
int calculate(int n,int k)
{
    printf("the value is %d",max_value);
    return n*k+n*k;
}
可以看到只编译了calc.c。main.c没有编译
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c calc.c
gcc -o main main.o calc.o

当没有任何文件修改的时候:会提示main is up to date
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
make: 'main' is up to date.

那么make是如何工作的呢:
1 make会在当前目录下查找名为makefile或者Makefile的文件
2 如果找到,它会找文件中的第一个目标文件,在上面的例子中,它会找到main这个文件
3 如果main不存在,或者main所依赖的后面的.o文件的修改时间比main晚,那么就会执行后面所定义的命令来生成main这个文件
4 如果main所依赖的.o文件存在,那么make会在当前文件中查找目标为.o文件的依赖性,如果找到,则再根据那个规则生成.o文件
5 当C文件和H文件存在时,make会生成.o文件。然后再用.o文件生成make的终结任务也就是执行文件main
也就是说,main会一层一层的寻找文件的依赖关系,直到编译出一个目标文件。如果在查找过程中依赖的文件找不到那么就会直接退出或报错。

继续来看下之前的makefile文件。在第一条规则的时候。.o文件被重复了两次。如果工程需要加入一个新的.o文件,那么就需要在2个地方加。如果makefile很复杂。那么就可有可能忘掉一个需要加入的地方。而导致编译失败。所以为了makefile的易维护,在makefile中可以使用变量。可以理解为C语言中的宏定义
main:main.o calc.o
    gcc -o main main.o calc.o
文件修改如下:
objects=main.o calc.o
main:$(objects)
    gcc -o main $(objects)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/481182.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.9 什么是A/B测试?如何进行A/B测试?

2.9 什么是A/B测试? 场景描述 在互联网公司中,A/B 测试是验证新模块、新功能、新产品是否有效,新算法、新模型的效果是否有提升,新设计是否受到用户欢迎,新更改是否影响用户体验的主要测试方法。在机器学习领域中&…

Google XSS Game Level 6 通关方式

文章目录 链接:[Google XSS Game](#https://xss-game.appspot.com/)Level 6 - Follow the 🐇思路1 (当然,我使用这个方式没有成功,所以才来记录下)解法2 【最简单的解法】需要注意的一个小问题 链接&#x…

C++入门笔记开源【研究生3年+7W字】

博主研究生3年时间积累了一个C的基础知识文档,共计7W字。几乎把常用的各种语法和接口都包含进去了。一个文档,markdown格式的,可以当做工具书来使用。由于本文档内容较多,直接复制到csdn会各种卡,而且图片链接不对&…

全智能深度演进,一键成片让视频创作颠覆式提效

全智能一键成片,让内容创作的「边际成本」逼近于零。 大模型和AIGC技术的发展,可以用“日新月异”来形容,其迭代速度史无前例,涌现出的各类垂直应用模型,也使得音视频行业的应用场景更加广泛和多样化。 然而&#xff…

PTA L2-027 名人堂与代金券

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元…

Unity vision pro模拟器开发教程-附常见问题解决方案

前言 庄生晓梦迷蝴蝶,望帝春心托杜鹃 废话 去年苹果发布会上,推出了Vision Pro这一款XR产品。并且宣布Unity作为其主要合作伙伴,负责开发XR的开发产品。 这消息一出,当晚Unity的股价直接被熔断。产品发布之后,一直等…

java篇 让java对象具有链式调用

一 操作 1.1 流程 1.在类中引入注解Accessors(chain true),引入后,不要在使用自定义的getter,setter方法 Data Accessors(chain true) public class Student {private String name;private int age;Overridepublic String toString() {r…

【模板】AcWing873. 《欧拉函数》(C++)

【题目描述】 给定 n 个正整数 ,请你求出每个数的欧拉函数。 欧拉函数的定义 【输入格式】 第一行包含整数 n。 接下来 n 行,每行包含一个正整数 。 【输出格式】 输出共 n 行,每行输出一个正整数 的欧拉函数。 【数据范围】 1≤n≤1…

opencv 十八 python下实现0缓存掉线重连的rtsp直播流播放器

使用opencv打开rtsp视频流时,会因为网络问题导致VideoCapture掉线;也会因为图像的后处理阶段耗时过长导致opencv缓冲区数据堆积,从而使程序无法及时处理最新的数据。为此对cv2.VideoCapture进行封装,实现0缓存掉线重连的rtsp直播流…

Mall 西瑾商城uniapp商城项目:一个全平台兼容的电商解决方案

一、引言 随着移动互联网的快速发展,电商行业正经历着前所未有的变革。在这个背景下,一个优秀的电商平台需要具备全平台兼容、高效的商品管理、用户友好的界面设计以及强大的消息和客服支持等功能。本文将详细介绍Mall 西瑾商城uniapp商城项目&#xff…

欣瑞达信息技术邀您莅临2024长三角快递物流展

2024数字物流技术展 2024新能源商用车及物流车展 2024电商物流包装展 2024冷链物流展 2024年7月8-10日 | 杭州国际博览中心 参展企业介绍 深圳市欣瑞达信息技术有限公司(曾用名:深圳市欣瑞达液晶显示技术有限公司)成立于1997年,是…

Gitlab的流水线任务【实现每小时自动测试 dev分支的更新】

背景 在现代软件开发实践中,持续集成(Continuous Integration, CI)是确保代码质量和快速响应软件缺陷的关键策略。GitLab 提供了强大的 CI/CD 功能,允许开发者自动化测试和部署流程。本文将介绍如何设置 GitLab 流水线计划任务&a…

Linux centos7安装nginx-1.24.0并且实现自启动

1.安装之前的操作 ps -ef|grep nginx 查看是否有运行 如果有就杀掉 kill -9 pid find / -name nginx 查看nginx文件 rm -rf file /usr/local/nginx* 通通删掉删掉 yum remove nginx 限载一下服务 1.2.下载安装包 地址 nginx: download 2.减压文件 tar…

浮点二分(求一个数的平方根)

问题&#xff1a;求一个浮点数的平方根&#xff0c;要求保留两位小数。 #include<iostream> #include<iomanip> using namespace std;int main(){double x;cin>>x;double L0,Rx;while(R-L>1e-4){//保留两位小数的精度&#xff0c;若要保留3位小数&#…

蓝桥杯十四届 试题E接龙数列

思路&#xff1a; 做题要想到用对立面解题&#xff0c;要求最短的&#xff0c;就可以先求最长的 //先求最长的接龙序列的长度maxx&#xff0c;再用长度n减去maxx //先声明dp数组&#xff0c;记录以0-9结尾的最长的接龙数列的长度 //以字符串的形式输入 //更新以b结尾的最大接…

Zabbix与Prometheus区别简述

Zabbix与Prometheus区别简述 历史沿革 一、监控工具简介 1、Zabbix https://www.zabbix.com/cn/download Zabbix是传统的监控系统&#xff0c;出现比云原生早&#xff0c;使用的是SQL关系型数据库&#xff1b;开源监控软件&#xff0c;遵守 GPLv2开源协议&#xff0c;起源于…

【Android】【Bluetooth Stack】蓝牙电话协议分析(超详细)

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待&#xff01…

linux -- I2C设备驱动 -- MS32006(低压5V多通道电机驱动器)

产品简述 MS32006 是一款多通道电机驱动芯片, 其中包含两路步进电机驱动, 一路直流电机驱动; 每个通道的电流最高电流1.0A; 支持两相四线与四相五线步进电机。芯片采用 I2C 的通信接口控制模式, 兼容 3.3V/5V 的标准工业接口。 MS32006 总共集成了两路步进电机驱动器与一…

mysql置事务隔离级

隔离级别脏读&#xff08;Dirty Read&#xff09;不可重复读&#xff08;Non-Repeatable Read&#xff09;幻读&#xff08;Phantom Read&#xff09;读未提交是是是读已提交否是是可重复读否否是序列化否否否 这个表格以可读性的方式总结了四种隔离级别下可能发生的并发问题。…

【数据结构】——栈与队列(附加oj题详解)深度理解

栈 1.栈的定义 栈&#xff1a;栈是仅限与在表尾进行插入或者删除的线性表 我们把允许一端插入和删除的一端叫做栈顶&#xff0c;另一端叫栈底&#xff0c;不含任何元素的栈叫做空栈&#xff0c;栈又叫做后进先出的线性表&#xff0c;简称LIFO结构 2.栈的理解 对于定义里面…