【Linux系列】打造你的数字车间:Linux 基础开发工具入门与精要 — gcc/g++ 编译

【Linux系列】打造你的数字车间:Linux 基础开发工具入门与精要 — gcc/g++ 编译
在这里插入图片描述



🫧 励志不掉头发的内向程序员个人主页
 ✨️ 个人专栏: 《C++语言》《Linux学习》

🌅偶尔悲伤,偶尔被幸福所完善


👓️博主简介:

在这里插入图片描述


文章目录


前言

上一章节讲解了 vim 编辑器,但是还没有说明我们的文件怎么编译成可执行文件,本章节我们便来讲解说明,这也是一个非常重要的内容,我们一起来看看吧。
在这里插入图片描述

一、编译流程

我们编译一般涉及 4 个流程,每个流程都有其作用,缺一不可。
  • 预处理(进行宏替换/去注释/条件编译/头文件展开等)
  • 编译(生成汇编)
  • 汇编(生成机器可识别代码)
  • 链接(生成可执行文件或库文件)

二、gcc 编译

gcc编译的作用就是用来编译我们 C 语言的文件的。编译时我们可以直接编译成可执行文件,也可以按照编译流程一步一步的编译。

2.1、直接生成可执行程序的 2 种方式

  • gcc [ 要编译的文件 ] -o [ 目标文件 ]
-rw-rw-r-- 1 zxl zxl 304 Sep 25 10:26 code.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.c -o mycode -rwxrwxr-x 1 zxl zxl 16000 Sep 25 11:24 mycode* zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ ./mycode hello world!
  • gcc -o [ 目标文件 ] [ 要编译的文件1 ] [ 要编译的文件2 ] [ 要编译的文件3 ] …
-rw-rw-r-- 1 zxl zxl 304 Sep 25 10:26 code.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -o mycode code.c -rwxrwxr-x 1 zxl zxl 16000 Sep 25 11:28 mycode* zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ ./mycode hello world!

2.2、gcc 编译选项

格式: gcc [ 选项 ] 要编译的文件 [ 选项 ] [ 目标文件 ]

预处理(进行宏替换)

  • 预处理功能主要包括宏定义、文件包含、条件编译、去注释等
  • 预处理指令是以 # 号开头的代码行
  • 选项 “ -E ”,该选项的作用是让 gcc 在预处理结束后停止编译过程
  • 选项 “ -o ” 是指目标文件,“ .i ” 文件为已经预处理过的 C 原始程序

例如:
代码:

// code.c// 头文件#include<stdio.h>// 宏替换#defineM100#defineNintmain(){printf("hello world!, %d\n", M);printf("hello world!\n");// 注释//printf("hello world!\n");//printf("hello world!\n");//printf("hello world!\n");printf("hello world!\n");// 条件编译#ifdefNprintf("hello N\n");#elseprintf("hello no N\n");#endifreturn0;}

编译(预处理):

-rw-rw-r-- 1 zxl zxl 368 Sep 25 11:47 code.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -E code.c -o code.i -rw-rw-r-- 1 zxl zxl 18053 Sep 25 11:48 code.i 

我们的 code.i 文件就是我们源文件在编译时预处理结束后就停止编译的文件。

在这里插入图片描述


此时我们预处理结束后头文件打开了,同时的宏被替换了,注释被去除的同时条件编译也执行了,所以就会成为上面的效果。

编译(生成汇编)

  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言
  • 用户可以使用 “ -S ” 选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码

编译(生成汇编):
我们可以拿 .c 文件直接进行生成汇编,也可以把已经预处理完成后的文件 .i 进行生成汇编。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -S code.i -o code.s # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -S code.c -o code.s -rw-rw-r-- 1 zxl zxl 924 Sep 25 13:48 code.s 

此时我们的代码就会被加工成汇编语言,同理 -S 只会把代码完成到生成汇编这一步,生成汇编后就停止下来了。

在这里插入图片描述



汇编(生成机器可识别代码)

  • 汇编阶段是把编译阶段生成的 “ .s ” 文件转成目标文件
  • 读者在此可使用选项 “ -c ” 就可看到汇编代码已转化为 “ .o ” 的⼆进制目标代码

编译(生成机器可识别代码):
同理,我们可以拿汇编之前生成的 .c、.i、.s 文件进行汇编。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code.c -o code.o # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code.i -o code.o # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code.s -o code.o -rw-rw-r-- 1 zxl zxl 1752 Sep 25 13:54 code.o 

此时我们的代码就会被加工成机器可识别代码,同理 -c 只会把代码完成到这一步就停止下来了。

在这里插入图片描述


此时我们的文件就已经变成二进制文件了。但是我们还没有办法运行,这是因为我们 .o 文件只不过是把我写的代码变成二进制文件了。但是我的代码中用到的各种头文件和各种库函数等,都没有编译进去,所以我们还得有一个连接阶段。

连接(生成可执行文件或库文件)

  • 在成功编译之后,就进入了链接阶段

编译(生成可执行文件或库文件):

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.c -o code # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.i -o code # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.s -o code # 或者 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.o -o code -rwxrwxr-x 1 zxl zxl 16000 Sep 25 14:02 code* zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ ./code hello world!, 100 hello world! hello world! hello N 

三、g++ 编译

gcc 编译是给我们 C 语言文件进行编译的, g++ 编译可以给我们 C 语言和 C++文件进行编译,它的编译方法和我们 gcc 一样,我们只要把前面的 gcc 变成 g++ 即可,这里就不过多赘述了。

四、静态库和动态库

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

有了这些库以后,我们想要去实现很多常用的功能,就没有必要从零开始造轮子,会有人把这些功能为我们写好,放到库中供我们使用。这样也统一了我们各功能,使其不会一个功能却有成千上百中实现方式。

Linux 当中,肯定也会提前安装很多动静态库,存在 /usr/lib64 目录文件中。

在这里插入图片描述


注意:
一个库的真实名字是它的名字去掉前面的 lib,再去掉 . 后面的后缀,剩下的就是库的真实名字了。

五、动态链接和静态链接

在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个 *.c 文件会形成一个 *.o ⽂件,为了满足前面说的依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个链接的过程就是静态链接。

静态链接的缺点很明显:

  • 浪费空间:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标⽂件都有依赖,如多个程序中都调用了 printf() 函数,则这多个程序中都含有 printf.o,所以同一个目标文件都在内存存在多个副本
  • 更新比较困难:因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。

静态链接的优点是:

  • 在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快
在这里插入图片描述

动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。动态链接只需要能够找到库中的对应方法的地址,即可让我们的方法调用起来。

在这里插入图片描述

动态链接其实远比静态链接要常用得多。比如我们查看下 code 这个可执行程序依赖的动态库,会发现它就⽤到了⼀个 C 动态链接库。
在 Linux 中可以使用 ldd [可执行文件名] 来查看我们的这个文件依赖什么库以及是什么链接。

-rwxrwxr-x 1 zxl zxl 16000 Sep 25 14:02 code* zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ ldd code linux-vdso.so.1 (0x00007ffdcb7f2000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd90923b000)/lib64/ld-linux-x86-64.so.2 (0x00007fd909471000)

这里面 libc.so.6 就是 C 的动态库,也叫 C 标准库。它的链接方式就是动态链接。

还可以使用 file [ 可执行文件名 ] 的指令来查看。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ file code code: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=73b57ba77bf13d1b9f3cee616c44215760563964,for GNU/Linux 3.2.0, not stripped 

从它的返回的字符串可以看到:

  • 64-bit:64位的
  • dynamically linked:动态链接

同时我们看动态库的文件大小为 16000。我们来看看如果是静态链接我们的文件大小会发生什么改变以及 file 和 ldd 会变成什么样子。
想要进行静态链接我们得在我们 gcc 命令后面加一个 -static 选项。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.c -o code -static -rwxrwxr-x 1 zxl zxl 900440 Sep 25 16:50 code*

我们可以看到我们的文件会变大非常多,将近 100 倍。这只是用了一个库的情况,要是有很多库,那就会非常浪费空间了。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ ldd code not a dynamic executable 

此时我们 ldd 后会发现它说我们不是一个动态可执行。

zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ file code code: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=6c381730b960e1b3426a6071c0283120d7bcef6e,for GNU/Linux 3.2.0, not stripped 

file 后显示 statically linked(静态链接)的 executable(可执行程序)。

注意:
我们之所以能够使用动静态库是因为我们 Linux 早就预装了这些库在我们 /usr/lib64 目录下,如果没有预装库,那就会报错,解决办法就是去网上找到这些库然后去安装,这也就是为什么有的时候我们直接复制别人网上的代码却发现运行不了的原因。

我们说了动静态库的和我们的函数的链接,那我们如何将我们自己写的库和我们的函数链接呢?

其实很简单,让我们的库和我们的函数一起形成一个可执行文件即可。如下我们把 code1.h、code1.c、code2.h、code2.c 和我们 code.c 文件进行链接形成可执行文件。

-rw-rw-r-- 1 zxl zxl 0 Sep 25 17:16 code1.h -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:16 code1.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:16 code2.h -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:16 code2.c -rw-rw-r-- 1 zxl zxl 368 Sep 25 11:47 code.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code1.c code2.c code.c -o code -rwxrwxr-x 1 zxl zxl 16000 Sep 25 17:17 code*

当然,如果你不想让别人看到你的源文件,就比如你把这个代码给室友,让其完成作业,但是你不想让他知道你的代码是怎么实现的,此时你可以把你的 * .c 文件把它编译成 * .o 文件,然后让 * .o 文件和别的文件进行链接,这样就不会被别人知道你的代码是怎么实现的了(*.h 不用加密,因为如果加密了别人就不知道怎么使用你写的函数了)。

-rw-rw-r-- 1 zxl zxl 0 Sep 25 17:27 code1.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:28 code1.h -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:27 code2.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:28 code2.h -rw-rw-r-- 1 zxl zxl 368 Sep 25 11:47 code.c # 不写 -o 已经后面的目标文件,系统会自动生成要编译的文件名加相应的后缀的文件 zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code1.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code2.c zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc -c code.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:27 code1.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:28 code1.h -rw-rw-r-- 1 zxl zxl 936 Sep 25 17:29 code1.o -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:27 code2.c -rw-rw-r-- 1 zxl zxl 0 Sep 25 17:28 code2.h -rw-rw-r-- 1 zxl zxl 936 Sep 25 17:29 code2.o -rw-rw-r-- 1 zxl zxl 368 Sep 25 11:47 code.c -rw-rw-r-- 1 zxl zxl 1752 Sep 25 17:36 code.o zxl@iv-ye423qlwxsqc6ikwbogx:~/lesson1$ gcc code.o code1.o code2.o -o code -rwxrwxr-x 1 zxl zxl 16064 Sep 25 17:37 code*


总结

我们动静态库在后面会有一章用来专门讲解,所以大家能够大致了解即可,这里我们能够知道我们写的代码文件能够如何进行编译形成可执行的文件即可。剩下的我们后面会来讲解的,我们下一章节再见。

🎇坚持到这里已经很厉害啦,辛苦啦🎇ʕ • ᴥ • ʔづ♡ど

Read more

假网站排全网第二,真官网翻五页都找不到!NanoClaw创始人破防:SEO之战,我快要输了

假网站排全网第二,真官网翻五页都找不到!NanoClaw创始人破防:SEO之战,我快要输了

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 自从 OpenClaw 爆火之后,各种“Claw”项目接连出现,其中以安全优化版 NanoClaw 最为知名。它的核心代码仅有 4000 行,却获得了 AI 大牛 Andrej Karpathy 的点赞。 可谁也没想到,这款口碑极佳的开源项目,近来竟被一个仿冒网站抢了风头。 投诉无门之下,NanoClaw 创始人 Gavriel Cohen 在 X 社交平台上无奈发文怒斥:谷歌搜索错误地将假网站排在真官网前面,不仅破坏了项目声誉,还埋下了严重的安全隐患,而他费尽心力,却只能哀叹一句——“我正在为自己的开源项目打 SEO 战,但我快要输了。” 那么,NanoClaw 究竟发生了什么?又是怎么走红的?事情还要从 OpenClaw

By Ne0inhk
曝Windows 12将于今年发布?以AI为核心、NPU成「硬件门槛」,网友吐槽:“不想要的全塞进来了”

曝Windows 12将于今年发布?以AI为核心、NPU成「硬件门槛」,网友吐槽:“不想要的全塞进来了”

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 当年,微软一句“Windows 10 将是最后一个版本”的表态,让不少用户以为 Windows 进入了“只更新、不换代”的时代。但几年过去,现实却完全不同。 在 Windows 11 发布之后,如今关于 Windows 12 的传闻再次密集出现。从内部代号、代码片段,到硬件厂商的暗示与 OEM 预热标签,种种线索拼在一起,勾勒出一个明显的趋势——这不会只是一次常规升级,而更像是一次围绕 AI 的平台级重构。 更关键的是,这次争议,可能远比当年 TPM 2.0 更大。 精准卡位 Windows 10 退场的时间?

By Ne0inhk
Python热度下滑、AI能取代搜索引擎?TIOBE最新榜单揭晓!

Python热度下滑、AI能取代搜索引擎?TIOBE最新榜单揭晓!

整理 | 屠敏 出品 | ZEEKLOG(ID:ZEEKLOGnews) 日前,TIOBE 发布了最新的 3 月编程语言榜单。整体来看,本月排名变化不算大,但榜单中仍然出现了一些值得关注的小波动。  AI 工具能帮大家秒懂最新编程语言趋势? 由于 2 月天数较少,3 月的榜单整体变化有限。借着这次发布,TIOBE CEO Paul Jansen 也回应了一个最近被频繁讨论的问题:为什么 TIOBE 指数仍然依赖搜索引擎统计结果?在大语言模型流行的今天,直接询问 AI 哪些编程语言最流行,是不是更简单? 对此,Jansen 的回答是否定的。 他解释称,TIOBE 指数本质上统计的是互联网上关于某种编程语言的网页数量。而大语言模型的训练数据同样来自这些网页内容,因此从信息来源来看,两者并没有本质区别。换句话说,LLM 的判断,本质上也是建立在这些网页数据之上的。 Python 活跃度仍在下降

By Ne0inhk
“裸奔龙虾”数量已达27万只,业内人士警告;AI浪潮下,中传“砍掉”翻译等16个专业;薪资谈判破裂,三星电子8.9万人要罢工 | 极客头条

“裸奔龙虾”数量已达27万只,业内人士警告;AI浪潮下,中传“砍掉”翻译等16个专业;薪资谈判破裂,三星电子8.9万人要罢工 | 极客头条

「极客头条」—— 技术人员的新闻圈! ZEEKLOG 的读者朋友们好,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。(投稿或寻求报道:[email protected]) 整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 一分钟速览新闻点! * “裸奔龙虾”已高达27万只!业内人士警告:一旦黑客入侵,敏感信息一秒搬空 * 阿里云 CTO 周靖人代管千问模型一号位,刘大一恒管理更多团队 * 中国传媒大学砍掉翻译、摄影等 16 个本科专业,直言教育要面向人机分工时代 * 雷军放话:小米将很快推出 L3、L4 的驾驶 * 消息称原理想汽车智驾一号位郎咸朋具身智能赛道创业 * vivo 前产品经理宋紫薇创业,瞄准 AI 时尚Agent,获亿元融资 * MiniMax 发布龙虾新技能,股价暴涨超 23% * 薪资谈判破裂,三星电子

By Ne0inhk