【linux】基本工具gcc/g++及Makefile

2023-10-27


一、程序翻译过程

在C语言的最后几节我们讲到了一个程序是如何进行编译链接的,这里我们回顾一下前面的知识,然后开始新的内容

1、程序的翻译过程

1、预处理(也可以叫做 预编译):头文件展开,自动删除注释,宏的自动替换,条件编译…
2、编译:把我们的C语言代码转换成为汇编代码
3、汇编:把汇编代码转换为二进制(不是可执行的,二进制目标文件不能被执行)
4、链接:把我们写的C语言代码和C标准库中的代码合起来

2、理解选项的含义

在linux中,我们如果直接gcc/g++ test.c(文件名),就会跳过上面的4个步骤,直接生成最终的a.out可执行程序(对应windows下面的.exe文件),所以我们在linux中,一步步操作,这样便于理解:

在这里插入图片描述

3、动态链接与静态链接

我们写的C语言代码中,写入的scanf和printf等等函数,并不是我们写好的,而是C标准库提供给我们的接口,我们直接拿来使用就行了。我们只是调用了库函数,并没有对应的实现!只有当链接的时候,对应的实现才和我们的代码关联起来。这就有了链接

链接本质:我们调用库函数的时候和标准库如何关联的问题
这种关联就包括动态和静态

• 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
• 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。gcc hello.o –o hello
• gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

总结:

动态链接:受库升级或者被删除的影响,形成的可执行程序小,节约资源
静态链接:不受库升级或者被删除的影响,形成的可执行程序大,网络、磁盘、内存

linux下的命名:

• 动态库 : lib XXXXX .so

• 静态库 : lib XXXXX .a

去掉前缀lib和对应的后缀就是库的名字。举例:libc.so.6就是C的标准库

对于动态库和静态库而言,动态库是系统自带的,我们安装系统之后就可以直接使用;静态库则需要我们安装的,也就是说:静态库并不是直接拷贝动态库的内容。

安装静态库的命令:sudo yum install -y glibc-static

安装完成之后,在原来的命令后面加上 -static,就是静态库编译了:

在这里插入图片描述

系统为了支持我们编程,给我们提供了标准库.h(告诉我们怎么用)标准的动态库和静态库.so/.a(告诉我们方法实现有,直接去找就可以)
windows下的动态库:.dll 静态库:.lib
我的代码+库的代码=可执行程序!


二、Linux项目自动化构建工具-make/Makefile

1、背景

1、 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
2、一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
3、makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
4、make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
5、make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

2、实例说明

对于makefile,想要使用make命令,必须要有makefile名字的文件(m可以大写为M)。在makefile内部编写一定的依赖规则之后,我们使用make就可以执行对应程序了,可以省略gcc test.c -o test
的编译命令

步骤1:创建一个makefile文件,并且在makefile文件里面编辑好对应的依赖关系依赖方法

在这里插入图片描述
在这里插入图片描述
步骤2:make执行程序
在这里插入图片描述
这样就不用再写gcc编译了

3、原理

makefile的原理最核心的就是:依赖关系和依赖方法
对于上面的样例来说:

makefile文件中,第一行表示依赖关系:mycode文件依赖于mycode.c实现的,mycode依赖于mycode.c。但仅仅有依赖关系是不够的,还要知道什么原因才依赖的,这就是依赖方法。第二行中,mycode是经过gcc编译生成的,即gcc就是依赖方法

4、语法

在这里插入图片描述
上图第一行仍然依赖关系,当时下面必须是tap键的空格,而不是我们直接按空格键

** .PHONY:被关键字修饰的对象是一个伪目标,这个伪目标总是被执行的

我们使用make clear就可以删除mycode文件

那么怎么理解:伪目标总是被执行的这句话呢?
在这里插入图片描述
但是如果修改makefile文件:
在这里插入图片描述
在这里插入图片描述
注意:对于makefile来说,第一条指令是默认规定直接make就可以执行的,比如上面的gcc

5、为什么gcc不更新文件

上面我们可以看到gcc对于最新版本的可执行文件是不会执行成功的,这是因为:mycode.c的modify时间比mycode的modify时间早,即在最新的mycode.c生成的mycode是不会被gcc再次执行的,除非把mycode.c的modfiy时间更改到比mycode的modfiy时间晚,才能执行gcc

但是如果.PHONY修饰之后,就能够执行是因为:.PHONY修饰之后,就不遵循这个所谓的时间规则

6、推导规则

我们按照上面程序翻译过程的步骤来拆分,最终结果是一样的
在这里插入图片描述

在这里插入图片描述

对于makefile内部的依赖关系来说,mycode依赖于mycode.o,但是此时并没有mycode.o,所以就要寻找mycode.o的依赖对象mycode.s,mycode.s继续找它的依赖对象mycode.i,mycode.i继续找它的依赖对象mycode.c。因为mycode.c存在,所以执行程序是从下到上的

这里我们只是推导,实际中我们没必要这么麻烦,直接一条gcc指令就可以完成


三、小程序——进度条

我们直接基于上面的mycode.c文件里面写

1、sleep 和 \n

在这里插入图片描述在这里插入图片描述

我们可以看到,明明printf在sleep前面执行的,为什么是先休眠2秒,再打印出you can see me …呢?

实际上,这就是一个缓冲区的问题,我们的确先执行的printf,后执行的sleep,但是先执行的printf不是直接打印在显示器上面的,而是进入了缓冲区。这就是为什么先休眠了2秒再打印内容的

2、行缓冲区概念

但是我们加上\n就不会先休眠再打印内容,可以直接先打印出内容,只是为什么呢?

这是因为:\n具有刷新缓冲区的作用,我们把\n称为行缓冲

我们来看看:
在这里插入图片描述

在这里插入图片描述

我们可以看到是先打印内容,再休眠2秒

3、\r 和 \n

\r :回车
\n :换行
在语法层面上\n既有回车,又有换行的作用,但是原始作用要区分清楚

在这里插入图片描述
在这里插入图片描述

不显示的原因就是我们回车\r将之前的内容全部覆盖掉了,并且在缓冲区也回到了起始位置,导致了程序结束也没有打印

4、fflush(stdout)

在这里插入图片描述

在这里插入图片描述

5、倒计时的实现

在这里插入图片描述
我们知道\r是回到起始位置,但是不控制格式为2d的话,打印结果为10,90,80,70,60…,所以我们要覆盖第一个位置,采用2d控制格式,并且fflush(stdout)
在这里插入图片描述

6、进度条实现

我们和学习数据结构的时候一样,采用三个文件的方式进行:

makefile:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【linux】基本工具gcc/g++及Makefile 的相关文章

  • 在 Linux 上更快地分叉大型进程?

    在现代 Linux 上达到与 Linux 相同效果的最快 最好的方法是什么 fork execve combo 从一个大的过程 我的问题是进程分叉大约 500MByte 大 并且一个简单的基准测试只能从进程中实现约 50 个分叉 秒 比较最
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 抑制 makefile 中命令调用的回显?

    我为一个作业编写了一个程序 该程序应该将其输出打印到标准输出 分配规范需要创建一个 Makefile 当调用它时make run gt outputFile应该运行该程序并将输出写入一个文件 该文件的 SHA1 指纹与规范中给出的指纹相同
  • 如何检测并找出程序是否陷入死锁?

    这是一道面试题 如何检测并确定程序是否陷入死锁 是否有一些工具可用于在 Linux Unix 系统上执行此操作 我的想法 如果程序没有任何进展并且其状态为运行 则为死锁 但是 其他原因也可能导致此问题 开源工具有valgrind halgr
  • 如何使用 bash 锁定文件

    我有一个任务从远程服务器同步目录 rsync av email protected cdn cgi l email protection srv data srv data 为了使其定期运行并避免脚本 reEnter 问题 我使用 rsyn
  • 如何使用 xterm.js 创建基于 Web 的终端以 ssh 进入本地网络上的系统

    我偶然发现了这个很棒的图书馆xterm js https xtermjs org 这也是 Visual Studio Code 终端的基础 我有一个非常普遍的问题 我想通过基于网络的终端 不在网络中 可能位于 aws 服务器上 访问本地网络
  • 应用程序无缘无故地被杀死。怀疑 BSS 高。如何调试呢?

    我已经在CentOs6 6中成功运行我的应用程序 最近 硬件 主板和内存 更新了 我的应用程序现在毫无理由地被杀死 root localhost PktBlaster PktBlaster Killed 文件和 ldd 输出 root lo
  • nginx 上的多个网站和可用网站

    通过 nginx 的基本安装 您的sites available文件夹只有一个文件 default 怎么样sites available文件夹的工作原理以及如何使用它来托管多个 单独的 网站 只是为了添加另一种方法 您可以为您托管的每个虚拟
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • chown:不允许操作

    我有问题 我需要通过 php 脚本为系统中的不同用户设置文件所有者权限 所以我通过以下命令执行此操作 其中 1002 是系统的用户 ID file put contents filename content system chown 100
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • arm64和armhf有什么区别?

    Raspberry Pi Type 3 具有 64 位 CPU 但其架构不是arm64 but armhf 有什么区别arm64 and armhf armhf代表 arm hard float 是给定的名称Debian 端口 https
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • Pyaudio 安装错误 - “命令‘gcc’失败,退出状态 1”

    我正在运行 Ubuntu 11 04 Python 2 7 1 并想安装 Pyaudio 于是我跑了 sudo easy install pyaudio 在终端中 进程退出并显示以下错误消息 Searching for pyaudio Re
  • 如何在Linux内核源代码中打印IP地址或MAC地址

    我必须通过修改 Linux 内核源代码来稍微改变 TCP 拥塞控制算法 但为了检查结果是否正确 我需要记录 MAC 或 IP 地址信息 我使用 PRINTK 函数来打印内核消息 但我感觉很难打印出主机的MAC IP地址 printk pM
  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 如何在shell中输出返回码?

    我正在尝试通过调用自定义 shell 脚本sh bin sh c myscript sh gt log txt 2 gt 1 echo 该命令的输出是创建的后台进程的 PID 我想指导 bin sh保存返回码myscript sh到某个文件
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • Linux 中什么处理 ping?

    我想覆盖 更改 linux 处理 ping icmp echo 请求数据包的方式 这意味着我想运行自己的服务器来回复传入的 icmp 回显请求或其他 数据包 但为了使其正常工作 我想我需要禁用 Linux 的默认 ping icmp 数据包
  • ubuntu:升级软件(cmake)-版本消歧(本地编译)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我的机器上安装了 cmake 2 8 0 来自 ubuntu 软件包 二进制文件放置在 usr bin cmake 中 我需要将 cmake 版本至少

随机推荐

  • vue生命周期

    随着对 vue 的不断了解 会越来越发现它生命周期的重要性 只有了解了它的生命周期 才能在开发项目的时候在逻辑上的很好的判断什么时候该发生什么事件 即很好的控制页面 一 什么是 vue 生命周期 Vue 实例从创建到销毁的过程 就是生命周期
  • kong+Verdaccio+ldap(docker)

    需求 使用Kong来代理Verdaccio 实现直接通过域名 path的方式来访问 并且Verdaccio使用ldap来管理 前提 Kong ldap已部署好 并且也部署好了Kong Dashboard 后面有需求再写关于Kong代理的各种
  • 国内的Ubuntu镜像源

    国内的Ubuntu镜像源 Ubuntu清华镜像源 今天学习docker需要在线Ubuntu镜像 所以做了一个镜像下载地址笔记 方面以后的下载 官方镜像下载访问地址 https cn ubuntu com download alternati
  • 明哥复习MyBatis(1)

    这不是原创 借鉴尚硅谷的 不是原创 一 核心配置文件详解
  • impdp或expdp报错ORA-39002: invalid operation,ORA-39070: Unable to open the log file

    oracle oracle rac01 backup cat expdp par USERID as sysdba DIRECTORY KMDATA EXP job name jinky exp filesize 5000m paralle
  • Java集合——Iterable和Iterator接口介绍

    Iterable Iterable和Iterator是什么 Iterable源码 Iterator源码 使用 Iterable和Iterator是什么 Iterable是Collection的实现接口 即是集合的最顶级父类 Iterator
  • 小白学股票基金_2

    到底是买股票还是买基金 说基金和股票差不多指的应该是偏股型基金 但是基金里面还有债券型 QDII以及非常大众化的货币型基金 众所周知的余额宝就是一款货币型基金啦 等等 风险等级也不一样 所以 为防止这样混为一谈 我们这里讨论的就是炒股和买偏
  • 0.0 Windows + Linux(Ubuntu20.04) 超简单的双系统安装

    目录 一 U盘启动盘的制作 1 下载操作系统 2 下载U启动制作工具 二 磁盘分配 三 Ubuntu20 04系统安装 1 修改bios为U启动 2 安装配置Ubuntu 2 1 Install Ubuntu 2 2 安装关键之处在于分区
  • 4年经验来面试20K的测试岗,连基础都不会,还不如招应届生!

    公司前段时间缺人 也面了不少测试 结果竟然没有一个合适的 一开始瞄准的就是中级的水准 也没指望来大牛 提供的薪资在10 20k 面试的人很多 但平均水平很让人失望 看简历很多都是3 4年工作经验 但面试中 不提工具和编程 仅仅基础的技术很多
  • Flink简单教学5-时间

    时间 Time Flink支持三种不同的时间 处理时间 processing time 指当前操作的时间 如 map 当程序以处理时间运行 所有基于时间的操作 窗口 都依赖各个operator的机器时间 事件时间 event time 事件
  • office 2010 projectn visio 下载

    Office 2010 project专业版 64位 ed2k file cn project professional 2010 x64 515551 exe 453437272 84D14496F889767D46C9DE576154B
  • 矩阵的基本演算

    目录 转置 逆 迹 行列式 转置 A B T
  • 网易低代码引擎Tango正式开源

    一 Tango简介 Tango 是一个用于快速构建低代码平台的低代码设计器框架 借助 Tango 只需要数行代码就可以完成一个基本的低代码平台前端系统的搭建 Tango 低代码设计器直接读取前端项目的源代码 并以源代码为中心 执行和渲染前端
  • element ui Tag 动态添加标签

    1 首先调接口获取到标签列表 级联选择器如果选择的不是第三级菜单 async getParamsData if this selectedCateKeys length 3 级联选择器不会有参数 下面的面板也都为空 this selecte
  • 三层架构到DDD四层架构演进

    应用架构演化 三层架构 三层架构 为什么还画了一层 Model 呢 因为 Model 只是简单的 Java Bean 里面只有数据库表对应的属性 有的应用会将其单独拎出来作为一个 但实际上可以合并到 DAO 层 第一步 数据模型与DAO层合
  • 检测是否为快乐数

    编写一个算法来判断一个数 n 是不是快乐数 快乐数 定义为 1 对于一个正整数 每一次将该数替换为它每个位置上的数字的平方和 2 然后重复这个过程直到这个数变为 1 也可能是 无限循环 但始终变不到 1 3 如果可以变为1 那么这个数就是快
  • MySQL类型定义 - 字符串类型

    1 char类型 1 CHAR类型和VARCHAR类型 CHAR类型和VARCHAR类型都在创建表时指定了最大长度 其基本形式如下 字符串类型 M 其中 字符串类型 参数指定了数据类型为CHAR类型还是VARCHAR类型 M参数指定了该字符
  • 数据结构 —七大排序算法(图文详细版)

    文章目录 前言 一 插入排序 1 直接插入排序 1 原理 2 实现 3 稳定性 时间复杂度 2 希尔排序 1 原理 2 具体实现 3 稳定性 时间复杂度 二 选择排序 1 直接选择排序 1 原理 2 具体实现 3 稳定性 时间复杂度 4 优
  • chromebook刷_使用Chromebook编码

    chromebook刷 Chromebooks are awesome They re relatively simple and inexpensive devices that run Chrome OS a stripped down
  • 【linux】基本工具gcc/g++及Makefile

    文章目录 一 程序翻译过程 1 程序的翻译过程 2 理解选项的含义 3 动态链接与静态链接 二 Linux项目自动化构建工具 make Make le 1 背景 2 实例说明 3 原理 4 语法 5 为什么gcc不更新文件 6 推导规则 三