【Linux】gcc与make、makefile

文章目录

  • 1 gcc/g++
    • 1.1 预处理
    • 1.2 编译
    • 1.3 汇编
    • 1.4 链接
      • 1.4.1 静态链接
      • 1.4.2 动态链接
  • 2 make和makefile
    • 2.1 依赖关系
    • 2.2 依赖方法
    • 2.3 伪目标
  • 3 总结

1 gcc/g++

在这里插入图片描述
当我们创建一个文件,并向里面写入代码,此时,我们该如何使我们的代码能够运行起来呢?

如果是在windows的vs下,只需要点击运行就行了,现在在Linux下,该如何运行?

我们需要使用gcc编译器来编译已经写好的test.c源文件

编译之后,会在当前目录之下生成可执行程序,运行可执行程序即可

在这里插入图片描述
使用红框中的命令gcc test.c -o test 就完成了对源文件的编译。

之后,生成了可执行程序test.

运行test即可执行我们的可执行程序。

补充:c语言的程序用gcc编译,c++的程序用g++编译

  • 格式:
    gcc - 选项 源文件名 -o 目标文件名
  • 选项:
    -E 从当前文件开始,在预处理完成之后停止, 生成的文件后缀一般加i
    -S 从当前文件开始,在编译完成之后停止, 生成的文件后缀一般加s
    -c 从当前文件开始,在汇编完成之后停止, 生成的文件后缀一般加o

1.1 预处理

预处理的作用:

  1. 去除注释
  2. 展开头文件
  3. 处理条件编译
  4. 进行宏替换

命令: gcc -E 文件名.c -o 文件名.i

在这里插入图片描述
左边是test.c文件,右边是test.i文件(预处理文件)
在这里插入图片描述

1.2 编译

命令: gcc -S 文件名.i -o 文件名.s
功能:将预处理文件编译成汇编语言
在这里插入图片描述

在这里插入图片描述

1.3 汇编

命令: gcc -c 文件名.s -o 文件名.o
功能:将编译生成的.s文件中的内容转变成机器能识别的二进制机器码。
在这里插入图片描述
可以通过od命令查看.o文件
将二进制机器码以十六进制的形式显示出来。
在这里插入图片描述

1.4 链接

到这一步时候,我们的文件是,o的汇编文件。

这里有一个问题:我们写的程序中,使用到了printf()函数,但是我们并没有写printf()函数的实现方法和定义等,为什么执行程序的时候不会报错?

因为我们使用了库函数

printf()函数很明显是库函数。假设我们不包含<stdio.h>头文件,我们的程序必然会报错。

我们包了<stdio.h>文件之后就能使用了吗?

也不是,因为我们知道.h只是一个头文件,相当于有一个函数的声明,但是没有函数的具体定义,函数的具体定义肯定是一个文件。

假设库的创建者写了1000个函数,分为两个文件。其中,函数的实现叫做c和定义叫做c.h。

库的创建者不想给我们看函数的具体实现。所以对这个库进行的封装。但是他必须提供库的使用方法,所以又把头文件给了我们,提供给我们具体的使用方法。

我们通过头文件得知使用方法之后,在我们的c程序执行到库函数时候,就会链接到库中的库函数。库函数也是.o目标文件,将我们自己的程序和库函数链接到一起,就会生成可执行程序.exe。

那么,该如何找到库呢?

在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找。

链接的库分为静态库和动态库。

1.4.1 静态链接

在这里插入图片描述

  1. 当我们的函数执行到库函数的时候,跳转到链接的库函数,将库函数中该函数的实现拷贝到当前程序文件中。
  2. 再此之后再生成可执行文件。

静态链接的指令gcc 文件名.o -o 文件名 -static

在这里插入图片描述

1.4.2 动态链接

在这里插入图片描述

  1. 当执行到库函数时,跳转到动态库中,找到该函数的.o文件,去链接标准库中库函数的.o文件。
  2. 链接完之后再跳转回来。

在这里插入图片描述
在这里插入图片描述
通过ldd命令可以查看a.out链接的动态库。
图中的红框就是我们链接的动态库c

库的名称为去掉前缀去掉后缀,图中就是去掉前缀lib,去掉后缀.so,最后得到c

通过file指令查看文件的属性
在这里插入图片描述
黄色框中说明这是一个动态链接,链接的是动态库。

动态链接和静态链接的区别是什么?
在这里插入图片描述
通过上图可以看出静态链接比动态链接之后的文件大很多。

这是因为动态链接是直接跳转,而静态链接是将静态库中的内容拷贝到文件中

总结

  • 静态库或者动态库一个系统只有一个,所有使用系统的用户都在使用同一个库。
  • 静态链接后的可执行程序不会受到静态库升级或者被删除的影响,而动态库会受到影响。
  • 系统为了我们编程,提供了标准库的头文件.h,和动静态库.so/.a,头文件是为了告诉我们怎么使用库函数,动静态库中提供了库函数的具体实现方法。

2 make和makefile

make 是方法,makefile是文件

创建makefile文件
在这里插入图片描述
写入makefile文件
在这里插入图片描述

效果
在这里插入图片描述
从上面的操作中,我们可以看到,以前我们每次编译文件,都需要输入gcc等一系列命令。现在只需要使用make,就自动编译成功了。

  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。

接下来分步解析。

2.1 依赖关系

什么是依赖关系?
a:b -----> 叫做a依赖b,有了b的存在才会有a的存在。

在makefile中,gcc编译的时候有哪些依赖关系呢?

在这里插入图片描述

2.2 依赖方法

依赖关系解决的谁以来谁的问题

依赖方法解决的是怎样依赖的问题

在这里插入图片描述
红框的内容就是依赖方法

在makefile中依赖关系和依赖方法是必须写的,并且必须是一一对应的

2.3 伪目标

在makefile中同样是可以删除文件的。

在这里插入图片描述
执行情况
在这里插入图片描述
其中,.PHONY:clean 这句话中.PHONY就是伪目标,clean被.PHONY修饰的

  • 被.PHONY修饰的对象就是一个伪目标。
  • 伪目标总是被执行。

如何理解伪目标总是被执行这句话?

首先理解什么文件不是总被执行。

在这里插入图片描述
可以看到,在执行第一次make的时候,可以正常执行;执行第二次make的时候就不能了。

为什么呢?

在这里插入图片描述

在使用stat命令之后,可以看到一个文件的ACM时间,分别是图上所示。

我们使用ll命令显示的就是文件的内容修改时间

在这里插入图片描述

可以看到test.c文件的最后一次被修改时间比test的最后一次被修改时间早。

这就意味着:可执行文件如果再次执行,其实内容是没有改变的。

如果test.c文件在test文件之后又被修改过,那么Modify时间应该比test文件的时间晚,这样再次编译的时候才会有效果。而如果test.c的时间比test时间早,说明test.c文件没有被修改过。因此也就没有再次编译的必要。

这是编译器为了更高效的举动。

验证
在这里插入图片描述
从上面可以知道,make不是总被执行,那么。伪目标是总被执行的,怎么验证?

在这里插入图片描述
只要执行make clean 就一直会执行,不会出现阻碍。

而clean正是被.PHONY修饰的伪目标

在这里插入图片描述

执行:
在这里插入图片描述
发现给make加上伪目标之后,make也总是被执行。

**clean:**之后没有东西,说明依赖关系也可以为空

3 总结

  1. 编译链接分为:预处理、编译、汇编、链接四个部分。使用到的命令如下:
    在这里插入图片描述
  • .c文件预处理变成.i文件
  • .i文件编译变成.s文件
  • .s文件汇编变成.o文件
  • .o文件链接变成可执行程序

其中,链接分为动态链接和静态链接。
静态链接将静态库中的.o程序拷贝到我们的程序,执行静态链接需要到系统默认的路径usr/lib中去找静态库,如果找不到就会报链接错误。

如果使用的是第三方库,需要用特定的方法链接到库。

  1. makefile中有:依赖关系,依赖方法和伪目标。
    其中,依赖关系和依赖方法是一一对应的。
    依赖关系也可以为空。

伪目标.PHONY表示总是执行

没有伪目标的文件通过判断文件的Modify时间来决定是否编译:

  1. 如果.c文件的Modify时间于可执行文件 ---- 不执行
  2. 如果.c文件的Modify时间于可执行文件 ---- 执行

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

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

相关文章

html--心花怒放

代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Canvas 绘制一个❤</title><link rel"shortcut icon" href"../../assets/images/icon/favicon.ico" type"ima…

c++ primer中文版第五版作业第十五章

仓库地址 文章目录 15.115.215.315.415.515.615.715.815.915.1015.1115.1215.1315.1415.1515.1615.1715.1815.1915.2015.2115.2215.2315.2415.2515.2615.2615.2815.2915.3015.3115.3215.3315.3415.3515.3615.3715.3815.3915.4015.4115.42 15.1 基类希望其派生类进行覆盖的函数&…

C#实现快速排序算法

C#实现快速排序算法 以下是C#中的快速排序算法实现示例&#xff1a; using System;class QuickSort {// 快速排序入口函数public static void Sort(int[] array){QuickSortRecursive(array, 0, array.Length - 1);}// 递归函数实现快速排序private static void QuickSortRecu…

springboot配置Redis缓存多节点

随着微服务架构的广泛应用&#xff0c;分布式缓存系统在提升系统性能、降低数据库压力方面起着关键作用。Redis作为高性能的内存键值对数据库&#xff0c;凭借其丰富的数据结构和高速读写能力&#xff0c;在众多缓存解决方案中脱颖而出。在Spring Boot框架中&#xff0c;我们可…

Python 潮流周刊第 41 期(摘要),赠书5本

本周刊由 Python猫 出品&#xff0c;精心筛选国内外的 250 信息源&#xff0c;为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景&#xff1a;帮助所有读者精进 Python 技术&#xff0c;并增长职业和副业的收入。 周刊全文&#xff1a;h…

测试开发面试题|面试真题

📋 个人简介 作者简介:大家好,我是凝小飞,软件测试领域作者支持我:点赞👍+收藏⭐️+留言📝测试开发的面试题,一般会考一些基础的算法编程题,难度不是特别高,除非是大厂的那种卷,如下是我作为面试官整理的一些参考测试题,供参考 算法排序类 Python: 一、list…

ubuntu自带屏幕截图功能

目录 简介开始截屏步骤1.打开截屏软件2.选择区域3.截图 快捷键 录屏方法11.开始录屏2.停止录屏 方法2 补充说明 简介 试了好多开源跨平台截图软件&#xff0c;但是在ubuntu上都或多或少存在问题。ubuntu有自带的截图软件。打算把ubuntu自带的截图软件用起来。 顺便说一下我使…

B端系统升级,登录页必在升级之列,不容置疑。

进行B端界面升级时&#xff0c;首先升级登录页有以下几个原因&#xff1a; 用户体验&#xff1a;登录页是用户进入系统的第一个页面&#xff0c;用户首先接触到的界面。通过升级登录页&#xff0c;可以提升用户的第一印象&#xff0c;增强用户对系统的信任感和好感度&#xff…

Android Studio编译及调试知识

文章目录 Android Studio编译kotlin项目Android Studio编译Java和kotlin混合项目的过程gradle打印详细错误信息&#xff0c;类似这种工具的使用Android apk 从你的代码到APK打包的过程&#xff0c;APK安装到你的Android手机上的过程&#xff0c;最后安装好的形态&#xff0c;以…

简单形状点云轮廓点排序(旋转角)

1、背景介绍 很多边缘提取算法提取的边缘点为无序点云&#xff0c;如下图所示&#xff0c;无序点云不利于后续各种应用&#xff0c;比如根据边缘计算点云面积、点云轮廓线规则化等。若对点云进行排序&#xff0c;则可以进行上述引用。但实际上&#xff0c;点云形状错综复杂&…

Dubbo 和 Zookeeper 的关系

Dubbo 和 Zookeeper 的关系 Zookeeper的作用 zookeeper用来注册服务和进行负载均衡&#xff0c;哪一个服务由哪一个机器来提供必需让调用者知道&#xff0c;简 单来说就是ip地址和服务名称的对应关系。当然也可以通过硬编码的方式把这种对应关系在调用方 业务代码中实现&#…

蓝桥杯第十四届真题 棋盘 二维差分数组

题目 小蓝拥有 nn 大小的棋盘&#xff0c;一开始棋盘上全都是白子。 小蓝进行了 m 次操作&#xff0c;每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色&#xff0c;黑色棋子变为白色)。 请输出所有操作做完后棋盘上每个棋子的颜色。 输入格式 输…

AVL树讲解

AVL树 1. 概念2. AVL节点的定义3. AVL树插入3.1 旋转 4.AVL树的验证 1. 概念 AVL树是一种自平衡二叉搜索树。它的每个节点的左子树和右子树的高度差&#xff08;平衡因子&#xff0c;我们这里按右子树高度减左子树高度&#xff09;的绝对值不超过1。AVL的左子树和右子树都是AV…

P8651 [蓝桥杯 2017 省 B] 日期问题---洛谷(题解)

这周周赛的题&#xff0c;我感觉我这题写的还是不错的&#xff0c;用到了上周周赛的口算题中别人题解的函数和最近了解substr还有去年天梯校赛有个日期检验的题&#xff0c;都有用到。 题目描述 小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都…

Rust 语言中的泛型

在Rust中&#xff0c;泛型&#xff08;Generics&#xff09;是一种允许你编写与多种不同数据类型一起工作的代码的方式。Rust主要通过两种方式来支持泛型&#xff1a;使用泛型函数和泛型结构体。下面是一些使用Rust泛型的示例。 一、泛型函数示例 fn add<T>(x: T, y: T…

MIT6.5840(6.824)Lab2总结(Raft)

MIT6.5840&#xff08;原MIT6.824&#xff09;Lab2总结&#xff08;Raft&#xff09; 资源分享&#xff1a; 官网地址&#xff1a;http://nil.csail.mit.edu/6.5840/2023/ Raft论文地址&#xff1a;http://nil.csail.mit.edu/6.5840/2023/papers/raft-extended.pdf 官方学生…

学习笔记 反悔贪心

0.写在前面 好久没更了&#xff0c;这周是开学第一周 A C M ACM ACM队临时安排讲课任务&#xff0c;没人讲&#xff0c;我就揽下来这活了。前两天有一道 c f cf cf的 d i v 2 C div2C div2C用到了反悔贪心这个技巧&#xff0c;也不需要什么前置算法就可以学&#xff0c;所以我…

JAVA循环中标记的作用

在Java循环中标记的作用是为循环语句提供一个标识符&#xff0c;使得程序可以在循环嵌套时跳出指定的循环。它可以用于在内部循环中控制外部循环&#xff0c;或者在多个嵌套循环中控制跳出特定的循环块。 标记通常与break和continue语句一起使用。使用break语句配合标记可以跳…

CentOS上安装与配置Nginx

CentOS上安装与配置Nginx Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;并在一个BSD-like协议下发行。以下是在CentOS系统上安装和配置Nginx的步骤。 &#x1f31f; 前言 欢迎来到我的小天地&#xff0c;这…

在深度学习中,时间、空间、通道三个维度是什么?

在深度学习中&#xff0c;时间、空间、通道三个维度是什么&#xff1f; 在深度学习中&#xff0c;时间、空间和通道是描述输入数据的三个主要维度。 空间维度&#xff08;Spatial Dimension&#xff09;&#xff1a; 指的是输入数据在空间中的排列方式。对于图像数据来说&…