Makefile 保姆级使用教程

news2025/1/11 18:46:55

目录

Makefile 规则

Makefile的使用介绍

make 命令的使用

即时变量、延时变量介绍和使用

使用make命令编译多个文件

假想目标

常用函数

1.$(foreach var,list,text)

2.$(wildcard pattern)

3.$(filter pattern...,text)

4.$(filter-out pattern...,text)

5.$(patsubst pattern,replacement,text)

通用 Makefile 的设计思想

1.怎么编译子目录? 进入子目录编译:

2.怎么编译当前目录中的文件?

3.当前目录下的.o 和子目录下的 built-in.o 要打包起来:


Makefile 规则

一个简单的 Makefile 文件包含一系列的“规则”,其样式如下:

目标(target)…: 依赖(prerequiries)…

<tab>命令(command)

目标(target)通常是要生成的文件的名称,可以是可执行文件或OBJ文件, 也可以是一个执行的动作名称,诸如‘ clean ’。

依赖是用来产生目标的材料(比如源文件),一个目标经常有几个依赖。

命令是生成目标时执行的动作,一个规则可以含有几个命令,每个命令占一 行。 

注意

每个命令行前面必须是一个 Tab 字符,即命令行第一个字符是 Tab。这是容易出错的地方。

通常,如果一个依赖发生了变化,就需要规则调用命令以更新或创建目标。 但是并非所有的目标都有依赖,例如,目标“ clean ”的作用是清除文件,它 有依赖。

规则一般是用于解释怎样和何时重建目标。make 首先调用命令处理依赖, 进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一 个动作,即打印提示信息。

一个 Makefile 文件可以包含规则以外的其他文本,但一个简单的 Makefile 文件仅仅需要包含规则。虽然真正的规则比这里展示的例子复杂,但格式是完全一样的

Makefile的使用介绍

在 Linux 中使用 make 命令来编译程序,特别是大程序

make 命令所执行的动作依赖于 Makefile 文件。最简单的 Makefile 文件如下:

将上述 4 行存为 Makefile 文件(注意必须以 Tab 键缩进第 2、4 行,不能以空格键缩进),放入 01_hello 目录下,然后直接执行 make 命令即可编译程序,执行 “make clean”即可清除编译出来的结果。

make 命令根据文件更新的时间戳来决定哪些文件需要重新编译,这使得可以避免编译已经编译过的、没有变化的程序,可以大大提高编译效率。

使用touch命令可以改变文件更新的时间

make 命令的使用

make 命令的使用:

执行 make 命令时,它会去当前目录下查找名为“Makefile”的文件,并根 据它的指示去执行操作,生成第一个目标。

我们可以使用“ -f ”选项指定文件,不再使用名为“Makefile”的文件,比 如:

我们可以使用“ -C ”选项指定目录,切换到其他目录里去,比如:

我们可以指定目标,不再默认生成第一个目标:

即时变量、延时变量介绍和使用

A = xxx // 延时变量

B ?= xxx // 延时变量,只有第一次定义时赋值才成功;如果曾定义过,此赋值无效

C := xxx // 立即变量

D += yyy // 如果 D 在前面是延时变量,那么现在它还是延时变量;// 如果 D 在前面是立即变量,那么现在它还是立即变量

例如:

使用make命令编译多个文件

%通配符

  • %.o:表示所用的.o文件%.
  • %.c:表示所有的.c文件

$@:表示目标

$<:表示第一个依赖文件   

$^:表示所有依赖文件

示例:

假想目标

我们的 Makefile 中有这样的目标:

clean:

        rm -f $(shell find -name "*.o")

        rm -f $(TARGET)

如果当前目录下恰好有名为“clean”的文件,那么执行“ make clean ”时它 就不会执行那些删除命令。

这时我们需要把“ clean ”这个目标,设置为“假想目标”,这样可以确保执行“ make clean ”时那些删除命令肯定可以得到执行。

使用下面的语句把“clean”设置为假想目标:

.PHONY : clean

示例:

常用函数

1.$(foreach var,list,text)

简单地说,就是 for each var in list, change it to text。对 list 中的每一个 元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。

2.$(wildcard pattern)

pattern 所列出的文件是否存在,把存在的文件都列出来。

3.$(filter pattern...,text)

把 text 中符合 pattern 格式的内容,filter(过滤)出来、留下来。

4.$(filter-out pattern...,text)

把 text 中符合 pattern 格式的内容,filter-out(过滤)出来、扔掉。

5.$(patsubst pattern,replacement,text)

寻找' text '中符合格式' pattern '的字,用' replacement '替换它们。

' pattern '和' replacement '中可以使用通配符。

示例:

通用 Makefile 的设计思想

在 Makefile 文件中确定要编译的文件、目录,比如:

obj-y += main.o

obj-y += a/

“Makefile”文件总是被“Makefile.build”包含的。

在 Makefile.build 中设置编译规则,有 3 条编译规则:

1.怎么编译子目录? 进入子目录编译:

$(subdir-y):

        make -C $@ -f $(TOPDIR)/Makefile.build

2.怎么编译当前目录中的文件?

%.o : %.c

        $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<

3.当前目录下的.o 和子目录下的 built-in.o 要打包起来:

built-in.o : $(cur_objs) $(subdir_objs)

        $(LD) -r -o $@ $^

顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:

$(TARGET) : built-in.o

         $(CC) $(LDFLAGS) -o $(TARGET) built-in.o

示例:

本程序的Makefile分为3类:
1. 顶层目录的Makefile
2. 顶层目录的Makefile.build
3. 各级子目录的Makefile

一、各级子目录的Makefile:
   它最简单,形式如下:

EXTRA_CFLAGS  := 
CFLAGS_file.o := 

obj-y += file.o
obj-y += subdir/


   "obj-y += file.o"  表示把当前目录下的file.c编进程序里,
   "obj-y += subdir/" 表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
   "EXTRA_CFLAGS",    它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置
   "CFLAGS_xxx.o",    它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置

注意: 
1. "subdir/"中的斜杠"/"不可省略
2. 顶层Makefile中的CFLAGS在编译任意一个.c文件时都会使用
3. CFLAGS  EXTRA_CFLAGS  CFLAGS_xxx.o 三者组成xxx.c的编译选项

二、顶层目录的Makefile:
   它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,
   主要是定义工具链前缀CROSS_COMPILE,
   定义编译参数CFLAGS,
   定义链接参数LDFLAGS,
   这些参数就是文件中用export导出的各变量。

三、顶层目录的Makefile.build:
   这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o

 

四、怎么使用这套Makefile:
1.把顶层Makefile, Makefile.build放入程序的顶层目录
   在各自子目录创建一个空白的Makefile

2.确定编译哪些源文件
   修改顶层目录和各自子目录Makefile的obj-y : 
    obj-y += xxx.o
    obj-y += yyy/
    这表示要编译当前目录下的xxx.c, 要编译当前目录下的yyy子目录    

3. 确定编译选项、链接选项
   修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项;
   修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项;
   
   修改各自子目录下的Makefile:
   "EXTRA_CFLAGS",    它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置
   "CFLAGS_xxx.o",    它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置
   
4. 使用哪个编译器?
   修改顶层目录Makefile的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-)
   
5. 确定应用程序的名字:
   修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字

6. 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除
   
   

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

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

相关文章

【每日一题】最大单词长度乘积

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;转态压缩 写在最后 Tag 【位运算-状态压缩】【字符串】【2023-11-06】 题目来源 318. 最大单词长度乘积 题目解读 找出英文字符串数组中两个字符串长度乘积的最大值&#xff0c;并且这两个字符串不含公共字母。 解题…

Day21力扣打卡

打卡记录 在树上执行操作以后得到的最大分数&#xff08;树状DP&#xff09; 链接 大佬的题解 class Solution { public:long long maximumScoreAfterOperations(vector<vector<int>> &edges, vector<int> &values) {vector<vector<int>…

更强的端点控制如何保护系统和数据

端点——员工日常使用的笔记本电脑、设备和工作站——正在成为网络攻击者的目标。 如果他们可以仅通过一个端点访问组织的系统&#xff0c;那么他们就拥有一个启动板&#xff0c;可以从该启动板在网络上横向移动&#xff0c;以窃取数据或植入勒索软件等。 他们甚至可以提升权…

基于白冠鸡算法的无人机航迹规划-附代码

基于白冠鸡算法的无人机航迹规划 文章目录 基于白冠鸡算法的无人机航迹规划1.白冠鸡搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用白冠鸡算法来优化无人机航迹规划。 1.白冠鸡…

Java与Redis的集成

目录 一、Java连接Redis 1.1 导入依赖 1.2 Redis服务器准备 1.3 建立连接 二、Java操作Redis的常见类型数据存储 2.1 String&#xff08;字符串&#xff09;存取值操作 2.1.1 指定存储数据的数据库与存储入库操作 2.1.2 存储数据的修改与查询 2.1.3 数据临时存储 2.2…

Python unittest单元测试框架 TestSuite测试套件

TestSuite 测试套件简介 对一个功能的验证往往是需要很多多测试用例&#xff0c;可以把测试用例集合在一起执行&#xff0c;这就产生了测试套件TestSuite 的概念&#xff0c;它是用来组装单个测试用例&#xff0c;规定用例的执行的顺序&#xff0c;而且TestSuite也可以嵌套Tes…

AI芯片架构体系综述:芯片类型CPU\GPU\FPGA\ASIC以及指令集CSIS\RISC介绍

大模型的发展意味着算力变的越发重要&#xff0c;因为大国间科技竞争的关系&#xff0c;国内AI从业方在未来的一段时间存在着算力不确定性的问题&#xff0c;与之而来的是许多新型算力替代方案的产生。如何从架构关系上很好的理解计算芯片的种类&#xff0c;并且从计算类型、生…

FastBond2阶段2——基于ESP32C3开发的简易IO调试设备

1. 项目介绍 之前买了许多国产单片机esp32c3一直在吃灰&#xff0c;没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动&#xff0c;刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器&#xff08;单片机开发测试领域&#xff09;&#xff0c;或者用于国…

虚拟机项目部署与发布

目录 一.单机项目 1.1. 本机测试 1.2.部署 二.前后端 3.1.准备 3.2.部署 今天就到这里了哦&#xff0c;希望能帮到你哦&#xff01;&#xff01;&#xff01; 一.单机项目 当我们拿到已开发完的项目后&#xff0c;首先需要在我们自己的主机上进行测试&#xff0c;开发完的…

【Shell脚本4】Shell 传递参数

Shell 传递参数 我们可以在执行 Shell 脚本时&#xff0c;向脚本传递参数&#xff0c;脚本内获取参数的格式为&#xff1a;$n。n 代表一个数字&#xff0c;1 为执行脚本的第一个参数&#xff0c;2 为执行脚本的第二个参数&#xff0c;以此类推…… 以下实例我们向脚本传递三个…

持续集成交付CICD:安装Jenkins Slave(从节点)

目录 一、实验 1.安装Jenkins Slave 二、问题 1.salve节点启动jenkins报错 2.终止命令行jenkins节点状态丢失 一、实验 1.安装Jenkins Slave&#xff08;从节点&#xff09; &#xff08;1&#xff09;查看jenkins版本 Version 2.414.2 (2) 添加节点 系统设置&#xf…

c++ 信息学奥赛 2047:【例5.16】过滤空格

#include<cstdio> using namespace std; char st[200]; int main() { while (scanf("%s",&st)1)printf("%s ",st); //%s 后要有一个空格&#xff0c;不能省略return 0; } 解析&#xff1a;本题中使用一个技巧&#xff0c;那就是scanf函数…

Redis原理到常用语法基础图文讲解

在初期&#xff0c;已经讲述了Redis安装问题。现在正式进入Redis的入门阶段 系统架构的演进 传统单机架构 一台机器运行应用程序、数据库服务器 现在大部分公司的产品都是这种单机架构。因为现在计算机硬件发展速度很快&#xff0c;哪怕只有一台主机&#xff0c;性能也很高…

多种循环法打印乘法表

1 问题 使用多种循环法打印乘法表&#xff0c;有助于巩固夯实循环的语法及用法。 使用for-for、for-while、while-for方法实现乘法表。 2 方法 &#xff08;1&#xff09;for-for:使用两个for.. in..来实现乘法表。 &#xff08;2&#xff09;for-while:使用一个for语句再一个w…

C++前缀和算法的应用:最大化城市的最小供电站数目

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 二分法 题目 给你一个下标从 0 开始长度为 n 的整数数组 stations &#xff0c;其中 stations[i] 表示第 i 座城市的供电站数目。 每个供电站可以在一定 范围 内给所…

强化学习中策略的迭代

一、策略迭代 一旦使用vπ改善了策略π&#xff0c;产生了更好的策略π0&#xff0c;我们就可以计算vπ0并再次对其进行改进&#xff0c;产生更好的π00。因此&#xff0c;我们可以获得一系列单调改善的策略和值函数&#xff1a; 其中E−→表示策略评估&#xff0c;I−→表示策…

[云原生1. ] Docker 的安全及日志管理

文章目录 1. Docker自身存在的安全问题1.1 Docker 自身漏洞1.2 Docker 源码问题 2. Docker 架构缺陷与安全机制2.1 容器之间的局域网攻击2.2 DDoS 攻击耗尽资源2.3 有漏洞的系统调用2.4 共享root用户权限 3. Docker 安全基线标准3.1 docker容器使用安全注意点&#xff1a;3.1.1…

【Spring Boot 源码学习】JedisConnectionConfiguration 详解

Spring Boot 源码学习系列 JedisConnectionConfiguration 详解 引言往期内容主要内容1. RedisConnectionFactory1.1 单机连接1.2 集群连接1.3 哨兵连接 2. JedisConnectionConfiguration2.1 RedisConnectionConfiguration2.2 导入自动配置2.3 相关注解介绍2.4 redisConnectionF…

3.26每日一题(线性非齐次的特解如何设)

1、非齐次方程有e的2x次幂&#xff1a;特解也有e的2x次幂 2、e的2x次幂前面有特殊的一元方程&#xff1a;特解要设为一般的特征方程&#xff08;axb&#xff09; 3、求线性齐次特征方程的特征根&#xff1b; 4、判断e的 rx 次幂中的 r 和特征根有没有重合的个数&#xff1a;…

vue3的自定义指令

除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外&#xff0c;Vue 还允许你注册自定义的指令 (CustomDirectives)。 1.自定义指令的目的和简单介绍 自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。 一个自定义指令由一个包含类似组件生命周期钩子的对象…