【Linux系统编程】第十三弹---项目自动化构建工具-make/Makefile

news2024/11/16 21:41:35

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、背景

2、编写makefile

2、make原理

3、理解makefile

 4、优化makefile

总结


1、背景

★ 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
★ 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
★ makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
★ make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

总结:

★ make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

2、编写makefile

第一步,先创建两个文件,一个用于编写源代码(test.c),一个用于自动编译源代码(makefile/Makefile)。

[jkl@VMCentos7 lesson4]$ touch test.c makefile # 创建两个文件
[jkl@VMCentos7 lesson4]$ ls
makefile  test.c

第二步,编写makefile文件。

test.exe:test.c
	gcc test.c -o test.exe
.PHONY:clean
clean:
	rm -f test.exe

注意:

  • makefile 的文件名必须是 makefile/Makefile,不能是其他名称,否则 make 识别不了。
  • 依赖文件可以有多个,也可以没有。
  • 依赖方法必须以 [Tab] 键开头,特别注意不能是四个空格。

第三步,编写test.c文件。

 #include<stdio.h>
 int main()
 {
     printf("hello linux\n");                                                                                        
     return 0;
 }

第四步,通过命令看效果。

[jkl@VMCentos7 lesson4]$ make
gcc test.c -o test.exe
[jkl@VMCentos7 lesson4]$ ls
makefile  test.c  test.exe
[jkl@VMCentos7 lesson4]$ ./test.exe
hello linux

2、make原理

在Linux中,输入make命令后,make会在当前目录下找文件名为 "makefile或者Makefile"的文件,1. 如果找到,则会把文件中的第一个目标文件作为最终的目标文件

[jkl@VMCentos7 lesson4]$ ls # 查看当前目录的文件,有一个makefile一个Makefile文件
makefile  Makefile  test.c
[jkl@VMCentos7 lesson4]$ make  # 把第一个文件作为目标文件
gcc test.c -o test.exe    # 执行makefile
[jkl@VMCentos7 lesson4]$ cat makefile
test.exe:test.c
	gcc test.c -o test.exe
.PHONY:clean
clean:
	rm -f test.exe
[jkl@VMCentos7 lesson4]$ cat Makefile
mytest:test.c
	gcc -o mytest test.c

 2. 如果没有找到,则打印提示信息。

[jkl@VMCentos7 ~]$ make
make: *** No targets specified and no makefile found.  Stop. # 没有找到目标文件

3、理解makefile

首先我们需要知道makefile文件中代码所代表的意思,通过下图进行一一解释:

注意:上面我们说了输入make指令出现两种可能,此处只讲解找到最终文件的情况。

当我们在命令行中输入make命令,会默认生成第一个目标文件,即执行第一个依赖方法。

[jkl@VMCentos7 lesson4]$ make # 默认执行第一个依赖方法,并打印出来
gcc test.c -o test.exe
[jkl@VMCentos7 lesson4]$ ls  # 查看当前目录文件,确实生成了可执行程序(目标文件)test.exe
makefile  Makefile  test.c  test.exe

当我们再次输入make命令,会出现以下提示:

[jkl@VMCentos7 lesson4]$ make
make: 'test.exe' is up to date.  # 可执行程序(目标文件)是最新生成的了

1. 为什么再次输入make命令会不让我们继续生成目标文件呢???

因为当有大量的文件的时候,编译执行会消耗大量的时间,为了达到更高的效率,因此源代码没有改变,makefile就会知道只生成一份可执行程序就可以了。

但是此时就有另外的两个问题了,编译器怎么知道哪个文件是没有改变的源代码???如果我们的目的就是想要输入命令则生成目标文件该怎么办???

2. 编译器怎么知道哪个文件是没有改变的源代码???

对比可执行程序最近修改时间与源文件最近修改时间,谁更新?

编写代码和代码生成的可执行程序的修改时间是不一样的,先写的源代码,后才有的代码生成的可执行程序。因此makefile会通过谁的时间更新,来确定到底要不要重新生成可执行程序。通过stat命令可以看到文件的三个时间。

3. 想要输入make命令则生成目标文件该怎么办???

此处可以在每个方法之前输入 .PHONY:xxx,xxx对应的方法总是要执行。xxx可以是目标文件也可以是依赖方法。

举例:想要make总是执行,可以将makefile改成如下内容:

.PHONY:test.exe
test.exe:test.c
    gcc test.c -o test.exe

此时输入make则会生成可执行程序。

4. 我们像VS编译一个程序可以生成解决方案,还可以清理解决方案,我们makefile如何清理解决方案呢???

 清理解决方案的实质是删除可执行程序,那么我们在makefile中提供一个删除文件的依赖方法即可,而且我们可能总是想要删除可执行程序,因此可以加上.PHONY:xxx。

test.exe:test.c
    gcc test.c -o test.exe
.PHONY:clean # 总是执行该依赖关系中的方法
clean:       # 删除可执行程序
    rm -f test.exe

5. 从上面我们可以看到,删除可执行程序是第二个依赖方法,我们前面知道make默认执行第一个依赖方法,那我们想要执行第二个依赖方法应该怎么办呢??

此处需要使用make命令+目标文件,即make clean。 只要不是第一个依赖方法,都是这样执行依赖方法!!!

[jkl@VMCentos7 lesson4]$ ls
makefile  Makefile  test.c  test.exe
[jkl@VMCentos7 lesson4]$ make clean  # 删除可执行程序
rm -f test.exe
[jkl@VMCentos7 lesson4]$ ls  # 确实删除了
makefile  Makefile  test.c

6. 虽然知道了如何执行其他时候的依赖方法,但是此时又有一个问题,如果我执行依赖方法之后不想看到执行的是什么,怎么解决呢???

解决办法是在依赖方法前面加一个@符号,则不会看到执行的内容了。

[jkl@VMCentos7 lesson4]$ cat makefile # 查看文件内容
.PHONY:test.exe
test.exe:test.c
	@gcc test.c -o test.exe  # 依赖方法中有@
.PHONY:clean
clean:
	rm -f test.exe           # 依赖方法中没有@
[jkl@VMCentos7 lesson4]$ make  # 不显示执行的是什么
[jkl@VMCentos7 lesson4]$ ls
makefile  Makefile  test.c  test.exe # 生成了可执行程序
[jkl@VMCentos7 lesson4]$ make clean  # 显示执行的是什么
rm -f test.exe
[jkl@VMCentos7 lesson4]$ ls  # 删除了可执行程序
makefile  Makefile  test.c

 4、优化makefile

前面我们理解了makefile中内容的意义,但是在依赖关系和依赖方法之间的文件名基本是重复的,有没有一种方法让它更简便一些呢???

答案是可以的,此处我们需要介绍几个makefile中一些自动化变量。

$@ : 规则的目标 ,即上面的test.exe

$<   : 规则的第一个依赖,即test.c

$?   : 所有比目标新的依赖的列表

$^   : 所有的依赖的列表,会自动去重  ,即目标后面的多个依赖列表

下面我们则对上面写的makefile文件进行优化:

1.如下为单个依赖关系的举例:

test.exe:test.c
	gcc -o $@ $< # 自动化变量需要在最后面 $@代表test.exe $<表示test.c
.PHONY:clean
clean:
	rm -f test.exe

 2.如下为多个依赖关系的举例:

test.exe:test.c test.h
	gcc -o $@ $^ # 自动化变量需要在最后面 $@代表test.exe $^表示test.c 和 test.h
.PHONY:clean
clean:
	rm -f test.exe

注意:依赖关系以空格间隔!!! 

除了makefile中的自动化变量以外,其实我们还可以自己创建变量

[jkl@VMCentos7 lesson5]$ cat makefile
bin=test.exe # 创建目标文件变量
src=test.c   # 创建被编译文件变量 
 
$(bin):$(src)  # 使用需要加$符号
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f $(bin)

注意:创建变量跟C语言相似,但是不用加类型。 

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

杭州等级保护测评—提升企业安全等级

4月初&#xff0c;在和杭州未来科技城正式签署“重点企业落户协议”之后&#xff0c;新一代本地生活服务平台“AC生活”又获得了由中华人民共和国公安部颁发的“信息系统安全等级保护”备案证书。尽管工作人员一再强调“公司还处在研发期”、“产品还不成熟”&#xff0c;但随着…

2.spring security 简单入门

创建springboot 项目&#xff0c;引入spring security坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--spring security坐标--><dependency&g…

【每日力扣】141. 环形链表与142. 环形链表 II

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 141. 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟…

恶补《操作系统》5_2——王道学习笔记

5.2_1 I-O核心子系统 1、用户层软件 假脱机系统 2、设备独立性软件&#xff08;设备无关性软件&#xff09; IO调度、设备保护、设备分配与回收、缓冲区管理 3、设备驱动程序&#xff08;比如打印机驱动&#xff09; 4、中断处理程序 5、硬件 5.2_2 假脱机技术&#xff…

爬虫工具:避免复制文字收费,VIP。。

step ctrl shift i 打开开发者工具 点击...打开设置勾选禁用JavaScript Principle 事件处理&#xff1a;JavaScript 用于处理用户交互&#xff0c;例如点击、滚动、输入等禁用 JavaScript 后&#xff0c;页面上的所有 JavaScript 代码都将不会执行

基于 Dockerfile 部署 LNMP 架构

目录 前言 1、任务要求 2、Nginx 镜像创建 2.1 建立工作目录并上传相关安装包 2.2 编写 Nginx Dockerfile 脚本 2.3 准备 nginx.conf 配置文件 2.4 生成镜像 2.5 创建 Nginx 镜像的容器 2.6 验证nginx 3、Mysql 镜像创建 3.1 建立工作目录并上传相关安装包 3.2 编写…

FastAPI - Pydantic相关应用

参考链接&#xff1a;Pydantic官方文档 文章目录 定义数据模型创建模型实例数据验证数据转换模型转换模型更新模型配置辅助类Field Pydantic 是一个 Python 库&#xff0c;主要用于数据验证和管理。数据验证是指检查数据是否符合预定的规则和格式&#xff0c;比如检查数据类型是…

c++项目文件夹重命名

文章目录 一、改变项目文件夹名&#xff1f;1. 手动改名2. 自动改名 二、全局替换原文件名的引用1.打开Visual Studio 2022软件 一、改变项目文件夹名&#xff1f; 1. 手动改名 文件名一个一个改挺麻烦的 2. 自动改名 import java.io.File; import java.util.Optional;publi…

leetcode_47.全排列 II

47. 全排列 II 题目描述&#xff1a;给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] …

Optional学习记录

Optional出现的意义 在Java中&#xff0c;我们经常遇到的一种异常情况&#xff1a;空指针异常&#xff0c;在原本的编程中&#xff0c;为了避免这种异常&#xff0c;我们通常会向对象进行判断&#xff0c;然而&#xff0c;过多的判断语句会让我们的代码显得臃肿不堪。 所以在J…

老Java学 Go 笔录(一) 到底为什么要学习 go ?

文章目录 一.到底什么是go ?1.1 历史渊源1.2 优秀特性1.2 应用场景1.3 和 java 有什么不同 二.聊一聊一个 java 的我为什么要学一学 go ?2.1 生活不止眼前苟且,还有诗和远方.但先要苟住2.2 了解一项新技能 三.打算怎么去学3.1 官网大概搂一遍3.2 b 站的学习视频跟着走一回3.3…

经纬度聚类:聚类算法比较

需求&#xff1a; 将经纬度数据&#xff0c;根据经纬度进行聚类 初始数据 data.csv K均值聚类 简介 K均值&#xff08;K-means&#xff09;聚类是一种常用的无监督学习算法&#xff0c;用于将数据集中的样本分成K个不同的簇&#xff08;cluster&#xff09;。其基本思想是…

产品AB测试设计

因为vue2项目升级到vue3经历分享1&#xff0c;vue2项目升级到vue3经历分享2&#xff0c;前端系统升级&#xff0c;界面操作也发生改变&#xff0c;为了将影响降到最低&#xff0c;是不能轻易让所有用户使用新系统的。原系统使用好好的&#xff0c;如果新界面用户不喜欢&#xf…

C语言中字符串输入的3种方式

Ⅰ gets() 函数 gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间 # include <stdio.h> int main(void) {char a[256] {0};gets(a);printf("%s",a);return 0; }Ⅱ getchar() # include <stdio.h> int mai…

【实验】根据docker部署nginx并且实现https

环境准备 systemctl stop firewalld setenforce 0 安装docker #安装依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 #设置阿里云镜像 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #安装最新版…

DSP实时分析平台设计方案:924-6U CPCI振动数据DSP实时分析平台

6U CPCI振动数据DSP实时分析平台 一、产品概述 基于CPCI结构完成40路AD输入&#xff0c;30路DA输出的信号处理平台&#xff0c;处理平台采用双DSPFPGA的结构&#xff0c;DSP采用TI公司新一代DSP TMS320C6678&#xff0c;FPGA采用Xilinx V5 5VLX110T-1FF1136芯片&#xff…

奇偶校验码

目录 前言 校验原理简介 奇偶校验码 前言 在前两个文章的学习中,我们已经知道了数字字符这些简单的数据应该怎么在计算机内部进行表示,其实本质上是0101的二进制代码,但是这些数据在计算机内部进行计算存取和传送的过程中,由于计算机原器件可能会发生故障,也有可能因为某些…

Qt服务器端与客户端交互

Qt做客户端与服务器端交互第一步引入network 第一步引入network后继续编程首先界面设计 创建server和socket 引入QTcpServer&#xff0c;QTcpSocket MainWindow.h代码如下 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QTcpServer&…

STM32入门学习之ADC

1.ADC在STM32进行数据采集时十分重要。通过ADC可以将外界的数字信号转换为模拟信号&#xff0c;以满足采样的需求。(资料参考于正点原子) STM32 拥有 1~3 个 ADC &#xff08; STM32F101/102 系列只有 1 个 ADC &#xff09;&#xff0c;这些 ADC 可以独立使用&#…

《老相册》读后感

外面在下着瓢泼大雨&#xff0c;豆粒大的雨点打在窗户上&#xff0c;发出啪啪的巨响。这样的雨天&#xff0c;是不适宜外出的&#xff0c;最惬意的方式就是一个人待在宿舍里&#xff0c;打开一本书&#xff0c;慢慢地看&#xff0c;静静地想&#xff0c;让所有的烦恼融化在这雨…