Linux开发工具入门(一):开发三板斧(包管理器,vim,gcc/g++) 以及入门理解动静态库

目录

[1 软件包管理器](#1 软件包管理器)

[1.1 什么是软件包](#1.1 什么是软件包)

[1.2 linux软件生态](#1.2 linux软件生态)

[1.3 yum具体操作](#1.3 yum具体操作)

[1.3.1 查看软件包](#1.3.1 查看软件包)

[1.3.2 安装软件](#1.3.2 安装软件)

[1.3.3 卸载软件](#1.3.3 卸载软件)

[2 编辑器Vim](#2 编辑器Vim)

[2.1 vim命令模式命令集](#2.1 vim命令模式命令集)

[2.2 vim底行模式命令集](#2.2 vim底行模式命令集)

[3 编译器gcc/g++](#3 编译器gcc/g++)

[3.1 预处理](#3.1 预处理)

[3.2 编译](#3.2 编译)

[3.3 汇编](#3.3 汇编)

[3.4 链接](#3.4 链接)

[3.5 知识点](#3.5 知识点)

[3.5.1 如何理解条件编译?条件编译的用途?](#3.5.1 如何理解条件编译?条件编译的用途?)

[3.5.2 为什么C/C++编译,要先变成汇编?](#3.5.2 为什么C/C++编译,要先变成汇编?)

[3.5.3 编译器要用什么语言写呢?先有汇编语言还是先有汇编语言写的编译器?](#3.5.3 编译器要用什么语言写呢?先有汇编语言还是先有汇编语言写的编译器?)

[3.5.4 什么叫做动静态库,什么叫做动静态链接,如何理解](#3.5.4 什么叫做动静态库,什么叫做动静态链接,如何理解)

[3.5.5 动静态库对比](#3.5.5 动静态库对比)

[3.5.6 做验证工作](#3.5.6 做验证工作)

[3.5.7 周边问题](#3.5.7 周边问题)


1 软件包管理器

1.1 什么是软件包

在linux上安装软件通常有三种方式。第一种是使用源码安装;第二种是使用软件包安装;第三种是使用软件包管理器(yum)安装。

源码安装是下载到程序的源代码,并进行编译,得到可执行程序。这样很麻烦,一般都不这样做。

于是有些人就把一些常用的软件提前编译好,做成软件包(可以理解成对应windows上的安装程序)放在一个服务器上。软件包安装现在也基本不使用,现在常用包管理器进行安装。通过包管理器可以方便的获取到编译好的软件包,直接进行安装。

软件包和软件包管理器,就好比App和应用商店的关系。

yum是linux下的一种常用的包管理器,主要应用在Fedora,RedHat,Centos等上;Ubuntu下主要使用apt作为包管理器。

包管理器是使用网络下载软件,然后安装(本质就是拷贝),所以要有root权限,安装到系统里面,只要安装一次,任何人都能使用。为什么会推荐包管理器?因为它会自动给我们解决软件包的依赖问题(一个软件A不能独立运行,需要其他库文件,文件有时又需要其他文件)。

如果没有包管理器,手动安装gcc需要几步?

  1. 下载 gcc 源码包
  2. 尝试编译 → 报错:缺少 GMP 库
  3. 下载 GMP 源码
  4. 编译 GMP → 报错:缺少 M4
  5. 下载 M4 源码
  6. ......

相当麻烦,这就是传说中的"依赖地狱"。

1.2 linux软件生态

如何去评估一款操作系统的好坏?一款操作系统生态好,这款操作系统就算好的操作系统,这其中包括社区,文档,人群,解决问题等方面。

一款操作系统一经发行,吸引的人群有哪些,在这个社区上有没有积累足够多的文档,文档有没有反映出足够多的问题,问题有没有被解决,这些都被称之为操作系统的生态问题。如何理解这个过程呢?

在Centos、Ubuntu等系统有其对应的社区。社区里有活跃的开发者,开发出对应的软件然后将源代码托管到官网或github,然后源码编译形成软件。一个软件可能在多个平台编,上到对应社区平台上,所以会有很多软件。自己的linux中预装yum/apt,通过指令来下载这些软件。

为什么会有人免费特定社区提供软件,还发布?还提供云服务器让你下载?

开源,本质是一种商业模式,很多公司会用你社区上的东西,我推出一款操作系统,为了让更多人用我的操作系统,将软件开源。很多公司用你社区上的东西,不想让你倒闭,一旦你用了,就介入了我的因果。

我的机器怎么知道下载链接的呢?

因为操作系统内部内置链接,centos默认内置链接www.centos.org,因为有防火墙,生态在国外,所以就有国人将国外网站镜像过来,同时更改下载链接,就可以下载了。

1.3 yum具体操作

1.3.1 查看软件包

通过yum list命令可以罗列出当前一共有哪些软件包,由于包的数量非常多,这里我们使用grep命令筛选出我们关注的包。例如:

复制代码
//找出关键字中包含sl的软件
sudo yum list | grep sl

1.3.2 安装软件

通过yum,可以通过简单的命令完成gcc的安装

复制代码
//centos
sudo yum -y install gcc


//ubuntu
sudo apt -y install gcc

注意事项:

  • yum/apt会⾃动找到都有哪些软件包需要下载,这时候敲"y"确认安装
  • 出现"complete"字样或者中间未出现报错,说明安装完成
  • 安装软件时由于需要向系统⽬录中写⼊内容,⼀般需要sudo或者切到root账⼾下才能完成
  • yum/apt安装软件只能⼀个装完了再装另⼀个。正在yum/apt安装⼀个软件的过程中,如果再尝试⽤ yum/apt安装另外⼀个软件,yum/apt会报错

1.3.3 卸载软件

使用命令卸载指定的软件

复制代码
//centos
//强制卸载sl
sudo yum remove -y sl


//ubuntu
sudo apt remove -y sl

使用yum/apt的所有操作需要保证机器网络畅通。

2 编辑器Vim

vim键盘图

这里说明vim的三种模式:命令模式,插入模式,底行模式。进入vim默认是默认模式。想要正常写东西,要从命令模式下切换到插入模式,输入i,切换到插入模式。想退出,按esc,进入命令模式,然后按shift+;,进入底行模式,按wq,保存退出。

2.1 vim命令模式命令集

这里列出一些重点命令

  • gg:快速回归到光标第一行
  • shift+g=G:快速定位到结尾
  • n+shift+g:快速定位第n行
  • shift+4=$:光标定位到行结尾
  • shift+6=^:光标定位到行开头
  • 上下左右移动用键盘的上下左右键,或者h:左移,j:下移,k:上移,l:右移
  • yy:复制
  • n+yy:复制n行
  • p:粘贴
  • n+p:粘贴n行
  • dd:删除/剪切当前行,然后可以p,粘贴
  • n+dd:删除n行/剪切n行,然后n+p,重复粘贴n行。
  • u:撤销历史操作
  • ctrl+r:撤销u操作
  • x:删除光标所在位置的字符
  • n+x:删除n个字符
  • shift+x:以光标为分界线,光标右侧不动,光标左侧删除。删完后也可p。
  • shift+v:光标处大小写切换
  • r:替换光标所在字符
  • shift+r=R:批量化替换,进入替换模式
  • ctrl+v:切换到视图模式,然后h j k l进行区域选择,然后shift+i进入插入模式,//进行注释这些行,然后esc回退默认模式,进行快速注释

2.2 vim底行模式命令集

  • w:保存
  • q:退出
  • wq:保存退出
  • ZZ(大写):快速退出
  • set nu:添加行号
  • set nonu:去掉行号
  • !+指令:可以在不退出vim时执行指令
  • /关键字:先按/键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以⼀直按n会往后寻找到您要的关键字为⽌
  • ?关键字:先按?键,再输⼊您想寻找的字符,如果第⼀次找的关键字不是您想要的,可以⼀直按n会往前寻找到您要的关键字为⽌

3 编译器gcc/g++

格式:

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

我们知道C/C++代码从源代码到可执行文件需要经过预处理,编译,汇编,链接这几个过程,下面就说明这几个过程

3.1 预处理

预处理做了什么?

  • 头文件展开:把 头文件的内容原封不动地复制进来
  • 宏替换:例如把#define MAX 100替换成 100
  • 条件编译:处理#ifdef,#ifndef等
  • 删除注释:把//和/* */去掉

选项-E,在预处理结束后,生成.i后缀文件,然后停下来。例如:gcc -E hello.c -o hello.i

选项-o是指目标文件

3.2 编译

预处理过后,就要编译,在这个阶段,gcc要检查代码的规范性,是否有语法错误等,以及确定代码实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。

选项:-S,作用是只进行编译而不进行汇编。

例如:gcc -S hello.i -o hello.s

3.3 汇编

将汇编代码翻译成机器指令,生成可重定位目标文件(.o文件),此时就是二进制文件了,但是还不能直接运行。

选项:-c,将汇编代码转化为".o"的二进制目标代码了。汇编完成就停下来。

例如:gcc -c hello.s -o hello.o

3.4 链接

把多个目标文件和库**合并成一个可执行文件。**例如:gcc hello.o -o hello。

3.5 知识点

编译多个文件,一般都是用-c选项把源文件统一变成.o文件,然后用gcc code1.o code2.o code3.o......-o code 整体生成一个可执行文件code。

ldd+可执行程序,可以查看可执行程序依赖哪些库

3.5.1 如何理解条件编译?条件编译的用途?

条件编译:#if,#endif;#ifdef,#ifndef。条件编译 是 C/C++ 预处理阶段的一个开关 ------它让你能根据不同的条件,决定哪些代码参与编译,哪些代码被忽略

用途:

(1)对软件进行专业度,收费情况进行区分(业务层面),使用条件编译,可以进行代码的动态裁剪,进行软件专业版和社区版的区分。

(2)内核源代码也是采用条件编译进行代码裁剪

(3)开发工具,应用软件采用条件编译让软件在windows和linux都能运行。

3.5.2 为什么C/C++编译,要先变成汇编?

我们编程的本质就是控制计算机。最开始的开关->打孔编程->汇编语言。

从汇编语言开始,编译器就要产生了,要将语言翻译成二进制。那么这时问题就来了:编译器究竟是C语言直接翻译二进制还是C语言翻译成汇编语言,然后再转换成二进制呢?

答案显然是后者。从C语言到汇编毕竟是从文本到文本,难度低,从汇编到二进制就是站在巨人的肩膀上。从C语言直接到二进制,成本太高。

3.5.3 编译器要用什么语言写呢?先有汇编语言还是先有汇编语言写的编译器?

答案是先有汇编语言,第一版的编译器是二进制版的,这样就可以编译汇编语言了。后来用汇编语言写一个汇编编译器,再用二进制版的编译器翻译一下,就诞生了第一个汇编语言的编译器。这个过程叫做编译器的自举过程。

所以根据以上流程,先有C语言,然后有C语言写的C编译器(拿汇编语言写一个C编译器,就能不编译C语言了,然后拿C语言写一个C编译器,用汇编语言写的C编译器翻译一下,诞生第一个C编译器)。

3.5.4 什么叫做动静态库,什么叫做动静态链接,如何理解

这里做简单说明,做小白式的理解,具体后续另写。

所谓的库,是一套方法或者数据集,为我们的开发提供最基本的保证(基本接口,功能,加速我们的二次开发)。

使用ls /usr/lib64查看系统里默认的库,.so结尾一般是动态库,windows中.dll文件是动态库。

C动态库:libc.so,C静态库:libc.a。Linux中,命名,去掉前缀lib,去掉后缀.so或.a剩下的就是名字。平时形成的可执行程序(c写的)都依赖动态库。

动静态库内部实现方法:

我们自己的程序,会使用库中的方法,自己的程序和库中的方法链接起来形成可执行程序,链接就是让自己的程序能在库中找到方法。

动态库的典型特点是:执行目标方法时(例如printf),需要跳转到库中执行,完了再返回。

所以链接就是让我的程序,能找到库中的方法的地址!动态链接的过程只是在地址上产生关联。

所谓静态链接,就是将库中实现的内容拷贝一份到我自己的程序中,这种链接方式叫做静态链接。

举一个例子:小明是一个初中生考上了XXX高中,他喜欢玩游戏,这个高中不允许携带任何电子设备。于是小明学长问有没有玩游戏的地方,学长告诉小明学校东门有一个网咖,小明知道了具体地址。到了开学后的周末,小明周末指定学习计划:9:00语文作业,10:00数学作业,11:00吃饭,12:00去上网,14:00化学作业。小明到了计划时间根据地址去到网咖,在100号机器上网,时间到了就回去了。

这个故事中,小明就是程序;高中就是内存;小明问学长,学长告诉小明具体地址,这个叫动态链接;网咖就是动态库,小明上高中就叫加载过程,执行学习计划就是执行代码;执行计划去网咖叫做库调用;回学校叫做库函数返回。

在这个故事里:

  • 链接时机 :小明在开学前就从学长那里知道了网咖地址(编译时确定地址)

  • 加载时机 :小明到了周末才真正去网咖(运行时才加载库)

  • 调用过程:小明按地址找到机器(通过地址跳转到函数)

所以叫"动态链接"------链接发生在编译时,但真正使用是在运行时

所以动态链接是在编译时,没加载时就链接好了。动态链接是将要访问库方法的地址写在程序中,执行时就通过地址找到了。

这个学校很多学生都去这个网咖,所以这个动态库,也叫做共享库。后来因为某些原因网咖关门了。所有同学的计划无法执行了,所以共享库有一个特点:被多个程序共享,一旦缺失,会导致所有程序无法运行。这是个缺点。

故事二:网咖关门了,上不了网,小明回家后告诉父亲因为无法去网咖查阅学习资料导致成绩下滑,他父亲就找到学校,学校允许带电脑了。小明父亲又找到网咖老板,将小明用的100号机器买了下来,搬到宿舍里,以后上网就在宿舍了,这个过程叫做把网咖电脑拷贝给小明,其他同学也纷纷效仿,这种链接方式叫做静态链接。

静态链接的特点是:把我们自己程序中用的库方法,拷贝给我自己!静态库只有在链接的时候有用,一旦形成可执行程序,静态库可以不再需要。

3.5.5 动静态库对比

对比维度 动态链接 静态链接
库的位置 系统里共享的一份 每个程序自己有一份
内存占用 小(共用一份) 大(每人一份)
可执行文件大小 小(只记录地址) 大(包含库代码)
更新库 所有程序自动受益 每个程序需重新编译
库缺失 所有程序无法运行 不受影响
典型后缀 .so(Linux)、.dll(Windows) .a(Linux)、.lib(Windows)

如何选择?

场景 推荐方式 原因
普通应用 动态链接 省内存、易更新
系统工具(如 ls 动态链接 和系统 libc 保持一致
嵌入式系统 静态链接 环境固定,避免依赖缺失
容器内程序 静态链接 容器小,避免找库
发布给别人的程序 静态链接 用户不用装依赖

3.5.6 做验证工作

写一个简单的printf的代码

ldd code,发现库是.so的库,所以默认是动态链接的。

ll code,发现体积是8360字节。

用静态库:C静态库就得存在。

发现报错cannot find -lc,意味着确实C库(libc.a)不存在,所以要安装静态库:

此时再次编译

可执行程序的体积是861216字节,体积扩大了100倍。

结论是:gcc编译,默认动态链接,-static用静态链接。

同理,C++程序使用g++编译,安装C++静态库使用sudo yum install libstdc++-static安装。

3.5.7 周边问题

动静态库,源文件,可执行程序本质都是文件。加载程序时,首先将程序加载到内存里,一般动态库也要加载到内存里,跳转执行是在内存中,以后其他程序要调用这个库时,也调用它。所以动态库本质是把所有程序中公共代码在内存中只出现一份。所以一旦动态库缺失,相当一大部分指令都无法运行。

为什么汇编要翻译成.o文件呢?为了和库文件(后缀.o)进行合并。链接的本质是将所有的.o文件进行合并。关于动态库更详细内容,以后文章再说明。

以上就是本文全部内容了,希望对你有所帮助,如果这篇文章对你有用,可以点点赞哦,你的支持就是我写下去的动力,后续会继续更新其他知识。

相关推荐
YMWM_2 小时前
linux文件快速传windows
linux·运维·服务器
sunxunyong9 小时前
CGroup配置
linux·运维·服务器
hy____1239 小时前
Linux_网络编程套接字
linux·运维·网络
若风的雨9 小时前
【deepseek】 Linux 调度延时分析
linux
小夏卷编程9 小时前
Ubuntu 20.04.4 宝塔 docker showdoc v3.2 更新到v3.7.3
运维·docker·容器
康康的AI博客9 小时前
农业工业变革:如何通过DMXAPI中转提升自动化效率
运维·人工智能·自动化
2301_8035545210 小时前
linux 以及 c++编程里对于进程,线程的操作
linux·运维·c++
LuDvei10 小时前
windows 中 vs code远程连接linux
linux·运维·服务器·windows