【命令行魔法:掌握Linux基础工具开发的独门技艺】(三)

简介: 【命令行魔法:掌握Linux基础工具开发的独门技艺】

【命令行魔法:掌握Linux基础工具开发的独门技艺】(二):https://developer.aliyun.com/article/1425532


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


  • 在成功编译之后,就进入了链接阶段。
  • 实例: gcc/g++ code.o –o code 或者 gcc/g++ -o code code.o


在这里涉及到一个重要的概念:函数库


  • 一个平台要支持开发,就必须要提前在系统中安装语言的标准头文件+库文件
  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而 没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
  • 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到 系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函 数“printf”了,而这也就是链接的作用



问题:拿汇编语言举例,先有的汇编编程语言还是先有的汇编程编译器


这个问题似乎和先有蛋还是现有鸡的问题一样,其实不然,早期我们使用二进制写程序的,由于二进制写起来比较麻烦,所以出现了汇编语言,那么此时汇编语言由谁编译呢?肯定是汇编语言编译器,但是这个汇编语言编译器不会是用汇编语言写的,所以汇编语言编译器是用二进制去写的,汇编语言使用二进制编写的编译器去编译的,从而最后形成软件。编译器也是软件,后续就有人用汇编语言写了一个汇编语言编译器通过二进制编写的编译器去编译,最后才出现了我们的汇编语言编译器。对于先有的汇编编程语言还是先有的编程编译器,我们可以确定的是一定先有二进制编写的编译器。


函数库一般分为静态库和动态库两种。



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


动态库的优点:所有人都去网咖共享一台电脑,比较节省资源,不会出现太多的重复代码 --- 节省的是磁盘空间,内存和网络等资源。缺点:一旦网咖因为运营而关闭,所有人都不能使用了,对库的依赖性比较强,一旦库丢失,所有使用这个库的程序都无法运行。


静态库的优点:不依赖库,同类型平台中都可以直接使用。缺点:可执行程序体积比较大,比较浪费资源 --- 磁盘空间,内存和网络等资源。


gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。ldd可以查询一个可执行程序所依赖的库文件。


我们也可以通过指令对可执行程序进行静态链接:gcc -o mybin-static mytest.c -static


这里我们也可以发现静态链接形成的可执行程序大小非常大,静态链接是把库中得代码拷贝过来。


但是我们的云服务器默认是没有安装静态库的,所以我们执行:gcc -o mybin-static mytest.c -static 是会报错的


上面报错信息中ld是我们的链接器,-l是gcc的另外一个选项,c就是说明我们缺少一个c标准库,我们库的名称是去掉前缀lib和后缀.so.6。所以我们是需要安装我们的静态库的,执行指令:

sudo yum install -y glibc-static libstdc++-static


安装完我们可以直接去/lib64/libc.a路径下去查看我们安装的静态库


gcc选项


  • -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
  • -S  编译到汇编语言不进行汇编和链接
  • -c  编译到目标代码
  • -o 文件输出到 文件
  • -static 此选项对生成的文件采用静态链接
  • -g 生成调试信息。GNU 调试器可利用该信息。
  • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
  • -O0 -O1 -O2 -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
  • -w  不生成任何警告信息。
  • -Wall 生成所有警告信息。


4.Linux项目自动化构建工具-make/Makefile


4.1背景


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


我们先来创建一个makefile文件,然后vim打开makefile文件,输出内容:


然后我们在输入make指令就形成了可执行程序mybin。


4.2依赖关系和依赖方法


这里通过一个小故事了解一下它们之间的关系:

 月末了你已经没有生活费了,此时的你就会向你老爸要生活费,然后你向你老爸说了一句我是你的儿子,然后又说月末了我没有生活费了。对老爸说我是你的儿子这句话就是表面依赖关系,解释的是为什么我要帮你,月末了我没有生活费这句话就是具体的依赖方法,解释的是如何帮你。


如果我们再次输入make呢?


此时显示该文件不需要再编译,当前的mybin已经是最新文件了,我们并没有对源文件test.c进行过任何修改,所以源文件没有变化,我们的可执行程序再编译的结果是一样的,所以gcc也就不再编译了。如果我们改一下源文件,那么make会让我们再编译嘛?答案是可以滴。


这里提一个问题,make和makefile怎么知道当前文件时最新的呢?首先我们要清楚,如果这个源文件我们一直没有修改,就算过了一万年,他仍然是最新的,仍然是不可编译的,所以这个肯定是与我们现在所处的时间概念无关的。但是它肯定与时间有关,但是这个时间是对比出来的,常识告诉我们,改一个源文件就需要打开该源文件,修改之后该文件的修改时间就会被改变,只要可执行程序的最近修改时间比所有源文件最近的修改时间新,说明它就是最新的!


我们可以通过stat+filename查看文件的时间信息


当我们再次vim打开该文件进行修改,再次执行stat+filename


此时我们发现文件的Modify时间就发生了变化,然后我们再make指令编译一下源文件,再次执行stat+filename


我们可以发现mybin的时间永远是源文件test.c更新。通过stat我们可以查看到Modify时间,那么Change时间是什么呢?我们之前提到文件=内容+属性。Modify是对于文件内容而言的,而Change是对于文件属性来说的。通过ll指令查看的就是文件的属性:权限,拥有者和所属组等等。


通过给other去掉读权限,我们可以看到文件的Change时间发生变化


随后我们再对文件内容进行修改,此时会发生什么呢?


我们会发现此时的Modify时间改变了,但是Change时间也发生了改变,因为我们对源文件修改的时候,可能增加或者删除了代码,此时我们文件的大小就可能发生变化,所以Change时间也发生了改变。我们再来了解一下Access时间,它是文件的访问时间。


然后我们多次执行访问文件,我们会发现Access时间没有改变,这是因为Access不是实时更新的,而是访问到一定的次数或者是在系统内部做了一定的访问操作,当系统认为可以时间可以更新便会自动更新。


结论:关于对比可执行程序和我们的源文件哪一个更新的时候,我们通常以Modify时间为准。


如果我们想在不改变源文件内容的时候,我们可以通过修改文件的Modify时间去让make能够重新编译。我们可以使用touch命令,如果文件不存在,touch帮我们创建文件,如果文件存在,touch就会帮我们更新文件。


我们还可以打开vim mytest.c,然后将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。


此后我们再输入make编译,此时就不再显示文件是最新的而不可被编译


不过我们一般不将我们的目标文件设置成伪文件,而是将clean设置成伪文件,因为清理工作总是要执行的。


我们也可以将上面的makefile这样写:@表示目标文件,^表示源文件列表。


或者也可以这样写,makefile是支持变量定义的,我们可以将它理解为宏,完成的任务是替换。


这里我们还需要了解一个问题mybin是直接依赖我们的test.c吗?根据我们上面提到滴,并不是,我们写的代码test.c需要经过预处理、编译、汇编和链接才可以形成可执行程序mybin。


  • 上面的文件 mybin ,它依赖 test.o
  • test.o , 它依赖 test.s
  • test.s , 它依赖 test.i
  • test.i , 它依赖 test.c


上面的这个依赖关系和依赖方法是类似于栈的,依赖关系先依次入栈,然后再出栈于相应的依赖方法相匹配。


【命令行魔法:掌握Linux基础工具开发的独门技艺】(四):https://developer.aliyun.com/article/1425555

相关文章
|
3天前
|
缓存 监控 前端开发
如何在 Linux 命令行中检查 CPU 使用率
【5月更文挑战第8天】
12 0
|
4天前
|
安全 Linux Python
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
|
5天前
|
数据可视化 小程序 Linux
【Linux】自动化构建工具make/Makefile和git介绍
【Linux】自动化构建工具make/Makefile和git介绍
13 0
|
6天前
|
安全 Linux Android开发
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
该文介绍了如何在Linux服务器上交叉编译Android的FFmpeg库以支持HTTPS视频播放。首先,从GitHub下载openssl源码,解压后通过编译脚本`build_openssl.sh`生成64位静态库。接着,更新环境变量加载openssl,并编辑FFmpeg配置脚本`config_ffmpeg_openssl.sh`启用openssl支持。然后,编译安装FFmpeg。最后,将编译好的库文件导入App工程的相应目录,修改视频链接为HTTPS,App即可播放HTTPS在线视频。
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
|
6天前
|
缓存 Linux
linux性能分析之内存分析(free,vmstat,top,ps,pmap等工具使用介绍)
这些工具可以帮助你监视系统的内存使用情况、识别内存泄漏、找到高内存消耗的进程等。根据具体的问题和需求,你可以选择使用其中一个或多个工具来进行内存性能分析。注意,内存分析通常需要综合考虑多个指标和工具的输出,以便更好地理解系统的行为并采取相应的优化措施。
27 6
|
10天前
|
Shell Linux
【Linux】Bash支持各种指令选项的原理:命令行参数
【Linux】Bash支持各种指令选项的原理:命令行参数
|
11天前
|
Linux
Linux课程四课---Linux开发环境的使用(自动化构建工具-make/Makefile的相关)
Linux课程四课---Linux开发环境的使用(自动化构建工具-make/Makefile的相关)
|
11天前
|
前端开发 Linux iOS开发
【Flutter前端技术开发专栏】Flutter在桌面应用(Windows/macOS/Linux)的开发实践
【4月更文挑战第30天】Flutter扩展至桌面应用开发,允许开发者用同一代码库构建Windows、macOS和Linux应用,提高效率并保持平台一致性。创建桌面应用需指定目标平台,如`flutter create -t windows my_desktop_app`。开发中注意UI适配、性能优化、系统交互及测试部署。UI适配利用布局组件和`MediaQuery`,性能优化借助`PerformanceLogging`、`Isolate`和`compute`。
【Flutter前端技术开发专栏】Flutter在桌面应用(Windows/macOS/Linux)的开发实践
|
11天前
|
负载均衡 网络协议 应用服务中间件
【亮剑】在Linux中构建高可用性和高性能网络服务的负载均衡工具HAProxy、Nginx和Keepalived。
【4月更文挑战第30天】本文介绍了在Linux中构建高可用性和高性能网络服务的负载均衡工具HAProxy、Nginx和Keepalived。HAProxy是一个高性能的开源TCP和HTTP负载均衡器,适合处理大量并发连接;Nginx是一个多功能Web服务器和反向代理,支持HTTP、HTTPS和TCP负载均衡,同时提供缓存和SSL功能;Keepalived用于监控和故障切换,通过VRRP实现IP热备份,保证服务连续性。文中详细阐述了如何配置这三个工具实现负载均衡,包括安装、配置文件修改和启动服务,为构建可靠的负载均衡系统提供了指导。