makefile学习笔记(一)(make架构详解、gcc -o 详解、make构建流程、clean使用、隐式规则和模式规则、自动变量、立即展开和延时展开)

1、make架构详解

make 是一个用于自动化构建和管理依赖关系的工具。它通过读取一个名为 Makefile 的文件,按照其中定义的规则来执行相应的操作。以下是一些基本的 make 执行规则和概念:

1. 目标(Target)

目标是 make 要创建或更新的文件,通常是可执行文件或对象文件。

2. 依赖(Dependencies)

依赖是目标所依赖的文件或其他目标。如果依赖文件发生变化,目标将被重新构建。

3. 命令(Commands)

命令是当目标需要更新时要执行的操作,通常是编译或链接的命令。命令必须以制表符(Tab)开始。

4. 基本结构

一个简单的 Makefile 示例:

makefile复制代码

target: dependencies command

5. 示例

假设有一个简单的 C 项目,有两个源文件 main.cutils.c,并且希望生成一个可执行文件 app,可以写一个如下的 Makefile

makefile复制代码

CC = gcc
CFLAGS = -Wallapp: main.o utils.o$(CC) $(CFLAGS) -o app main.o utils.omain.o: main.c$(CC) $(CFLAGS) -c main.cutils.o: utils.c$(CC) $(CFLAGS) -c utils.cclean:rm -f *.o app

6. 使用说明

  • 构建:在终端中运行 make 命令,默认会构建第一个目标(在这个例子中是 app)。
  • 清理:运行 make clean 可以删除所有生成的目标文件和可执行文件。

7. 特殊变量

  • CC: 指定编译器。
  • CFLAGS: 指定编译选项。

8. 内置规则

make 有许多内置规则,可以简化常见任务,例如自动处理 .c.o 的编译过程。

9. 伪目标

如上例中的 clean,不是文件名,而是一个伪目标,用于执行特定命令而不产生文件。

总结

  • -o 选项用于指定输出文件的名称。

  • 可以用于创建可执行文件或对象文件。

  • 如果不使用 -o,GCC 会默认为 a.out 作为可执行文件名,或者使用输入文件的基础名加上 .o 作为对象文件名。

  • 首先,当你运行 make app 时,make 会查找 app 目标,并发现它依赖于 main.outils.o

  • 如果 main.outils.o 不存在或需要更新,make 将会依次执行对应规则来生成这两个对象文件。

  • 随后,make 将执行链接命令 $(CC) $(CFLAGS) -o app main.o utils.o,构建最终的可执行文件 app


2、gcc -o 详解

在使用 gcc 编译器时,-o 选项用于指定输出文件的名称。它允许用户定义生成的可执行文件或对象文件的名称,而不是使用默认名称。

常见用法

  1. 编译源代码为可执行文件

当你想要将一个 C 源文件编译为一个可执行文件时,可以使用 -o 选项来指定输出文件名。例如:

bash复制代码

gcc main.c -o my_program

在这个例子中,main.c 是源代码文件,my_program 是生成的可执行文件名。如果没有指定 -o 选项,默认情况下输出文件名将是 a.out(在 Unix/Linux 系统中)。

  1. 编译源代码为对象文件

如果你想将 C 源文件编译为对象文件(即 .o 文件),同样可以使用 -o 选项。例如:

bash复制代码

gcc -c main.c -o main.o

在这个例子中,-c 选项表示只编译,不进行链接。结果是生成 main.o 对象文件,而不是默认的 main.o

完整示例

假设你有两个源文件 main.cutils.c,并且希望生成一个名为 app 的可执行文件,你可以使用以下命令:

bash复制代码

gcc main.c utils.c -o app

这条命令将 main.cutils.c 编译和链接成一个名为 app 的可执行文件。

总结

  • -o 选项用于指定输出文件的名称。
  • 可以用于创建可执行文件或对象文件。
  • 如果不使用 -o,GCC 会默认为 a.out 作为可执行文件名,或者使用输入文件的基础名加上 .o 作为对象文件名。

3、make构建流程

构建流程
使用 make 工具进行构建时,通常会生成几个不同类型的文件,包括源文件、对象文件和可执行文件等。以下是一个典型的构建流程,以及在这个过程中生成的各种文件及其生成顺序。

  1. 源文件

通常以 .c.cpp 或其他语言相关的扩展名存在。这些是最初的代码文件,例如:

  • main.c
  • utils.c

2. 对象文件

在编译过程中,每个源文件会被编译成一个对象文件(通常以 .o 作为扩展名)。这些文件包含机器代码,但不能直接执行。例如:

  • main.o
  • utils.o

3. 可执行文件

链接所有对象文件后,最终生成的可执行文件。例如:

  • app

4. Makefile

Makefile 是描述如何构建项目的文件,它定义了目标、依赖关系和命令。尽管不是由 make 直接生成的文件,但它是整个过程的核心。

构建过程顺序

假设有如下的 Makefile

makefile复制代码

CC = gcc CFLAGS = -Wall app: main.o utils.o $(CC) $(CFLAGS) -o app main.o utils.o main.o: main.c $(CC) $(CFLAGS) -c main.c utils.o: utils.c $(CC) $(CFLAGS) -c utils.c clean: rm -f *.o app

以下是构建过程的详细步骤和生成的文件顺序:

  1. 准备阶段:
  • 确保有源文件:main.cutils.c
  1. 编译阶段:
  • 当你运行 make 时,make 会读取 Makefile 并找到默认目标 app
  • 检查 app 的依赖项:main.outils.o
  1. 生成对象文件:
  • 如果 main.o 不存在或 main.c 最近更新,执行以下命令:

    bash复制代码

    gcc -Wall -c main.c

    这将生成 main.o 对象文件。

  • 接下来,如果 utils.o 不存在或 utils.c 最近更新,执行以下命令:

    bash复制代码

    gcc -Wall -c utils.c

    这将生成 utils.o 对象文件。

  1. 生成可执行文件:
  • 一旦所有对象文件都已生成,执行链接命令:

    bash复制代码

    gcc -Wall -o app main.o utils.o

    最终生成可执行文件 app

  1. 清理(可选):
  • 如果你想要删除生成的对象文件和可执行文件,可以运行:

    bash复制代码

    make clean

    这将执行 rm -f *.o app,清除所有生成的文件。

总结

在整个 make 构建过程中,通常包括以下文件及其生成顺序:

  1. 源文件(如 .c, .cpp
  2. 对象文件(如 .o
  3. 可执行文件(如 app

4、clean使用

随着项目的演变,依赖项可能会发生变化。旧的编译文件可能无法正确反映新的依赖关系。使用 make clean 可以帮助确保所有的文件都是基于目前的依赖关系和内容重新生成的。


5、隐式规则和模式规则:

make 中,规则用于定义如何构建目标文件。规则可以分为隐式规则和显式规则。

1. 显式规则

显式规则是用户明确指定的规则,通常包含目标、依赖关系和构建命令。以下是一个示例:

# 显式规则示例
target: dependenciescommand
示例
# 这是一个将源文件 hello.c 编译成可执行文件 hello 的显式规则
hello: hello.o main.ogcc -o hello hello.o main.o# 依赖规则,表示如何生成 hello.o
hello.o: hello.cgcc -c hello.c# 依赖规则,表示如何生成 main.o
main.o: main.cgcc -c main.c# 清理目标
clean:rm -f hello *.o

2. 隐式规则

隐式规则是 make 自动应用的规则,允许用户在不显式指定的情况下创建常见文件类型。例如,make 知道如何从 .c 文件生成 .o 文件。

示例

下面的 Makefile 演示了隐式规则的使用:

CC = gcc
# 使用模式匹配规则的 Makefile# 设置编译器和编译选项
CC = gcc
CFLAGS = -Wall# 定义最终目标
hello: $(patsubst %.c, %.o, $(wildcard *.c))# 模式匹配规则,用于从 .c 文件生成 .o 文件
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@# 清理目标
clean:rm -f hello *.o

在这个例子中,make 默认知道如何从 *.c 文件创建 *.o 文件,因此不需要我们为每个对象文件编写显式规则。

总结

  • 显式规则:用户明确指定,适合复杂的构建需求。
  • 隐式规则:由 make 自动处理,适合常见的编译任务,简化了 Makefile 的书写。

6 自动变量:

常用的自动变量

  1. $@: 表示规则中的目标文件名。例如,在链接阶段,$@ 会被替换为目标可执行文件的名称。

  2. $^: 表示规则中的所有依赖文件名,且没有重复项。通常在链接时使用,用于列出所有需要链接的对象文件。

  3. $<: 表示第一个依赖文件名。在编译规则中,这表示要编译的源文件。

  4. $*: 表示不带扩展名的目标文件名。通常用于模式匹配规则中,例如在生成 .o 文件时,可以用来生成相应的文件名。

示例

考虑下面的 Makefile 片段:

makefile复制代码

# 编译规则示例
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@main: main.o utils.o$(CC) $(CFLAGS) -o $@ $^

在这个示例中:

  • make 处理 main.o: main.c 规则时,$< 将会被替换为 main.c,而 $@ 则是 main.o
  • 在链接目标 main 的规则中,$@ 将被替换为 main,而 $^ 则包含了所有依赖的对象文件(例如 main.outils.o)。

优势

使用自动变量的主要优点包括:

  • 减少冗余: 自动变量可以减少手动输入,使得 Makefile 更加简洁和易于维护。
  • 提高灵活性: 如果您更改了目标或依赖关系,自动变量将自动适应这些更改,而无需修改命令行。
  • 清晰性: 它们使得构建过程的逻辑更加清晰,更容易理解每个命令所做的事情。

总结

自动变量是 Makefile 中的一种强大工具,能帮助开发者简化构建过程,提高可读性和维护性。通过合理使用这些自动变量,您可以使得 Makefile 既灵活又高效

7、立即展开和延时展开:

Makefile 中,变量的展开方式主要分为两种:立即展开(即刻展开)和延迟展开(稍后展开)。这两种展开方式在目标和依赖关系中的使用以及命令中的应用有不同的目的和效果。我们来逐一解释它们的区别,并通过示例来说明。

变量的展开方式

  1. 立即展开:
  • 立即展开的变量使用 = 定义。在 Makefile 被读取时,这些变量的值会立即计算并替换。
  • 适用于定义目标和其依赖项,因为目标和依赖项在 make 开始处理规则时就需要确定。
  1. 延迟展开:
  • 延迟展开的变量使用 := 定义。这样,变量的值会在实际使用时计算,而不是在定义时。
  • 适用于命令中的变量,因为这些命令在目标被构建时执行,此时所需的最新信息是重要的。

示例

下面是一个简单的 Makefile 示例,通过这个例子可以看到如何使用立即展开与延迟展开变量:

# 使用立即展开的变量
SOURCE_FILES = main.c utils.c
OBJECT_FILES = $(SOURCE_FILES:.c=.o)  # 立即展开,计算出对象文件列表# 使用延迟展开的变量
CC = gcc
CFLAGS = -Wall# 最终目标
TARGET = programall: $(TARGET)# 链接目标
$(TARGET): $(OBJECT_FILES)$(CC) $(CFLAGS) -o $@ $(OBJECT_FILES)# 编译规则,使用延迟展开的命令
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@clean:rm -f $(TARGET) $(OBJECT_FILES).PHONY: all clean

分析

  1. 立即展开的变量:
  • SOURCE_FILESOBJECT_FILES 是使用立即展开定义的。在 Makefile 被解析时,OBJECT_FILES 会被计算为 main.o utils.o,无论在构建过程的任何时刻,其值都是固定的。
  1. 延迟展开的变量:
  • 在编译和链接阶段,$(CC)$(CFLAGS) 是延迟展开的。这意味着在执行命令时,会获取当前的 CCCFLAGS 的值,从而保证使用的是最新的配置。

为什么选择这种方式

  • 立即展开 用于目标和依赖项是因为这些信息在开始生成目标之前就已经确定,即使在多个不同的上下文中都能保持一致性。

  • 延迟展开 用于命令是因为在命令执行时,可能需要使用到最新的状态或环境设置,这样才能确保编译和链接使用的参数是正确的。

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

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

相关文章

WEB领域是不是黄了还是没黄

进入2024年后&#xff0c;WEB领域大批老表失业&#xff0c;一片哀嚎&#xff0c;个个饿的鬼叫狼嚎&#xff0c;为啥呢&#xff0c;下面是我个人的见解和看法。 中国程序员在应用层的集中 市场需求&#xff1a;中国的互联网行业在过去几年中经历了爆炸性增长&#xff0c;尤其是…

python和pyqt-tools安装位置

一.python的安装位置 1.查询安装的python的位置 先查询python&#xff0c;然后输入import sys和sys.path 二.python-tools的安装位置 找到python的文件后按下图路径即可查到tools的文件

UEFI EDK2框架学习 (一)

01 Shell界面打印 执行qemu指令后 qemu-system-x86_64 -drive ifpflash,formatraw,fileOVMF.fd -nographic -net none出现shell界面 02 在UEFI shell中创建APP 创建SimplestApp文件夹以及SimplestApp.c、SimplestApp.inf cd edk2 mkdir SimplestAppuuidgen // generate …

论文不会写快来看!分享4款ai改写论文软件

在当今学术研究和写作领域&#xff0c;AI论文改写工具已经成为不可或缺的助手。这些工具不仅能够帮助研究人员提高写作效率&#xff0c;还能确保论文的质量和原创性。以下是四款值得推荐的AI改写论文软件&#xff0c;其中特别推荐千笔-AIPassPaper。 千笔-AIPassPaper 传送门&…

【在.net6和WPF框架下进行海康SDK开发】(一)如何引用Dll

最近有个上位机项目&#xff0c;需要将海康VisionMaster的部分功能嵌入到统一的界面。项目使用WPFdotNet6开发&#xff0c;UI库使用HandyControl。 先说下需求&#xff0c;在某个TabItem内嵌入一个UserControl&#xff0c;UserContr内嵌入VisionMaster运行界面。 本以为按照海康…

开关频率与谐振频率对应的模态图

当fsfr时 当fr2<fs<fr1时 当fs>fr1时 开关频率对应输入电压的频率 谐振频率对应的是谐振电流的频率

人工智能之计算机视觉的发展历程与相关技术内容,相应的模型介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能之计算机视觉的发展历程与相关技术内容&#xff0c;相应的模型介绍。本文围绕计算机视觉这一领域&#xff0c;以问答的形式呈现了关键问题及详细解答。内容涵盖计算机视觉的基本概念、技术原理、应用场景等…

Java刷题知识总结(一)

1.局部变量参与运算前是必须要初始化的&#xff0c;比如下面的代码就会编译出错&#xff0c;提示y必须要初始化。 public static void main(String[] args) {int x 1;int y;int z x y; } 2.ArrayList和Vector主要区别是什么&#xff1f; A Vector与ArrayList一样&#xf…

浮动静态路由

浮动静态路由 首先我们知道静态路由的默认优先级是60&#xff0c;然后手动添加一条静态路由优先级为80的路由作为备份路由。当主路由失效的备份路由就会启动。 一、拓扑图 二、基本配置 1.R1: <Huawei>system-view [Huawei]sysname R1 [R1]interface GigabitEthernet…

嵌入式linux方向细分工作岗位分析

大家好,今天主要给大家分享一下,linux方向细分的工作岗位有哪些?,为即将进入linux领域的开发者指明方向。 第一:总结分布 第二:Linux BSP工程师岗位 工作内容: 1、开发和维护Linux系统的板级支持包(BSP),包括启动加载程序、设备驱动、文件系统等。 2、负责解决硬件和软…

企业上云不迷茫,香港电讯助力企业上云全攻略

在全球政策和市场双重驱动下&#xff0c;云计算产业正迎来前所未有的增长浪潮。据中国信通院《云计算白皮书&#xff08;2023年&#xff09;》1显示&#xff0c;2022年全球云计算市场规模已达到4,910亿美元&#xff0c;同比增长率高达百分之十九。而在中国市场&#xff0c;这一…

实现一个基于nio的discard server

写在前面 源码 。 为了能够进一步的熟悉下nio相关的api操作&#xff0c;本文来实现一个基于nio的discard server。 discard server的意思是&#xff0c;server接收到来自client的一个消息之后&#xff0c;直接就将连接关闭&#xff0c;即discard。 1&#xff1a;正戏 1.1&…

【ollama 在linux 上离线部署 本地大模型】

本文继续来讲如何在linux上部署离线本地智能大模型&#xff0c;前篇如下&#xff1a;window上部署离线大模型 首先还是安装ollama linux版本&#xff0c;如果完全离线的话&#xff0c;可以从github上下载一个linux 版本的压缩包传上去 git hub上搜索ollama 找到右下角 找到li…

变量与变量提升【JavaScript】

一、变量 在 JavaScript 中&#xff0c;变量 是用于存储数据的容器。你可以使用变量来保存和操作各种类型的数据。其中&#xff0c;声明变量、变量初始化和变量赋值是三个相关但不同的概念。下面是它们之间的区别与联系&#xff1a; 1. 变量声明 变量声明是定义变量的过程。它…

基于SpringBoot+Vue+MySQL的教学资料管理系统

系统展示 管理员后台界面 教师后台界面 系统背景 在当今信息化高速发展的时代&#xff0c;教育机构面临着日益增长的教学资料管理需求。为了提升教学管理的效率&#xff0c;优化资源的配置与利用&#xff0c;开发一套高效、便捷的教学资料管理系统显得尤为重要。基于SpringBoot…

出海企业如何利用海外云手机开展业务?

随着全球化的持续推进&#xff0c;越来越多的企业将目光投向海外市场。然而&#xff0c;面对不同国家的网络环境、政策限制以及文化和语言的差异&#xff0c;出海企业在拓展海外业务时遇到了许多障碍。海外云手机作为一种创新的解决方案&#xff0c;为企业提供支持和帮助。 海外…

Spring Data Rest 远程命令执⾏命令(CVE-2017-8046) 靶场攻略

靶场环境 vulhub/spring/CVE-2017-8046 漏洞复现 1. 访问 http://47.113.231.0:8080/customers/1 2.抓取数据包&#xff0c;使⽤PATCH请求来修改 PATCH /customers/1 HTTP/1.1 Host: 47.113.231.0:8080 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en U…

微信抢红包设计

包几个红包&#xff0c;发红包的总金额塞钱进红包&#xff0c;弹出支付的界面&#xff0c;支付完之后就会被发到 群里抢拆红包&#xff0c;才是真正的抢红包 红包金额怎么分配 每个人至少抢到1分钱人数抢到的金额之和就应该是红包的总金额一个人抢的红包不应该极度的大&#…

选择排序(C语言实现)

目录 1.基本思想 2.代码实现 代码思路 代码实现 代码测试 3.复杂度分析 1&#xff09;时间复杂度 2&#xff09;空间复杂度 4.特性总结 1.基本思想 选择排序是一种简单直观的比较排序算法。该算法的基本思想是在每一轮中选出当前未排序部分的最小&#xff08;或最大&a…

xv6讲解(2) Operating system organization

这一章 讲操作系统是如何实现进程并发、进程隔离和进程交互(multiplexing isolation and interaction) 进程并发&#xff1a; 操作系统需要同时支持多个进程。如一个进程可以使用fork来启动新的进程。对计算机的资源进行时间共享&#xff0c;确保所有进程都有机会执行。 进程…