Makefile的入门学习

news2024/11/22 5:38:10

一、Makefile的入门学习

编译工具及构建工具介绍

在之前的课程,都是直接使用gcc对代码进行编译,这对简单的工程是可以的,但当我们遇到复杂的工程时,每次用gcc等编译工具去操作就会显得很低效。因此make工具就出现了, make的出现是为了解决手动编译和链接大型工程的问题,它可以避免重复的工作,提高效率,保证正确性。make工具就根据makefile中的命令进行编译和链接的。但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改,因此更高级的一些构建系统或者工具工具像cmake、qmake、ninja和auto make就出现了,它们可以根据一些配置文件来自动化编译和链接软件项目。

在这里插入图片描述

  • cmake是一个跨平台的构建系统,它可以根据CMakeLists.txt中的指令来生成不同平台和工具的工程文件,例如Makefile、Visual Studio解决方案、Ninja文件等。cmake可以支持多种语言和多种架构,它还提供了一些高级功能,如测试、打包、安装等。
  • qmake是一个用于Qt项目的构建系统,它可以根据.pro或.pri中的指令来生成Makefile或其他形式的工程文件。
  • ninja是一个小巧而快速的构建工具,它可以根据ninja.build中的规则来执行编译和链接命令。ninja主要关注于性能和效率,它可以利用多核处理器和并行处理来加速构建过程。ninja通常不需要用户直接编写配置文件,而是由其他构建系统(如cmake)来生成。
  • auto make是一个用于生成Makefile.in文件的工具,Makefile.in是一种用于auto conf的配置文件格式,auto conf是一个用于生成configure脚本的工具。configure脚本是一个用于检测系统环境并生成最终的Makefile文件的脚本Makefile.am是一种用于auto make的配置文件格式,它包含了一些指令和变量,用于定义程序或库的源文件、目标文件、依赖关系和编译选项等。
  • make是一个经典而通用的构建工具,它可以根据Makefile中的规则来执行编译和链接命令。make可以支持多种平台和工具,它还提供了一些高级功能,如条件判断、函数调用、模式匹配。

二.Makefile的简单讲解

  1. 编译的四个阶段

    回顾下编译的四个过程:预处理(Pre-Processing)、编译(Compiling)、汇编 (Assembliang)、链接(Linking)。

    在这里插入图片描述

  2. Makefile的规则

    TARGET....: prerequisites...
    <tab缩进>command
    <tab缩进>...
    <tab缩进>...
    

    TARGET 也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签( Label),对于标签这种特性,在后续的讲“伪目标”中会有叙述。prerequisites 就是,要生成那个 target 所需要的文件或是目标。command 也就是 make 需要执行的任意shell命令。

    Makefile一个示例:

    #这是一个Makefile
    debug:
    	@echo "hello world"
    

    Makefile采用#进行一行注释,采用\作为续行符。make后,打印hello world@的作用是不打印echo指令本身。

    如果,我们要编译下面这个最简单的例子:

    #include <stdio.h>
    int main(int argc, char *argv[])
    {
    	printf("hello world!\n");
    	return 0
    }
    

    Makefile修改如下:

    debug :
    	@echo "hello world"
    
    hello :
    	gcc -o hello hello.c
    
    clean :
    	@rm -f hello
    
    .PHONY: clean
    

    在终端只输入make,执行第一个命令即make debugmake hello相当于在终端输入gcc -o hello hello.c,同理make clean相当于在终端输入rm -f hello

    .PHONY伪目标,如果一个目标和一个实际文件同名,那么make会认为该目标已经是最新的,不需要重新生成,也不会执行其命令。通过将目标声明为伪目标,可以避免这种情况,强制执行其命令。

  3. 变量赋值和预定义变量

    Makefile中的变量赋值运算符有四种,分别是=:=?=+=

    • = 表示延迟展开赋值,即变量的值是在使用时才确定,可能会受到后面的赋值影响。
    • := 表示直接赋值,即变量的值是在定义时就确定,不会受到后面的赋值影响。
    • ?= 表示条件赋值,即只有当变量没有被赋值时,才使用等号后面的值作为变量的值。
    • += 表示追加赋值,即将等号后面的值追加到变量原来的值之后,形成一个新的值。
    • $@ 表示生成的目标文件;$^ 表示所有的依赖文件;$< 代表第一个依赖文件。

    示例:

    TARGET = hello
    CC := gcc
    TARGET1 := $(CC) $(TARGET)#'='为延迟赋值 ':='为立即赋值
    CC ?= g++# "?=" 表示如果前面没有定义CC,就定义为g++,如果定义了CC,就不定义了
    CC += -g#'+='为追加。在CC后面追加-g
    
    $(TARGET): hello.c
    	$(CC) -o $@ $^
    
    compile: $(TARGET)
    
    clean:
    	@rm -rf $(TARGET_DIR)
    
    .PHONY: clean compile
    

    make compile编译的结果为gcc -g -o hello hello.c

三.Makefile的一些常见函数

Makefile函数的基本格式是: ( ) 或者是 ( )或者是 ()或者是{ },其中,是函数名,是函数的参数,参数之间要用逗号分隔开,参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号或者大括号。

  1. wildcard 通配符

    Makefile中的wildcard 是一个函数,用于扩展通配符,返回与通配符匹配的文件列表。通配符是一种特殊的字符,可以表示多个文件名或目录名,常见的通配符有 * 和 ?,分别表示任意长度的任意字符和单个任意字符。格式如下:

    #格式:$(wildcard argments)
    #示例:
    SRC = $(wildcard src/*.c)
    #SRC赋值为src目录中的所有.c文件
    
  2. shell

    shell为在终端执行后面的命令并返回结果。

    #格式:$(shell <cmd> <args>)
    #示例:
    SRC = $(shell find . -name *.c)
    #找到当前文件下的所有.c文件
    
  3. patsubst替换函数

    #格式:$(patsubst pattern,replacement,text)
    #`patsubst`将text中的pattern全部替换为replacement,pattern和replacement可以包含%通配符。
    #示例:
    SRC = $(wildcard src/*.c)
    OBJ = $(patsubst %.c,%.o,$(SRC))
    #将SRC中的所有.c文件替换为.o文件
    
  4. subst替换函数

    #格式:$(subst from,to,text)
    #subst和patsubst类似,是将text中的from替换为to,并返回修改后的字符串。
    #示例:
    $(subst ee,EE,feet on the street)
    #返回结果:fEEt on the strEEt
    
  5. dir

    #格式:$(dir NAMES...)
    #dir函数是一个用于从文件名序列中提取目录部分的函数。
    #示例:
    SRC = $(wildcard ./src/*.c)
    OBJ = $(subst .c,,$(SRC))
    TARGET := $(patsubst ./src/%,./obj/%,$(subst .c,,$(SRC)))
    TARGET_DIR = $(dir $(TARGET))
    #SRC为src目录下的所有.c文件,OBJ为将SRC的结果去掉.c,TARGET将OBJ的结果的目录从src变为obj,最后通过TARGET_DIR得到TARGET中的目录,即:./obj/
    
  6. suffix

    #格式:$(suffix <names...>)
    #suffix为从文件名序列中取出各个文件名的后缀,返回文件名序列的后缀序列,如果文件没有后缀,则返回空子串。
    #示例:
    $(suffix ./src/foo.c ./src-1.0/bar.c hacks)
    #返回结果:.c .c
    
  7. basename

    #格式:$(basename <names...>)
    #从文件名序列中取出各个文件名的前缀部分,返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
    #示例:
    $(basename ./src/foo.c ./src-1.0/bar.c hacks)
    #返回结果:./src/foo ./src-1.0/bar hacks
    
  8. addsuffix

    #格式:$(addsuffix <suffix>,<names...>)
    #把后缀加到每个单词后面,返回加过后缀的文件名序列。
    #示例:
    $(addsuffix .c,foo bar)
    #返回结果:foo.c bar.c
    
  9. addprefix

    #格式:$(addprefix <prefix>,<names...>)
    #把后缀加到每个单词后面,返回加过后缀的文件名序列。
    #示例:
    $(addprefix src/,foo bar)
    #返回结果:src/foo src/bar
    
  10. foreach循环函数

    #格式:$(foreach <var>,<list>,<text>)
    #把list中使用空格分割的单词依次取出并赋值给变量var, 然后执行text表达式。
    #示例:
    #$(I_FLAGS)可以-I包含INCLUDE里的库
    INCLUDE = /usr/inclue \
    			/usr/local/inclue
    I_FLAGS := $(foreach var,$(INCLUDE),-I$(var))
    @echo $(I_FLAGS)
    #输出结果:-I/usr/include -I/usr/local/include
    
  11. 条件判断

    • ifeq/ifneq语句:

      #ifeq语句:判断参数是否相等,相等为true,否则是false。
      ifeq (arg1, arg2)
          #arg1 arg2 相等执行这里的语句
      else
          #arg1 arg2 不相等执行这里的语句
      endif
      
      #ifneq语句:判断参数是否不等,不等为true,否则为false。
      ifneq (arg1, arg2)
          #arg1 arg2 不相等执行这里的语句
      else
          #arg1 arg2 相等执行这里的语句
      endif
      
    • ifdef/ifndef语句:

      #ifdef语句:判断参数是否有值,有值为true,否则是false。
      ifdef var
          #如果定义了var,执行这里的内容
      else
          #如果没定义var,执行这里的内容
      endif
      
      #ifndef:判断参数是否没有值,没有值为true,否则为false。
      infdef var
          #如果没定义var,执行这里的内容
      else
          #如果定义var,执行这里的内容
      endif
      

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

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

相关文章

Linux高级进阶-ssh配置

Ubuntu-system 允许使用root远程登陆 apt install ssh -y在/etc/ssh/sshd_config 文件修改PermitRootLogin yes systemctl restart ssh远程连接软件用户名为root

Linux——内存管理代码分析

虚空间管理 页框和页的关系 页框 将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个页框&#xff0c;也叫页帧&#xff0c;即物理页面&#xff0c;是linux划分内存空间的结果。 每个页框都有一个页框号&#xff0c;即内存块号、物理块号。 页 将用户…

【LeetCode 滑动窗口】LC_3_无重复字符的最长子串

文章目录 1. 无重复字符的最长子串 1. 无重复字符的最长子串 题目链接&#x1f517; &#x1f34e;题目思路&#xff1a;&#x1f427;① 滑动窗口的思想&#xff1b;&#x1f427;② 用什么来维护窗口呢 &#xff1f; 用 双指针 和 unordered_set来维护&#xff0c;为什么呢…

《大道平渊》· 玖 —— 把高深的道理讲的通俗,这是一门艺术。

《平渊》 玖 "化繁为简, 点石成金。" 把高深的道理讲得通俗&#xff0c;这是一门艺术&#xff01; 讲述者能够站在群众的角度&#xff0c;用尽可能简单通俗的语言来解释复杂的概念。 讲述者需要对概念有深刻的理解&#xff0c;还要有灵活的表达能力。 群众愿意接受…

新型航标驱鸟器:解决鸟粪污染问题

航标作为船舶航行的重要导向标志&#xff0c;承载着为各类水上活动提供安全信息的重任。近年来&#xff0c;随着环保意识的提升&#xff0c;鸟类种群数量的增加&#xff0c;航标船上的鸟类问题逐渐凸显。许多鸟类会在航标船上停歇、捕食&#xff0c;造成了航标船严重的鸟粪污染…

【实战】kafka3.X kraft模式集群搭建

文章目录 前言kafka2.0与3.x对比准备工作JDK安装kafka安装服务器增加hosts 修改Kraft协议配置文件格式化存储目录 启动集群停止集群测试Kafka集群创建topic查看topic列表查看消息详情生产消息消费消息查看消费者组查看消费者组列表 前言 相信很多同学都用过Kafka2.0吧&#xf…

redis安裝启动

1、下载redis解压 https://github.com/tporadowski/redis/releases 2、打开cmd&#xff0c;切换到解压的文件夹 3、redis-server.exe redis.windows.conf 启动redis redis可通过命令行输入config set requirepass password和直接修改redis.config文件中修改 requirepass 来设…

打破信息孤岛,U-Mail邮件系统轻松集成各类业务系统

随着国家大力推动企业数字化转型&#xff0c;企业内部数字化建设需要各种业务系统来提高企业生产力&#xff0c;然而&#xff0c;随着在业务数据量逐步增大的情形下&#xff0c;如何更加高效地整合、协同各个系统之间的信息交互&#xff0c;并且更好地融合企业邮件系统&#xf…

Visual Studio Code 开发esp8266流程2Arduino 配置 nodemcu

http://arduino.esp8266.com/stable/package_esp8266com_index.json http://arduino.esp8266.com/stable/package_esp8266com_index.json Arduino: Library Manager Arduino: Board

项目:基于httplib/消息队列负载均衡式在线OJ

文章目录 写在前面关于组件开源仓库和项目上线其他文档说明项目亮点 使用技术和环境项目宏观结构模块实现compiler模块runner模块compile_run模块compile_server模块 基于MVC结构的OJ服务什么是MVC&#xff1f;用户请求服务路由功能Model模块view模块Control模块 写在前面 关于…

UV胶为什么会开裂?如何避免UV胶开裂?

UV胶为什么会开裂&#xff1f;如何避免UV胶开裂&#xff1f; UV胶开裂可能由以下几个主要因素导致&#xff1a; 紫外线照射不足&#xff1a;UV胶的固化需要足够的紫外线能量。如果紫外线照射不足&#xff0c;胶水可能无法完全固化&#xff0c;导致开裂。这可能是由于固化设备…

数据挖掘与机器学习——聚类算法

目录 无监督学习 聚类算法 概念&#xff1a; 功能&#xff1a; 应用场景&#xff1a; 评判标准&#xff1a; 划分聚类&#xff1a; K-means聚类 逻辑实现&#xff1a; 聚类方式 问题&#xff1a; 解决&#xff1a; 可能存在的问题&#xff1a; 1.初始值对K-means聚…

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第10章——实数

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 10. 实数(The Real Numbers) 本章介绍比率数(rational numbers)和非比数(irrational numbers)及其与十进制展开的关系。讨论了实数的公理&#xff0c;并解释了完备性公理对于区分实数和比率数为何必不可少&…

【设计模式】JAVA Design Patterns——Monitor(监视器模式)

&#x1f50d;目的 主要目的是为多个线程或进程提供一种结构化和受控的方式来安全地访问和操作共享资源&#xff0c;例如变量、数据结构或代码的关键部分&#xff0c;而不会导致冲突或竞争条件。 &#x1f50d;解释 通俗描述 监视器模式用于强制对数据进行单线程访问。 一次只允…

体育器材管理系统(Java+MySQL)

技术栈 Java语言&#xff1a;作为主要编程语言&#xff0c;用于编写应用逻辑和界面交互。MySQL数据库&#xff1a;用于存储和管理体育器材的相关数据。Swing窗口视图&#xff1a;用于创建图形用户界面&#xff0c;使用户能够通过窗口进行操作&#xff08;GBK编码&#xff09;。…

MongoDB-4.2.1 之安装和使用

安装 下载安装包 我自己电脑是 Windows7 的老古董&#xff0c;所以就下载老版本的 MongoDB。 mongodb: https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.1.zip 解压安装包到指定路径 我解压到的 C 盘 C:\mongodb-4.2.1 添加环境变量 创建数据库和…

【AIGC X UML 落地】通过多智能体实现自然语言绘制UML图

前天写了篇博文讲到用PlantUML来绘制C类图和流程图。后台有读者留言&#xff0c;问这步能否自动化生成&#xff0c;不想学习 PlantUML 语法。 我想了下&#xff0c;发现这事可行&#xff0c;确实可以做到通过自然语言的描述就能实现 UML图的绘制&#xff0c;昨天晚上加了个班到…

HCIP-Datacom-ARST自选题库_10_其他判断【23道题】

1.端到端时延等于路径上所有处理时延与队列时延之和。 2.部署PPP Multilink之后&#xff0c;数据将根据源地址和目的地址均匀的分配在各条成员链路上。 3.流镜像分为本地流镜像和远程流镜像两种方式。√ 4.IP报文中用Tos字段进行Q0S标记&#xff0c;Tos字段中是使用前6bit来…

《日均70亿请求项目实战》之部署三台zookeeper集群

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

HOW - vscode 使用指南

目录 一、基本介绍1. 安装 VS Code2. 界面介绍3. 扩展和插件4. 设置和自定义 二、常用界面功能和快捷操作&#xff08;重点&#xff09;常用界面功能快捷操作 三、资源和支持 Visual Studio Code&#xff08;VS Code&#xff09;是一款由微软开发的免费、开源的代码编辑器&…