手把手教你如何编写一个Makefile文件

2023-11-02

一、概念理解(彩蛋藏在某个地方)

1.1 什么是Makefile?

  • C语言中,我们使用visual studio开发软件时候,写程序开始时候都会创建一个project项目文件,然后在文件里面编译 .h 和 .c 的文件。
  • 在Linux中,有一个叫make的东西,就相当于C语言的集成开发环境,我们只需要在make里面创建文件,写代码,make会帮我们管理这些文件。
  • 不过我们创建的项目不叫project,而是称为Makefile,打开一个make源程序包,发现很多Makefile的文件,说明里面有很多的项目。
  • 在源程序包里面,也有名为makefile的文件(m是小写),两个命名同时存在,这是合理的,在开发一个项目的时候,工程师一般都会命名为Makefile然后打包交给用户,用户觉得某个Makefile需要改动,用户改动后或者新建后的项目定义为makefile,并且在运行时候,先执行makefile,再执行Makefile文件。

【文章福利】小编在群文件上传了一些个人觉得比较好得学习书籍、视频资料,有需要的可以进群【977878001】领取!!!额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)

内核资料直通车:Linux内核源码技术学习路线+视频教程代码资料

学习直通车:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈

1.2 为何使用Makefile?

上面提到需要将我们写的大量项目文件管理起来,这里具体讲讲:

这个树形图展示了一个项目中的层级关系,如果我们需要变动3号文件,会发现,牵一发而动全身,改动一个被迫需要改动一堆,为了解放我们,make中编写Makefile就不再需要考虑这些,你把每个文件的依赖关系以指令的形式说明清楚并且保存下来,改动一个即可,会自动帮你修改关联到的其他文件。

二、实战代码演示与讲解

2.1 没有makefile的项目是怎么创建运行的

2.1.1 创建文件

touch main.c tool1.c tool1.h  tool2.c tool2.h 

使用指令"touch"时,如果指定的文件不存在,则将创建一个新的空白文件。例如,在当前目录下,使用该指令创建一个空白文件"file",输入如下命令:

$ touch file #创建一个名为“file”的新的空白文件**

2.1.2 查看创建的文件

要有优秀的编程习惯,创建完了之后看一下时候创建成功

ls
ls 查看当前目录下的文件,发现成功创建了5个文件。

2.1.3 给创建的文件放一点内容

vim * -p
vim就是进入文本编辑的命令,按键 i 进入编辑模式,Esc退出编辑模式,:wq 保存退出到终端界面
"tool1.h"

#ifndef TOOL1_H__
#define TOOL1_H__
# 声明函数
void mytoo1(void); 

#endif

"tool1.c"

#include <stdio.h>
#incldue "tool1.h"
# 定义函数
void mytool1(void)
{
	printf("tool1 print\n");
}

只需要稍微修改一下 tool2.h 和 tool2.c 的文件就好啦。

"tool2.h"

#ifndef TOOL2_H__
#define TOOL2_H__
# 声明函数
void mytoo2(void); 

#endif

"tool1.c"

#include <stdio.h>
#incldue "tool2.h"
# 定义函数
void mytool2(void)
{
	printf("tool2 print\n");
}

现在还剩下一个主函数main了,测试代码如下

#include <stdio.h>
#include "tool1.h"
#include "tool2.h"

int main(){

	mytool1();
	mytool2();
	
return 0;
}

:wa退出编辑模式(保存所有打开的文件)

2.1.4 编译运行

2.2 有makefile的项目如何创建运行

makeile教学视频

讲前小科普:

2.2.1 删掉自动生成的a.out文件

rm a.out

2.2.2 创建makefile

vim进入编辑模式,系统检测没有名为makefile的文件,会自动创建。

如果自己想自定义一个其他名字,比如makefilebuff-demo,可能在make操作时候会有影响。下面会讲。

接下来的写依赖关系的时候,你可能会疑惑gcc命令的一些参数,nb我已经预判到了,我的这篇文章可以帮你解决一小部分疑惑
Linux——gcc -c -o 等参数的解释.
# 自定义依赖关系,源文件(后缀为.c)经过编译汇编生成目标文件(后缀为.o)
# 目标文件执行生成可执行文件(类似与mytool)
mytool:main.o tool1.o tool2.o
	# 写gcc命令时候,前面要tab按键一下
	# 不写-o参数,生成默认的可执行文件名为a.out,这里我们修改为mytool
	gcc main.o tool1.o tool2.0 -o mytool

main.o:main.c
	#-Wall 可以看到所有的警告
	#-g 可以调试
	#-c 只允许执行到汇编步骤,不允许链接。
	gcc main.c -c -Wall -g -o main.o
tool1.o:tool1.c
	gcc main.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
	gcc main.c -c -Wall -g -o tool2.o

保存退出,然后查看一下目录(好习惯),发现有一个makefile的文件啦。

2.2.3 执行makefile文件

直接使用make命令

科普:如果你的文件名字不是makefile,而是makefilebuff-demo这样自定义的,那么需要这么操作

make -f makefilebuff-demo
make 命令可以通过 -f 执行使用的makefile。
如果在没有使用 -f 指定的情况下,会按照下面的顺序执行。
GNUmakefile, makefile 和 Makefile

2.2.4 查看目录并运行可执行文件

可以看到可执行文件已经是其他颜色了,颜色不同代表这文件权限不同。

(./文件名)运行!

第一阶段就可以完结撒花啦!!!!!

实际上,这里的makefile文件的信息写的并不是十分的规范,有的东西还没有写,有的写的太麻烦。接下来逐步完善一下

三、代码优化

3.1 添加clean信息

_实际上,正如上面介绍的流程我们已经基本处理完了项目,这个时候我修改了某文件代码保存退出后,就需要重新的执行make指令,但是跟第一次不同的是,这次make指令执行后界面如图,不再展示依赖和被依赖关系。

_但是我们还是希望每次执行make,都展示一下依赖和被依赖关系,需要添加 clean 信息

clean:
	# rm 删除指令,删除所有后缀为.o文件,删除mytool这个可执行文件
	# -rf 强制删除并且递归删除,否则的话会一直询问我们是否需要删除
	rm *.o mytool -rf

执行make clean,发现出现了依赖和被依赖的关系

3.2 简化makefile信息

3.2.1 简化第一版

# OBJS   代替  依赖文件
# CC     代替  gcc
# CFLAGS 代替  编译命令

OBJS=main.o tool1.o tool2.o
CC=gcc
CFLAGS=-c -Wall -g

mytool:$(OBJS)
	$(CC) $(OBJS) -o mytool
main.o:main.c
	$(CC) main.c $(CFLAGS)  -o main.o
tool1.o:tool1.c
	$(CC) main.c $(CFLAGS) -o tool1.o
tool2.o:tool2.c
	$(CC) main.c $(CFLAGS) -o tool2.o

clean:
	rm *.o mytool -rf

3.2.2 简化第二版

# $^ 代替 上面的指令
# RM 代替 rm -f
# $@ 代替 目标文件

OBJS=main.o tool1.o tool2.o
CC=gcc
CFLAGS=-c -Wall -g

mytool:$(OBJS)
	$(CC) $^ -o mytool
main.o:main.c
	$(CC) $^ $(CFLAGS)  -o $@
tool1.o:tool1.c
	$(CC) $^ $(CFLAGS) -o $@
tool2.o:tool2.c
	$(CC) $^ $(CFLAGS) -o $@

clean:
	$(RM) *.o mytool -r

这个 $(RM) 运行下来可以看到,替代了 rm和 -f

3.2.3 简化第三版

# 6-11行代码相似性很强,可以提取出一个公式模版
#      %.o:%.c
#	       $(CC) $^ $(CFLAGS)  -o $@
# 百分号相当于一个通配符

OBJS=main.o tool1.o tool2.o
CC=gcc
CFLAGS=-c -Wall -g

mytool:$(OBJS)
	$(CC) $^ -o mytool
%.o:%.c
	$(CC) $^ $(CFLAGS)  -o $@

clean:
	$(RM) *.o mytool -r

四、总结一下

这次从零开始接触makefile,先查阅文本资料简单的接触一下makefile,留下了印象是好难读懂什么意思,痛苦几天后找到和视频资料并且写下了这篇总结,基本上可以对makefile有个较为全面的认识。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手把手教你如何编写一个Makefile文件 的相关文章

  • 如何“grep”连续流?

    可以用吗grep在连续的流中 我的意思是有点tail f
  • Linux下的C#,Process.Start()异常“没有这样的文件或目录”

    我在使用 Process 类调用程序来启动程序时遇到问题 可执行文件的层次结构位于 bin 目录下 而当前工作目录需要位于 lib 目录下 project bin a out this is what I need to call lib
  • Snap-confine 具有提升的权限,并且不受限制,但应该受到限制。拒绝继续避免权限升级攻击

    我已经使用 snap 一段时间了 但最近升级后 当我尝试打开任何应用程序时 出现此错误 Snap confine has elevated permissions and is not confined but should be Refu
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 为什么使用Python的os模块方法而不是直接执行shell命令?

    我试图了解使用Python的库函数执行特定于操作系统的任务 例如创建文件 目录 更改文件属性等 背后的动机是什么 而不是仅仅通过执行这些命令os system or subprocess call 例如 我为什么要使用os chmod而不是
  • 使用netcat将unix套接字传输到tcp套接字

    我正在尝试使用以下命令将 unix 套接字公开为 tcp 套接字 nc lkv 44444 nc Uv var run docker sock 当我尝试访问时localhost 44444 containers json从浏览器中 它不会加
  • 如何从“git log”中查看 Git 中的特定版本?

    My git log显示为 enter code here git trial git log commit 4c5bc66ae50780cf8dcaf032da98422aea6e2cf7 Author king lt email pro
  • 通过 SSH 将变量传递给远程脚本

    我正在通过 SSH 从本地服务器在远程服务器上运行脚本 首先使用 SCP 复制该脚本 然后在传递一些参数时调用该脚本 如下所示 scp path to script server example org another path ssh s
  • 如何在两个不同帐户之间设置无密码身份验证

    我们可以在两台机器的两种不同用途之间设置无密码身份验证吗 例如 计算机A有用户A 计算机B有用户B 我们可以设置密码 ssh 以便计算机 A 上的用户 A 使用其用户帐户 A 登录计算机 B 谢谢你 如果我理解你的问题 你能设置一下吗ssh
  • gdb 错误 - 文件不是可执行格式:无法识别文件格式

    我正在尝试使用 gdb 调试某个名为 xdf 的程序 但是当我运行 gdb xdf 时 出现以下错误 home nealtitusthomas X ray astronomy heasoft 6 24 x86 64 pc linux gnu
  • Linux 文本文件操作

    我有一个格式的文件 a href a href a href a href 我需要选择 之后但 之前的文本 并将其打印在行尾 添加后 例如 a href http www wowhead com search Su a a a a a
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • 使用命令行将 MediaWiki 维基文本格式转换为 HTML

    我倾向于编写大量文档 因此 MediaWiki 格式对我来说很容易理解 而且比编写传统 HTML 节省了我很多时间 然而 我也写了一篇博客 发现一直从键盘切换到鼠标来输入正确的 HTML 标签会增加很多时间 我希望能够使用 Mediawik
  • Bash 脚本 - 迭代 find 的输出

    我有一个 bash 脚本 其中需要迭代 find 命令输出的每一行 但似乎我正在迭代 find 命令中的每个单词 以空格分隔 到目前为止我的脚本看起来像这样 folders find maxdepth 1 type d for i in f
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • 无关的库链接

    我有一个可能有点愚蠢的问题 因为我很确定我可能已经知道答案了 假设你有静态库A 动态共享库B和你的linux下的程序C 假设库 A 调用库 B 中的函数 并且您的程序调用库 A 中的函数 现在假设 C 在 A 中调用的所有函数都不使用 B
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • 确保 config.h 包含一次

    我有一个库项目 正在使用 Linux 中的 autotools 套件移植到该项目 我对自动工具很陌生 本周 我已经了解了其操作的基础知识 我有一个关于如何保留内容的问题config h免遭重新定义 我惊讶地发现生成的config h文件也没
  • 如何从linux命令行运行.exe可执行文件? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 Windows 中有一个 abc exe 可执行文件 我可以使用 DOS 命令提示来执行此应用程序 并为其提供一些运行时变量 我想从
  • touch命令在一个目录下创建多个文件(不同名称)

    我想制作一个在 bash 中创建目录和文件结构的脚本 我尝试过这样的事情 mkdir p 1 2 touch 1 2 a b c a b c 应该是在一个命令或其他命令中创建的文件 但由于某种原因 结构是这样的 current folder

随机推荐

  • Scanvenger游戏制作笔记(九)Unity3D创建声音

    Scanvenger游戏制作笔记 九 Unity3D创建声音 前言 一 在GameManager 上创建audio source 播放背景音乐 二 创建其他声音 三 将audioSource拖入efx source中 四 停止背景音乐 系列
  • springboot中Instant时间传参及序列化

    在部分场景中 后台的时间属性用的不是Date或Long 而是Instant Java8引入的一个精度极高的时间类型 可以精确到纳秒 但实际使用的时候不需要这么高的精确度 通常到毫秒就可以了 而在前后端传参的时候需要对Instant类型进行序
  • Vue教程(二):数据代理和事件处理

    1 数据代理 数据代理 通过obj2操作obj1的对象
  • 写给萌新的mmdet

    写给萌新的mmdet 本文简称mmdetection为mmdet 安装是劝退新入坑的小伙伴的大老虎 一般按照官方readme安装一遍 然后发现运行官方demo报错 网上搜了半天 试了一些奇怪的命令发现没用 只能删除环境 重新再装一遍 然后报
  • QT笔记:QT 窗口关闭 程序进程不退出

    最近在做一个工具用于控制mcu 这其中肯定就需要open端口 所以不能同时打开一个设备 所以在发布程序后 打开设备后关闭QT的UI界面 再次打开程序进行连接设备的时候出现open设备失败的问题 第一次打开设备 关闭应用再次连接设备 后面查看
  • SpringBoot对接小程序微信支付

    目录 前言 一 准备工作 2 1 企业微信小程序开通 2 1 1 获取开发者ID 2 1 2 开通支付功能 2 1 3 关联商户号 2 2 企业商户号的开通 2 2 1 获取商户号mch id 2 2 2 获取商户API密钥mch key
  • I帧、P帧和B帧的特点

    I帧 帧内编码帧 I帧特点 1 它是一个全帧压缩编码帧 它将全帧图像信息进行JPEG压缩编码及传输 2 解码时仅用I帧的数据就可重构完整图像 3 I帧描述了图像背景和运动主体的详情 4 I帧不需要参考其他画面而生成 5 I帧是P帧和B帧的参
  • 李沐论文精读系列三:MoCo、对比学习综述(MoCov1/v2/v3、SimCLR v1/v2、DINO等)

    文章目录 一 MoCo 1 1 导言 1 1 1 前言 1 1 2 摘要 1 1 3 导言 1 2 相关工作 1 2 1 SimCLR 端到端的学习方式 Inva Spread也是 1 2 2 memory bank InstDisc模型
  • MySql下最好用的数据库管理工具是哪个?

    维基上有个很全的列表 https en wikipedia org wiki Comparison of database tools 1 phpmyadmin 用过3 9版 UTF 8 中文不显示 2 HeidiSQL 7 0 不错 以前
  • 关于CoInitialize()

    在msdn中对于CoInitialize的解释如下 Initializes the COM library on the current apartment and identifies the concurrency model as s
  • ADC基本原理

    ADC基本原理 1 ADC即为典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号 2 对于32 1 ADC转换时间 最大转换速率 1us 最大转换速度为1MHz 在ADCCLK 14M 采样周期为1 5个ADC时钟下得到 2
  • f2fs文件系统 CP介绍

    前言 在前面的介绍中 f2fs保证一致性有两种方法 前滚恢复和后滚恢复 前滚恢复需要配合fsync流程使用 先不进行介绍 而后滚恢复就是本章节需要介绍的CheckPoint相关内容 所谓的文件系统一致性 可以简单类比交易操作 即交易双方中一
  • Selenium成长之路-08简单对象定位之class name方法

    class name 的定位方法与tag name 是差不多的 我们直接上代码 还是以百度首页输入框为例来进行演示 从截图中可以看出来 class name 就是 s ipt 下面我们就通过class name元素来进行定位 coding
  • Finding the Control Points of a Bezier Curve

    原文链接 https blog sklambert com finding the control points of a bezier curve Finding the Control Points of a Bezier Curve
  • 【HIT-计算机系统】ICS-Lab4 Buflab/AttackLab

    第1章 实验基本信息 1 1 实验目的 理解C语言函数的汇编级实现及缓冲器溢出原理 掌握栈帧结构与缓冲器溢出漏洞的攻击设计方法 进一步熟练使用Linux下的调试工具完成机器语言的跟踪调试 1 2 实验环境与工具 1 2 1 硬件环境 x64
  • Unity3D开发工程师

    岗位职责 1 完成Unity3D项目架构 2 负责项目相关逻辑开发 3 Unity 3D同PHP数据交互 4 Unity 3D通过javascript与数据库链接 职位要求 1 计算机相关专业 2 熟悉3D图形学 两年以上Unity3D经验
  • 6 种方法部署 TensorFlow2 机器学习模型,简单 + 快速 + 跨平台!

    当你创建或找到了一个完美的机器学习模型时 你一定想在各个平台上都使用到它 比如电脑 网页 移动端 甚至是 Docker 环境中 不但个人如此 在实际工作中 一个优秀的程序员除了要学会构建机器学习模型 也更应该学会将其成功部署 向用户提供便捷
  • Matlab坐标变换篇

    一 安装Robotics System Toolbox 二 弄懂左乘和右乘 介绍的第一个函数为欧拉 齐次矩阵 左手坐标系下 中指对着自己为x轴 z轴为拇指 T0 eul2tr 0 0 0 基坐标系 Tx transl 5 0 0 xyz T
  • linux系统下的ocr软件,Ubuntu下的ocr文字识别(pdf、tif等)

    平时使用扫描件或者pdf查看文档 但是在ipad上当文字比较小的时候不能有效放大 过着每次阅读需要移动屏幕 十分不方便 为此想将pdf或者图片中的文字截取出来 可以有效处理 当然需要ocr技术了 现在我们就来考虑和解决这个问题 1 技术准备
  • 手把手教你如何编写一个Makefile文件

    一 概念理解 彩蛋藏在某个地方 1 1 什么是Makefile C语言中 我们使用visual studio开发软件时候 写程序开始时候都会创建一个project项目文件 然后在文件里面编译 h 和 c 的文件 在Linux中 有一个叫ma