Linux:编译,链接,自动化构建工具

c语言源代码编译成可执行程序的过程包括以下几个步骤,每一步都对源代码进行了不同的处理:

预处理(.c文件 -> .i文件)

目的:将头文件和宏进行替换,取消注释。文件从 code.c 变为 code.i

Linux:编译,链接,自动化构建工具

现在我使用指令对 .c 文件进行预处理,让我们来看一下预处理后的代码:

gcc -E code.c -o code.i

可以看到头文件确实被库 中的代码替换了;而其他代码保持不变。

Linux:编译,链接,自动化构建工具

注意:替换后的代码仍然是C语言代码,只是变得更加简洁(没有注释)。

编译(.i文件 -> .s文件)

目的:将C语言代码处理为汇编代码。

这次我们直接使用预处理过的文件进行下一步的汇编:

gcc -S code.i -o code.s

Linux:编译,链接,自动化构建工具

我们发现这次处理后的代码已经变成我们看不懂的了,这就是已经从C代码转换为了汇编代码。

汇编(.s文件 -> .o文件)

目的:进一步处理汇编代码,形成机器可识别的代码(可重定向目标文件)。

这次我们使用上一次的 code.s 文件继续编译,会报错;所以我们这次使用 code.c 来进行处理:

gcc -c code.c -o code.o

Linux:编译,链接,自动化构建工具

这次的代码和上次的有变化,但还是看不懂。我们记住是从汇编代码处理为了机器可识别的代码,变成了可重定向目标文件。

链接(.o文件 -> exe文件)

目的:产生可执行文件。

这次使用 .o 文件链接为 exe 文件:

gcc code.o -o code

Linux:编译,链接,自动化构建工具

E、S、c选项先有语言还是先有编译器?答案是先有语言,但并不是先有当前编译器的语言。在最早的时期,人们都是使用二进制语言来编写程序的;然而,为了更加方便地编写代码,人们使用二进制编写了汇编代码,因此汇编语言产生了。然后,人们又使用汇编代码开发出了汇编代码编译器,这个过程就叫做语言自举。

动态连接和静态连接库的位置,我们平时使用的头文件都是声明,实现都在库文件中,库一般都在 /usr/include 目录下。

Linux:编译,链接,自动化构建工具

连接方式分为动态链接和静态连接。

查看文件使用的哪种库?

Linux:编译,链接,自动化构建工具

根据红色的部分判断是什么库?

云服务器默认没有安装C/C++静态标准库,我们可以使用 yum 按照下面的指令安装:

sudo yum install libstdc++-static

Makefile自动构建工具

LuckyCola工具库 LuckyCola工具库

LuckyCola工具库是您工作学习的智能助手,提供一系列AI驱动的工具,旨在为您的生活带来便利与高效。

LuckyCola工具库 19 查看详情 LuckyCola工具库

我们可以把 Makefile 理解为指令的集合;Makefile 文件里有我们写好的很多指令,然后我们对 Makefile 进行操作就可以更加便捷地调用其内部的指令。

举个例子,比如有一份 proc.c 的C语言文件,在使用的过程中需要多次对文件编译,通常情况下每次编译都要使用 gcc proc.c -o proc 生成可执行文件 proc;这样操作是很麻烦的。Makefile 工具可以很好地解决这种频繁调用编译的问题。

Makefile 的使用:

Linux:编译,链接,自动化构建工具

第一行:proc 是生成的文件,proc.c 是依赖文件;冒号代表的是依赖关系。第二行需要空一个 Tab 键的长度(不能使用空格),然后输入要执行的命令。

Linux:编译,链接,自动化构建工具

我们直接使用指令 make 就可以调用 gcc proc.c -o proc 指令了,这样使用起来是不是会很方便?

那是不是也可以这样方便地清理文件呢?

答案是可以的:

Linux:编译,链接,自动化构建工具

不同的是删除代码不需要依赖任何文件,所以没有依赖文件。我们需要使用 make clean 来调用清除可执行程序的指令。

为什么 gcc proc.c -o proc 直接使用 make 就可以呢?

这是因为代码的执行顺序是从上到下的,make 默认调用第一个依赖关系命令,这里实际上 make 的完整指令应该是 make proc

目标的调用顺序

现在来写一下C语言编译的完整过程:

Linux:编译,链接,自动化构建工具

程序执行的顺序是从上往下执行的,当执行 gcc proc.o -o proc 时,这时候还没有 proc.o 文件,所以就会先把这一行的指令放入堆栈中,依次类推,直到最后 gcc -E proc.c -o proc.i 产生了 proc.i 文件,紧接着指令依次出栈;最后执行完毕。

.PHONY伪目标

在没有使用 .PHONY 的情况下,proc.c 文件在最新版本时,只能 make 一次。这样做的目的是提高效率。

Linux:编译,链接,自动化构建工具

在此编译会给出“proc is up to date”,proc 可执行程序是最新的,不需要再次编译。

如何查看文件是否是最新的?

Linux:编译,链接,自动化构建工具

stat 文件名:查看文件的最近一次的更改时间相关的信息。正常情况下,proc.c 文件的时间应该是在 proc 之前的,因为先有 proc.c 再有 proc;这是我刚才更新了一下 proc.c 文件,这时候 proc.cproc 还要新,所以这个时候是可以重新编译的。

使用伪目标忽略时间:

Linux:编译,链接,自动化构建工具

如果我们对 make proc 设置伪目标,那样就可以无限次地编译了。

Linux:编译,链接,自动化构建工具

总结

以上就是Linux:编译,链接,自动化构建工具的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/487243.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月8日 13:53:35
下一篇 2025年11月8日 13:54:16

相关推荐

  • C++ 函数指针的典型使用场景有哪些?

    函数指针的典型场景包括:回调函数、排序函数、事件处理、函数表、懒加载和底层 api 互操作性。通过使用函数指针,可以在运行时间接调用函数,实现动态和可扩展的代码。例如,回调函数用于异步事件(例如,用户输入或网络请求)发生时的回调,为不同的对象类型定制比较算法提供了排序函数,事件处理用于注册和处理不同…

    好文分享 2025年12月18日
    000
  • C++ 递归函数的空间复杂度如何分析?

    c++++递归函数的空间复杂度取决于它在函数调用期间分配在栈上的数据大小。递归调用的深度决定了所需的栈空间,可分为:无终止条件:o(1)常量递归深度:o(n)对数递归深度:o(log n) C++ 递归函数的空间复杂度分析 简介 递归函数在 C++ 中是一种常见且强大的编程技术。然而,理解其空间复杂…

    2025年12月18日
    000
  • 在 C++ 中,函数指针可以做什么,不能做什么?

    函数指针在 c++++ 中用于传递、返回或存储函数,增强了程序灵活性。其功能包括:传递函数作为参数从函数返回函数存储函数在数据结构中事件处理但也有限制:类型安全:指向不同函数的指针可以相互转换,存在运行时错误风险。生命周期管理:必须确保函数在指针生命周期内有效。优化:编译器无法优化涉及函数指针的代码…

    2025年12月18日
    000
  • 如何将函数指针转换为函数对象并反之?

    在 c++++ 中,通过 std::function 模板可将函数指针转换为函数对象:使用 std::function 将函数指针包装成函数对象。使用 std::function::target 成员函数将函数对象转换为函数指针。此转换在事件处理、函数回调和泛型算法等场景中很有用,提供了更大的灵活性…

    2025年12月18日
    000
  • C++ lambda 表达式的参数列表如何制定?

    lambda 表达式的参数列表语法为:[capture-list](parameters) -> return-type { body },其中:capture-list 捕获外部变量。parameters 为参数列表。return-type 为返回类型。body 为函数体。 C++ Lamb…

    2025年12月18日
    000
  • 使用 C++ lambda 表达式进行数据过滤和转换有哪些实战案例?

    在 c++++ 中,lambda 表达式可用于方便地对数据进行过滤和转换。例如,可使用 lambda 表达式过滤容器中的奇数元素,转换容器中的元素,过滤和转换关联容器,在算法中使用 lambda 表达式,以及作为函数参数传递 lambda 表达式。这些方法可以让数据处理任务变得更加简洁和高效。 使用…

    2025年12月18日
    000
  • C++ 递归函数在算法设计中的作用?

    递归函数在 c++++ 算法设计中通过分解问题、重复解决子问题并优化效率发挥作用。它的语法是通过自身调用解决问题的函数。递归函数的实际应用包括计算阶乘、查找树的最大深度、求解迷宫、反转列表和排序算法。 C++ 递归函数在算法设计中的作用 递归函数是计算机科学中一种重要的算法技术。在 C++ 中,递归…

    2025年12月18日
    000
  • C++ 函数指针的本质和工作原理是什么?

    函数指针本质上是变量,指向函数内存地址,允许在运行时动态调用函数。它包含指向函数的地址、函数类型和指针运算能力。工作原理涉及获取函数地址、推入参数和返回地址、调用函数,并将返回值和控制权返回到调用代码。 C++ 函数指针的本质和工作原理 什么是函数指针? 函数指针是一种指向函数内存地址的变量。它允许…

    2025年12月18日
    000
  • C++ 函数指针的应用场景

    函数指针在 c++++ 中指的是指向函数内存地址的变量。它常用于回调函数、动态绑定和事件处理等场景。举例来说,在排序算法中,我们可以使用函数指针来实现不同的比较函数,从而灵活地选择排序算法。 C++ 函数指针的应用场景 什么是函数指针? 在 C++ 中,函数指针是一种指向函数的指针。它是一个指向函数…

    2025年12月18日
    000
  • C++ 函数库如何进行序列化和反序列化?

    c++++ 函数库序列化和反序列化指南序列化:创建输出流并将其转换为存档格式。将对象序列化到存档中。反序列化:创建输入流并将其从存档格式恢复。从存档中反序列化对象。实战示例:序列化:创建输出流。创建存档对象。创建对象并将其序列化到存档中。反序列化:创建输入流。创建存档对象。创建对象并从存档中反序列化…

    2025年12月18日
    000
  • C++ 函数库如何进行网络编程?

    c++++ 库中网络编程通过库提供套接字 api、boost.asio 和 qt network 等功能。实战案例展示了使用 berkeley 套接字 api 构建 tcp 服务器的步骤:1. 包含头文件;2. 创建套接字;3. 绑定套接字到地址和端口;4. 监听连接;5. 处理客户端请求。 C++…

    2025年12月18日
    000
  • C++ 函数调试的实用技巧

    C++ 函数调试的实用技巧 引言调试 C++ 函数可能是具有挑战性的,尤其是对于大型和复杂的函数。本文介绍了一些实用的技巧,可以帮助您高效地调试 C++ 函数,并识别和解决错误。 实战案例考虑下面这个 C++ 函数,它计算两个数字的平均值: double calculateAverage(int n…

    2025年12月18日
    000
  • C++ 函数指针与回调函数的对比

    函数指针和回调函数都是实现回调机制的工具。函数指针在编译时创建,不可修改,需要显式调用;而回调函数在运行时创建,可动态绑定到不同函数,由回调函数自动调用。因此,函数指针适合静态回调,而回调函数适合动态回调。 C++ 函数指针与回调函数的对比 函数指针和回调函数都是 C++ 中用来实现回调机制的强大工…

    2025年12月18日
    000
  • C++ 中提升函数性能的具体方法是什么?

    提升 c++++ 函数性能的五个方法:内联函数(将代码嵌入调用方);减少函数参数传递(只传递必要的参数);使用常量引用(传递函数参数的常量引用);优化循环(使用迭代器或范围循环);使用局部变量(访问全局变量或频繁获取局部变量地址)。 C++ 中提升函数性能的具体方法 提升函数性能是提高 C++ 程序…

    2025年12月18日
    000
  • 如何使用 C++ 函数指针传递和调用函数?

    函数指针允许将函数作为参数传递,使函数调用更加灵活。您可以声明函数指针、传递参数,并通过指针运算符调用指向的函数。通过函数指针可以实现动态调度、排序算法选择等高级功能。 如何使用 C++ 函数指针传递和调用函数 函数指针是一种特殊类型的指针,它指向一个函数。函数指针使我们可以将函数作为参数传递给其他…

    2025年12月18日
    000
  • C++ lambda 表达式如何捕获外部变量?

    在 c++++ 中捕获外部变量的 lambda 表达式有三种方法:按值捕获:创建一个变量副本。按引用捕获:获得变量引用。同时按值和引用捕获:允许捕获多个变量,按值或按引用。 C++ lambda 表达式:捕获外部变量 lambda 表达式是 C++ 中强大的工具,它允许我们在函数中定义匿名函数。有时…

    2025年12月18日
    000
  • C++ 函数指针与 lambda 表达式的比较和对比是什么?

    函数指针和 lambda 表达式都是 c++++ 中封装代码块的技术,各有不同。函数指针是指向函数内存地址的常量指针,而 lambda 表达式是匿名函数,语法更灵活,可捕获外部变量。函数指针适合类型安全和低开销的场景,lambda 表达式适合需要匿名性和捕获外部变量的场景。 C++ 函数指针与 La…

    2025年12月18日
    000
  • C++ 递归函数在树数据结构中的应用?

    递归函数在处理树形数据结构时有如下应用:基本概念:递归函数调用自身分解大问题为小问题。遍历树形结构:前序遍历:访问节点前访问子节点。后序遍历:访问节点后访问子节点。实战案例:前序遍历二叉树,输出二叉树中节点值。 C++ 递归函数在树数据结构中的应用 递归函数在处理树形数据结构时非常有用。树形结构是一…

    2025年12月18日
    000
  • 用 C++ lambda 表达式实现多线程编程的优势是什么?

    lambda 表达式在 c++++ 多线程编程中的优势包括:简洁性、灵活性、易于传参和并行性。实战案例:使用 lambda 表达式创建多线程​​,在不同线程中打印线程 id,展示了该方法的简洁和易用性。 用 C++ lambda 表达式实现多线程编程的优势 引言 lambda 表达式是 C++11 …

    2025年12月18日
    000
  • C++ lambda 表达式的性能优化有哪些技巧?

    优化 c++++ lambda 表达式的性能技巧包括:避免创建不必要的 lambda 对象通过 std::bind 显式捕获最小的对象使用 std::move 移动捕获的变量以避免复制优化 lambda 体,避免不必要的内存分配、重复计算和全局变量访问 C++ Lambda 表达式的性能优化技巧 L…

    2025年12月18日
    000

发表回复

登录后才能评论
关注微信