makefile 学习(4): makefile基础

news2024/11/23 17:05:31

0. 官方文档

  • GNU Make 官方网站: https://www.gnu.org/software/make
  • GNU Make 官方文档下载地址: https://www.gnu.org/software/make/manual/
  • Makefile Tutorial:https://makefiletutorial.com/

1.基本要求

1.1 基本格式

targets : prerequisties
[tab键] command

  • target : 目标文件,可以.o后缀的目标文件,也可以是执行文件,还可以是一个标签(Label),对于标签这种特性,在后续的“伪标签”章节会有叙述
  • prerequisties:要生成的那个target所需要的文件或目标
  • command: 是make需要执行的命令

通常我们会将一堆.c/.cpp文件放在prerequisties, targets 放对应需要生成的.o文件。执行的command对应就是g++ - c $(prerequisties) -o $(argets) 。同样链接可执行文件的时候也是一样的,targets放可执行文件,prerequisties则放目标.o文件

注意: command的前面需要用tab,而不是空格键。makefile对格式的控制是非常严格的

案例

通常在makefile中,会希望有个语句debug, 用来打印一些需要的信息,比如变量的值或者一些函数的处理结果。
Makefile中的内容如下

debug:
	echo hello

cd 到Makefile所在目录,然后执行make debug就可以输出结果了。
【图】

可以看到输出了hello结果,同时也输出了command命令。随着工程越来越大,我们的命令会变得复杂。都打印出所有command终端看起来会显得冗余。 可以在命令前加上@符号,就可以不在终端输出command,只输出结果。

debug:
	@echo hello

1.2 Makefile规则

  • make会在当前目录下找到一个名字叫Makefile或者makefile的文件
  • 在执行make命令时,如果没有指定target(make xx (target)),它会找到文件中第一个目标文件(target), 并把这个文件作为最终的目标文件
  • 如果target文件不存在,或者target文件依赖的.o文件(prerequities)的文件修改时间要比target这个文件新,就会执行后面所定义的命令command来生成target文件
  • 如果target依赖的.o文件(prerequities) 文件也不存在,make会在当前文件中找到target为.o文件的依赖项,并根据对应的command生成.o文件。

makefile会根据依赖,一层层去执行,直到最终生成我们需要的target。makefile中一旦源文件做了更改(.cpp/.c), 它会自动重新编译一遍,这其实是非常方便的。

1.3 伪目标

  • 伪目标不是一个文件,它只是一个标签,我们需要显示地指明这个目标才能让其生效。
  • 伪目标的取名不能和文件名重名,否则不会执行命令。(比如与makefile同目录存在一个与伪目标同名clean文件,此时我们想 执行make clean删除 文件夹objs,则会无法删除
    【图2】

为了避免和文件重名的情况,我们可以使用一个特殊的标记.PHONY来显示地指明一个目标为伪目标,向make说明,不管是否存在该文件,都不影响该伪目标的执行。通常在一个makefile里面,对于clean,debug,run等命令, 我们一般都会写在.PHONY后面, 然后就可以和make 一起当作命令去执行了。

.PHONY:clean debug run

【图3】

注意:如果出现报错,可能是使用了空格,重新tab

2.变量的定义与使用

变量在声明时候需要给予初值, 在使用时,需要给变量名前加上$符号,并以()把变量给包括起来。

2.1 变量的定义

cpp := src/main.cpp
obj := objs/main.o

2.2 变量的引用

  • 可以使用() 或者{}
cpp := src/main.cpp
obj := objs/main.o

$(obj) : $(cpp)
	@g++ -c $(cpp) -o $(obj)

# make compile可执行编译
compile : $(obj)

# 打印调试信息
debug :
	@echo $(cpp)  
	@echo $(obj)

在终端运行make compile命令,可执行编译过程。编译完后,在objs下会生成main.o目标文件

2.3 预定义的变量

除了自定义的变量,makefile还提供了一些预定义的变量,可以很方便减少command中的语句。

  • $@: 目标(target)的完整名称
  • $<: 第一个依赖的文件(prerequisties)的名称
  • $^: 所有的依赖文件(prerequisties), 以空格分开,不包括重复的依赖文件
cpp := src/main.cpp
obj := objs/main.o

$(obj) : $(cpp)
	@g++ -c $< -o $@
	@echo $^

compile: $(obj)

clean:
	@rm -rf objs/main.o

debug :
	@echo $(cpp)
	@echo $(obj)

# 为了防止和文件冲突,添加伪目标标识
.PHONY : compile clean

执行

# 清除之前编译生成的.o文件
make clean
# 重新编译
make compile

在这里插入图片描述

3. 常用的符号

(1) =

  • 简单的赋值运算符
  • 用于将右边的值分配给左边变量
  • 如果在后面的语句中重新定义了了该变量,则将使用新的遍历

示例

HOST_ARCH = aarch64
TARGET_ARCH = ${HOST_ARCH}

#....
#....

HOST_ARCH = amd64

debug:
	@echo ${TARGET_ARCH}

终端执行:

make debug
>> amd64

可以看到TARGET_ARCH 的值随着HOST_ARCH的变化更新了

(2) :=

  • 立即赋值运算符
  • 用于在定义变量时立即求值
  • 该值在定义后不再更改 (与=的区别)
  • 即使在后面的语句中重新定义了该变量

示例

HOST_ARCH := aarch64
TARGET_ARCH := ${HOST_ARCH}

#....
#....

HOST_ARCH := amd64

debug:
   @echo ${TARGET_ARCH}

终端执行:

make debug
>> aarch64

在这里插入图片描述

可以看到打印出来的是最初赋的值aarch64

(3) ?=

  • 默认赋值运算符
  • 如果该变量已经定义,则不进行任何操作
  • 如果该变量尚未定义,则求值并分配

示例

HOST_ARCH = aarch64
HOST_ARCH ?= amd64

debug:
	@echo ${HOST_ARCH}
  • 输出的是aarch64,已经赋值了,就不会进行赋值操作。
#HOST_ARCH = aarch64
HOST_ARCH ?= amd64

debug:
	@echo ${HOST_ARCH}
  • 此时输出的是amd64,因为没有赋值的话,就会进行赋值

需要注意下,如下也是赋值了的,只是赋值了一个空的字符串

HOST_ARCH = 

(4) 累加+=
+=是非常常用的,比如在编译的时候,添加头文件路径,库的路径,名字以及c++编译的选项等,就会需要进行累加的操作,添加完成就相当于将所有字符串,保存称为一个字符串数组或列表中。

示例

include_path := src

CXXFLAGS := -m64 -fPIC -g -o0 -std=c++11 -w -fopenmp

CXXFLAGS += $(include_path)

debug :
	@echo ${CXXFLAGS}

.PHONY: debug

终端执行:

>>  -m64 -fPIC -g -o0 -std=c++11 -w -fopenmp src

可以看到将src加到了最后。

(4) 续行符\
后面会用的库越来越多,包含头文件的路径,库文件的路径也会越来越多,所以都会用续行符\去写,注意\前面可以用空格隔开,后面不需要空格

LDLIBS := cudart opencv_core gomp \
		nvinfer protobuf cudnn pthread \
		cublas nvcaffe_parser nvinfer_plugin

4. 常用函数

函数的调用,很像变量的使用,也是用$来标识的,其语法如下:

$(fn,arguments) or ${fn,arguments}
  • fn函数名
  • argument: 函数参数,参数间以逗号分隔,而函数名和参数之间以空格分隔

(1) shell
shell函数是一个非常常用的函数,可以让我们在makefile里面执行终端bash的命令

${shell <command> <arguments>}
  • 名称: shell 命令函数 —shell
  • 功能: 调用shell命令 command
  • 返回: 函数返回shell 命令command的执行结果

示例
查找src目录下所有.cpp文件


cpp_srcs := ${shell find src -name *.cpp} #src 目录  -name 以名字查找  *.cpp 所有以.cpp结尾

debug :
	@echo ${cpp_srcs}

.PHONY : debug

记得如果debug是个命令,而不是生成的文件的话,记得加上.PHONY的标识符.

终端执行:

make debug

在这里插入图片描述

就可以拿到src目录下全部的.cpp文件路径

未完待续

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

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

相关文章

一、MongoDB简介

文章目录 一、MongoDB简介1、NoSQL简介2、什么是MongoDB ?3、MongoDB 特点4、安装mongodb5、MongoDB 概念解析5.1 数据库5.2 文档5.3 集合5.4 MongoDB 数据类型 6、适用场景 一、MongoDB简介 1、NoSQL简介 NoSQL(NoSQL Not Only SQL)&#xff0c;意即反SQL运动&#xff0c;…

关于在spyder,jupyter notebook下创建虚拟环境(pytorch,tensorflow)均有效

anaconda下载地址 https://www.anaconda.com/download/ 下载完成后打开anaconda目录下的 anaconda prompt 在命令行中输入下面的命令创建一个叫tf2.0的虚拟环境&#xff08;“tf2.0”是建立的Conda虚拟环境的名字&#xff0c;可以自拟&#xff09; conda create -n tf2.0 p…

chatgpt赋能Python-pythonfor遍历

Python for 遍历&#xff1a;优雅地遍历数据结构 对于任何编程语言来说&#xff0c;遍历是一项基本操作。而在 Python 中&#xff0c;遍历是一项非常简单和优雅的操作。Python 提供了多种遍历数据结构的方法&#xff0c;包括 for 循环、while 循环、迭代器和生成器等。本文将介…

模板和STL【C++初阶】

目录 一、前言 二、函数模板 三、类模板 四、STL 一、前言 以前我们写swap函数时&#xff0c;对每一种类型的变量都要写一份swap函数&#xff0c;但是他们的格式都是一样的&#xff0c;未免有些麻烦 因此&#xff0c;我们今天学习的模板就可以针对广泛的类型而不是具体的类…

chatgpt赋能Python-pythondir

Python dir命令&#xff1a;探索Python模块的秘密 如果你是一名Python开发者&#xff0c;那么你一定或多或少接触过dir这个命令。但是&#xff0c;你了解dir到底能做什么吗&#xff1f;这篇文章将会介绍dir命令的用途、用法以及一些有趣的技巧。 什么是dir命令 简单来说&…

chatgpt赋能Python-pythonfind

Python文件搜索工具Pythonfind 在开发过程中&#xff0c;文件搜索工具是一个非常重要的工具。在大型项目中&#xff0c;可能需要查找特定类型的文件或者在代码库中查找特定的代码块。 Pythonfind是一个非常强大和灵活的python文件搜索工具&#xff0c;可以帮助我们简化这个过程…

chatgpt赋能Python-pythonforelse

Python For Else 详解&#xff1a;用 Python 的人都应该了解的语法结构 在 Python 中&#xff0c;一个常见的语法结构是 for...else。这种语法结构让循环变得更加直接明了&#xff0c;也让代码更加易读和易懂。 什么是 Python For Else 在 Python 中&#xff0c;for...else …

第13章_约束

第13章_约束 1. 约束(constraint)概述 1.1 为什么需要约束 数据完整性&#xff08;Data Integrity&#xff09;是指数据的精确性&#xff08;Accuracy&#xff09;和可靠性&#xff08;Reliability&#xff09;。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的…

chatgpt赋能Python-pythondataframe转置

Python Dataframe 转置 - 了解 Pandas 中 DataFrame 转置的用法 数据分析是现代业务中的一个关键课题。当您在数据分析中使用 Pandas 时&#xff0c;往往会遇到需要转置 DataFrame 的情况。本文中&#xff0c;我们将介绍如何使用 Python 的 Pandas 库中的 DataFrame 转置来实现…

chatgpt赋能Python-pythondoc

PythonDoc&#xff1a;了解Python的文档工具 什么是PythonDoc&#xff1f; PythonDoc是Python官方文档。它是Python编程语言的权威指南和参考资料&#xff0c;提供丰富而全面的信息&#xff0c;从基础语法到高级主题&#xff0c;都有许多实用和详细的文档说明。 PythonDoc的…

chatgpt赋能Python-pythonddos

PythonDDoS&#xff1a;了解一下这种利用Python语言的攻击方式 PythonDDoS&#xff08;Python分布式拒绝服务攻击&#xff09;是一种利用Python语言编写的DDoS攻击技术&#xff0c;它利用了Python的强大处理能力&#xff0c;可以构建高效的攻击工具&#xff0c;让攻击者能够轻…

SpringMVC学习总结(路由映射、参数传递、转发和重定向...)

目录 1. MVC简介 2. SpringMVC简介 3. 路由映射注解 3.1 RequestMapping 3.2 GetMapping与PostMapping 4. 接收前端传递参数 4.1 接收单/多个参数 4.2 接收对象 4.3 接收JSON对象 4.4 后端参数重命名/映射 4.5 设置参数必传/非必传 4.6 获取URL中的参数 4.7 获取文…

学生考勤信息管理系统

系列文章 任务36 学生考勤信息管理系统 文章目录 系列文章一、实践目的与要求1、目的2、要求 二、课题任务三、总体设计1.存储结构及数据类型定义2.程序结构3.所实现的功能函数4、程序流程图 四、小组成员及分工五、 测试操作页面bk.txt信息录入&#xff1a;加入新出勤的信息查…

chatgpt赋能Python-pythonget

PythonGet&#xff1a;一个优秀的Python包管理器 PythonGet是一个优秀的Python包管理器&#xff0c;它可以帮助Python工程师安装、管理和更新Python包。本文将在介绍PythonGet的基本用法的同时&#xff0c;探讨PythonGet在SEO优化中的应用。 PythonGet的简介 PythonGet是Pyt…

不用魔法,快速、手摸手上线Midjourney!【附源码】【示例】

首先来一波感谢&#xff1a; 感谢laf提供赞助&#xff0c;目前可以免费使用Midjourney进行开发和测试。 感谢白夜、米开朗基杨sealos.io的耐心解答&#xff0c;让我对laf有了更多的使用与了解。 什么是laf&#xff1f;来了解下。 文末有【示例】 开始 废话不多说&#xff0c;…

基于Freertos的ESP-IDF开发——7.WS2812B彩色灯循环

基于Freertos的ESP-IDF开发——7.WS2812B彩色灯循环 0. 前言1. WS2812B简介2. 完整代码3. 演示效果4. 其他FreeRtos文章 0. 前言 本节使用WS2812B实现彩灯循环 开发环境&#xff1a;ESP-IDF 4.3 操作系统&#xff1a;Windows10 专业版 开发板&#xff1a;自制的ESP32-WROOM-3…

【软考中级】软件设计师选择题题集(一)

海明校验码是在n个数据位之外增设k个校验位,从而形成一个k+n位的新的码字, 使新的码字的码距比较均匀地拉大。n与k的关系是(1)。 (1)A.2k - 1≥n + k  B.2n - 1≤ n + k   C.n = k  D.n-1≤k 【答案】A 【解析】 【答案】B A 【解析】 在采用结构化方法进行系统分析时,…

MySQL高级篇——索引失效的11种情况

导航&#xff1a; 【黑马Java笔记踩坑汇总】Java基础进阶JavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线设计模式牛客面试题 目录 1. 索引优化思路 2. 索引失效的11种情况 2.0. 数据准备 2.1 要尽量满足全值匹配 2.2 要满足最佳左前缀法则 2.3 主键插…

详解Jetpack Compose中的Modifier修饰符

前言 本文将会介绍Jetpack Compose中的Modifier。在谷歌官方文档中它的描述是这么一句话&#xff1a;Modifier元素是一个有序、不可变的集合&#xff0c;它可以往Jetpack Compose UI元素中添加修饰或者各种行为。例如&#xff0c;背景、填充和单击事件监听器装饰或添加行为到文…

依次对数组中的元素进行逻辑非和异或判断numpy.logical_not()numpy.logical_xor()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 依次对数组中的元素进行逻辑非和异或判断 numpy.logical_not() numpy.logical_xor() [太阳]选择题 下列代码中np.logical_xor(A, B)输出的结果是&#xff1f; import numpy as np A [True, …