Makefile的基本知识

文章目录

  • 一、使用Makefile 的引入
    • 1.GCC的编译流程
    • 2.Makefile的引入
  • 二、Makefile的语法规则
  • 三、Makefile中的变量
    • 1.全局变量
    • 2.赋值符“=”,“:=”,“?=”区别
  • 四、Makefile中的自动化变量
  • 四、Makefile中伪目标
  • 五、Makefile中条件判断
  • 六、Makefile中函数的使用


一、使用Makefile 的引入

1.GCC的编译流程

1.预处理
2.编译
3.汇编和链接。
💦预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。
💦编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。
💦汇编就是将汇编语言文件编译成二进制目标文件。
💦链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。

2.Makefile的引入

💦使用 GCC 编译器在 Linux 进行 C 语言编译,通过在终端执行 gcc 命令来完成 C 文件的编译,如果工程只有一两个 C 文件还好,需要输入的命令不多,当文件有几十、上百甚至上万个的时候用终端输入 GCC 命令的方法显然是不现实的。
💦如果我们能够编写一个文件,这个文件描述了编译哪些源码文件、如何编译那就好了,每次需要编译工程的时只需要使用这个文件就行了。所以就诞生了工程编译的工具:make,描述哪些文件需要编译、哪些需要重新编译的文件就叫做 Makefile。
💦Makefile 就跟脚本文件一样,Makefile 里面还可以执行系统命令。使用的时候只需要一个 make即可。

二、Makefile的语法规则

💦Makefile作为一个工具,有其自己的语法规则。
在这里插入图片描述
💦举例说明:创建main.c input.c calcu.c input.h calcu.h文件。
main.c

#include "input.h"
#include "calcu.h"
#include <stdio.h>
 int main(int argc, char *argv[])
 {
 int a, b, num;

 input_int(&a, &b);
 num = calcu(a, b);
 printf("%d + %d = %d\r\n", a, b, num);
 }

input.c

#include <stdio.h>
 #include "input.h"

 void input_int(int *a, int *b)
 {
 printf("input two num:");
 scanf("%d %d", a, b);
 printf("\r\n");
 }

calcu.c

 #include "calcu.h"
int calcu(int a, int b)
 {
 return (a + b);
 }

两个.h文件

input.h文件
 #ifndef _INPUT_H
#define _INPUT_H

void input_int(int *a, int *b);
#endif
calcu.h文件
 #ifndef _CALCU_H
 #define _CALCU_H

 int calcu(int a, int b);
 #endif


💦输入编译指令gcc main.c input.c calcu.c -o main此指令编译生成可执行文件main
如下图所示:可以看到编译后是可以正常执行的。
在这里插入图片描述
💦从上图可以看出使用命令编译文件,只需要一行就可以完成编译,但是此时工程只有三个文件,如果有n个文件或者有一个文件被修改了,使用上面的命令编译的时候所有的文件都会重新编译,编译一次所需要的时间就可怕了。
💦所以最好的办法是哪个文件被修改了,就编译这个被修改的文件即可,其它没有修改的文件就不需要再次编译了,为此改变一下我们的编译方法,如果第一次编译工程,我们先将工程中的文件都编译一遍,然后修改了哪个文件就编译哪个文件,命令如下
在这里插入图片描述
💦上述命令前三行分别是将 main.c、input.c 和 calcu.c 编译成对应的.o 文件,所以使用了“-c”选项,“-c”选项是只编译不链接。最后一行命令是将编译出来的所有.o 文件
链接成可执行文件 main。假如我们现在修改了 calcu.c 这个文件,只需要将 caclue.c 这一个文件重新编译成.o 文件,然后在将所有的.o 文件链接成可执行文件即,只需要下面两条命令即可
在这里插入图片描述
💦此时看似解决了修改一个文件或者多个文件修改后编译和链接问题,但如果修改的文件一多,都不记得哪个文件修改过了,然后忘记编译,然后……,为此我们需要这样一个工具:
1、如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。
2、如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。
3、如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且
链接成可执行文件。
所以引出makefile工具,在工程目录下创建名为“Makefile”的文件,文件名一定要叫做==“Makefile”==并且区分大小写的。

main:main.o input.o calcu.o
	gcc main.o input.o calcu.o -o main
main.o:main.c
	gcc -c main.c
input.o:input.c
	gcc -c input.c
calcu.o:calcu.c
	gcc -c calcu.c


clean:
	rm *.o
	rm main

在这里插入图片描述
💦命令解析:冒号前边为生成的目标文件,后边为生成目标的源文件,也就是说冒号后边的文件通过下边的指令生成冒号前的文件。main.o是main.c通过gcc -c main.c 指令生成的。

在这里插入图片描述

三、Makefile中的变量

1.全局变量

💦Makefile 中的变量都是字符串!类似 C 语言中的宏。使用变量将上面的代码修改,修改以后如下所示:

#main:main.o input.o calcu.o
	#gcc main.o input.o calcu.o -o main
	objects=main.o input.o calcu.o
main:$(objects)
	gcc $(objects) -o main
main.o:main.c
	gcc -c main.c
input.o:input.c
	gcc -c input.c
calcu.o:calcu.c
	gcc -c calcu.c


clean:
	rm *.o
	rm main

💦objects是全局变量,代表main.o input.o calcu.o三个文件,注释使用#号

2.赋值符“=”,“:=”,“?=”区别

💦使用“=”在给变量的赋值的时候,变量的真实值取决于它所引用的变量的最后一次有效值,加入@符号不显示执行过程。
在这里插入图片描述
在这里插入图片描述
💦使用“:=”在给变量的赋值的时候,变量的真实值取决于它所引用的变量的第一次有效值,加入@符号不显示执行过程。

在这里插入图片描述
💦使用“?=”赋值符,如果变量 curname 前面没有被赋值,那么此变量就是“?=”后边的值,如果前面已经赋过值了,那么就使用前面赋的值,相当于条件判断,如果前边定义过就是一定义,没有定义就是用条件后边的
在这里插入图片描述
在这里插入图片描述
💦变量追加“+=”
在这里插入图片描述

四、Makefile中的自动化变量

💦在模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生成对应的目标?自动化变量就是完成这个功能的!所谓自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完。
注意:自动化变量只出现在规则的命令中

在这里插入图片描述
💦 7 个自动化变量中,常用的三种: @ 、 @、 @<和$^,我们使用自动化变量来完成上边的例子:

在这里插入图片描述

四、Makefile中伪目标

💦 Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,比如下边代码:main是要生成的目标文件,

main:$(objects)

💦 伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。
比如:只需要执行clean下边的指令

clean:
	rm *.o
	rm main

💦 使用伪目标的目的:主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的。
💦 上述规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean,当我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。如果我们在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的时候,规则因为没有依赖文件,所以目标被认为是最新的,因此后面的 rm 命令也就不会执行,我们预先设想的清理工程的功能也就无法完成。为了避免这个问题,我们可以将 clean 声明为伪目标
代码如下:

.PHONY:clean
clean:
	rm *.o
	rm main

💦 声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行。

五、Makefile中条件判断

💦 Makefile 也同C 语言一样支持条件判断语句,根据不同的情况来执行不同的代码。
在这里插入图片描述

六、Makefile中函数的使用

💦 Makefile 支持函数,类似 C 语言一样,与C语言不同的是,不支持自定义函数,Makefile 中的函数是已经定义好的,可以直接使用。如果有需要可以去网上搜索。

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

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

相关文章

安防监控视频汇聚平台EasyCVR接入海康Ehome设备,设备在线但视频无法播放是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Elastic 线下 Meetup 将于 2024 年 3 月 30 号在武汉举办

2024 Elastic Meetup 武汉站活动&#xff0c;由 Elastic、腾讯、新智锦绣联合举办&#xff0c;现诚邀广大技术爱好者及开发者参加。 活动时间 2024年3月30日 13:30-18:00 活动地点 中国武汉 武汉市江夏区腾讯大道1号腾讯武汉研发中心一楼多功能厅 13:30-14:00 入场 活动流程…

微信小程序获取手机号(Java后端)

最近在做小程序后端的时候&#xff0c;需要拿到手机号进行角色校验&#xff0c;小白也是第一次获取小程序的手机号&#xff0c;所以功能完毕后总结一下本次操作咯。 根据微信小程序官方文档&#xff1a;获取手机号 | 微信开放文档 调用的接口是getPhoneNumber 请求参数 从伤处…

C语言数据结构-二叉树基础练习

繁霜尽是心头血 洒向千峰秋叶丹 目录 二叉树最大的深度 思路 代码展示 单值二叉树 思路 代码展示 相同的树 思路 代码展示 对称二叉树 思路 代码展示 另一颗树的子树 思路 代码展示 二叉树最大的深度 题目链接&#xff1a;二叉树最大的深度 给定一个二叉树 root &#xff0…

osgEarth学习笔记3-第二个Osg QT程序

原文链接 打开QT Creator&#xff0c;新建一个窗口项目。 QT版本如下&#xff1a; 修改pro文件 QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets CONFIG c11 DEFINES QT_DEPRECATED_WARNINGS SOURCES \main.cpp \mainwindow.cpp HEADERS \mainwindow…

释放创造力,Nik Collection 6 by DxO 点亮你的视觉世界

在数字摄影时代&#xff0c;后期处理是提升摄影作品品质的重要环节。而Nik Collection 6 by DxO作为一套优秀的滤镜插件套装&#xff0c;不仅为摄影师提供了丰富的后期处理工具&#xff0c;更让他们能够释放无限的创造力&#xff0c;打造出惊艳的视觉作品。 Nik Collection 6 …

Unity定时播放音乐

一、需求 需要定时在早上8:50&#xff0c;中午12:00&#xff0c;下午13:10定时播放音乐 二、实现步骤 依次在unity创建背景图、主文字提示、时间文字提示、音量控制器及音量文字提示、退出按钮、播放按钮&#xff0c;暂停按钮 在Canvas下创建一个Script脚本&#xff1a;获取…

路由器里如何设置端口映射?

在互联网时代&#xff0c;我们经常需要将内部网络的服务暴露到公网以便其他人访问。直接将内部网络暴露在公网上存在一定的安全风险。为了解决这个问题&#xff0c;我们可以利用路由器里设置端口映射来实现将特定端口的访问请求转发到内部网络的特定设备上。 端口映射的原理 端…

SolidWorks教育版:为何它成为工程教育的优选?

你是否曾经想过&#xff0c;为什么SolidWorks教育版在工程教育中如此受欢迎&#xff1f;作为专业的数码科技博主&#xff0c;今天就来给大家揭秘。首先&#xff0c;我们要明白SolidWorks是一款功能强大的三维CAD软件&#xff0c;广泛应用于机械、汽车、航空等领域。而教育版则是…

从零开始搭建游戏服务器 第四节 MongoDB引入并实现注册登录

这里写目录标题 前言正文添加依赖安装MongoDB添加MongoDB相关配置创建MongoContext类尝试初始化DB连接实现注册功能测试注册功能实现登录逻辑测试登录流程 结语下节预告 前言 游戏服务器中, 很重要的一点就是如何保存玩家的游戏数据. 当一个服务端架构趋于稳定且功能全面, 开发…

Redis部署方式(三)主从模式

在前面单机版的基础上&#xff0c;41为主&#xff0c;30为从。 一、主从搭建 1、主Redis安装 41机器redis主要配置 requirepass redis#!_41 bind 0.0.0.0 port 6379 daemonize yes 2、从redis安装 30机器redis主要配置 requirepass redis#!_30 bind 0.0.0.0 port 6380 da…

【SpringBoot3.x教程04】SpringBoot如何自定义starter

前言&#xff1a;什么是Starter POMs Starter POMs是预配置的依赖集合&#xff0c;旨在提供一种快速的方式来引入和管理Spring及相关技术栈的依赖。每个Starter POM都是针对特定的Spring模块或技术场景设计的。使用Starter POM&#xff0c;开发者只需要添加一个依赖项&#xff…

67、自定义通信帧协议解析

帧格式&#xff1a;方便自定义长度多种帧标识传输 格式规定 帧标识A 类型 备注 A<0x0F 短帧 数据长度1字节 A>0x0F 长帧 数据长度2字节 短帧:帧标识 帧标识取反 帧用户数据字节数 用户数据…用户数据 长帧:帧标识 帧标识取反 帧用户数据字节数(高8位) 帧用户数据字节数…

卸载应用无残留,App Cleaner Uninstaller Pro助你轻松管理Mac

App Cleaner & Uninstaller Pro是一款专为Mac用户设计的强大应用程序清理和卸载工具。这款软件拥有出色的卸载功能&#xff0c;能够彻底删除不再需要的应用程序及其相关文件和数据&#xff0c;确保Mac磁盘空间得到高效释放。同时&#xff0c;其强大的搜索功能可以快速找到与…

机器视觉系统选型-镜头参数

镜头参数&#xff1a; 光圈&#xff1a;光圈是一个用来控制镜头通光量的装置 &#xff0c;表示光圈大小我们是用光圈值&#xff08;F值&#xff09; &#xff0c;如F1.4&#xff0c;F2&#xff0c;F2.8 焦距&#xff08;Focus&#xff09;&#xff1a;透镜中心到其焦点的距离 景…

蓝桥杯刷题(十二)

1.答疑 代码 n int(input()) L [] for i in range(n):a,b,c map(int,input().split())A ab # 进入和答疑时间B abc # 个人总用时L.append([A,B]) L.sort(keylambda x:x[1]) # 个人总用时短的优先 ans tmp 0 # ans为发消息时刻&#xff0c;tmp为前一个人的总用时 for i …

C++ —— 类和对象(终)

目录 1. 日期类的实现 1.1 前置 和 后置 重载 1.2 >> 和 << 的重载 2. const 成员 3. 取地址及const取地址操作符重载 4. 再谈构造函数 4.1 构造函数体赋值 4.2 初始化列表 4.3 隐式类型转换 4.4 explict 关键字 5. static 成员 5.1 概念 5.2 特性 …

最新梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码下载

最新梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码下载 梨花带雨播放器基于thinkphp6开发的XPlayerHTML5网页播放器前台控制面板,支持多音乐平台音乐解析。二开内容:修复播放器接口问题,把接口本地化,但是集成外链播放器接口就不本地化了,我花钱找人写的理解下…

iOS图片占内存大小与什么有关?

1. 问&#xff1a;一张图片所占内存大小跟什么有关&#xff1f; 图片所占内存大小&#xff0c;与图片的宽高有关 我们平时看到的png、jpg、webp这些图片格式&#xff0c;其实都是图片压缩格式。通过对应的算法来优化了大小以节省网络传输与本地保存所需的资源。 但是当我们加…

vant4中如何修改Dialog弹框内容的字体大小

最近在开发一个移动端的需求&#xff0c;用的UI组件库是vant4 简单地总结一下&#xff0c;如何修改Dialog弹框内容的字体大小 我们先看一下Dialog弹框简单的使用 import { showConfirmDialog } from vant;showConfirmDialog({title: 标题,message:如果解决方法是丑陋的&#…