文章目录
- 一、解决sudo命令的问题
- 二、Linux编译器-gcc/g++
- 1.gcc的使用
- 2.g++的使用
- 三、gcc编译链接过程
- 1.预处理
- 2.编译(生成汇编)
- 3.汇编(生成机器可识别代码)
- 4.链接(生成可执行文件或库文件)
- 5.一些选项的意义
- 四、库
- 1.关于库的一些认识
- 2.与库的链接
- 1>动态链接
- 2>静态链接
- 3.验证
- 4.一些问题
- 5. file指令
- 6.动静态链接的优缺点
- 五、debug和release
一、解决sudo命令的问题
当我们使用一个新的普通用户想要对一条指令进行提权的时候,我们会遇到如下问题,显示不被信任
所以我们现在需要做的就是将我们的该用户添加到系统的白名单中
这个白名单在下面这个路径下
/etc/sudoers
当然我们不可以用普通用户去访问,因为我们可以看到这个文件的权限是这样的
所以我们需要用root账号去进行修改
进入以后,我们在第100行可以看到这个
然后我们只需要修改添加一行即可
然后我们在回到这个普通账号,我们就可以使用sudo进行提权了,以root的身份进行创建文件,我们也可以看到,我们创建的文件的拥有者就是root
二、Linux编译器-gcc/g++
gcc智能用来编译c语言,g++即可用来编译c语言,又可用来编译c++
但我们一般用gcc编译c,g++编译c++
1.gcc的使用
当我们写好代码以后直接
gcc test.c
然后它会自动生成一个可执行程序a.out
这个可执行程序的名字不重要,关键是它的属性具有可执行权限
然后我们直接使用如下命令,就可以进行运行了
./a.out
如下所示
2.g++的使用
g++的使用与gcc是十分类似的
不过我们需要先安装一下g++
yum install gcc gcc-c++
安装以后,我们就可以使用g++编译c++代码了,它默认生成的就是a.out文件
三、gcc编译链接过程
我们知道执行一个c程序需要经过一下几个步骤
- 预处理
- 编译(生成汇编)
- 汇编(生成机器可识别代码)
- 链接(生成可执行文件或库文件)
1.预处理
在预处理过程中,会有如下操作
- 去掉注释
- 头文件展开
- 宏替换
- 条件编译
我们先来展示前三点
我们需要先输入如下指令
gcc -E test.c -o test.i
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
最后我们就可以观察到了前三点的现象
这里,我们还需要了解的一点是,我们为什么可以在windows或者linux上进行C/C++或者其他形式的开发呢?
这是因为我们的系统中一定要提前或者后序安装上,C/C++开发相关的头文件,库文件
而这些文件就在下面的路径中
/usr/include
然后我们可以打开一下比如stdio.h
vim /usr/include/stdio.h
我们可以看到大概有900多行的代码
而我们前面的头文件展开,就是将这里面的内容全部拷贝到test.i中
其实我们在安装vs2022的时候,还在安装的时候,就要选择对应的开发包,同步也在下载C的头文件和库文件
也就是说,在windows也同步有着对应的文件
还有条件编译,也会在预处理阶段给解决掉
gcc -E test.c -o test.i
不过对于宏,我们也可以在编译时候去定义的
gcc -E test.c -o test.i -DDEBUG
而条件编译的作用就是
比如vs2022有社区版和专业版,而公司不可能会专门维护两份代码,所以社区版只是专业版裁剪掉了某些功能得到的,而这个裁剪用的就是条件编译
2.编译(生成汇编)
在我们与预处理完以后,我们的代码其实还是C语言
所以我们下一步就是生成汇编
gcc -S test.i -o test.s
不过我们也可以从test.c直接生成汇编
gcc -S test.c -o test.s
生成以后,里面就是这个东西
在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言
3.汇编(生成机器可识别代码)
-
汇编阶段是把编译阶段生成的“.s”文件转成目标文件
-
在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
gcc -c test.s -o test.o
不过我们可以看到里面全是乱码
这是因为这个.o文件是二进制文件,而vim是文本编辑器。
所以我们可以使用二进制查看工具比如od
4.链接(生成可执行文件或库文件)
我们直接将所有的目标文件进行链接起来即可
gcc test.o -o mytest
最终这个mytest就是我们的可执行文件
对于生成可执行程序这里,还有很多种方式
首先就是直接生成
gcc test.c
这种方式最终生成的可执行程序是a.out
第二种方式是这样的
gcc test.c -o test
这种方式就和前面比较相似,直接将.c文件变成一个可执行程序test
这种方式我们也是最为推荐的
不过也可以这样写,无论如何-o后面跟的永远都是最终的可执行程序
gcc -o test test.c
5.一些选项的意义
gcc -E test.c -o test.i
这个-E的意思是告诉gcc,从现在开始进行程序的翻译,将预处理工作做完就停下来,不要往后走了!
gcc -S test.i -o test.s
从现在开始进行程序的翻译,将编译工作做完,就停下来
gcc -c test.s -o test.o
从现在开始进行程序的翻译,将汇编工作做完,就停下来
我们最终形成的这个test.o文件就是可重定位目标二进制文件,简称目标文件,在windows下他就是.obj文件;还需要注意的是这个文件不可以独立执行,虽然已经是二进制文件了,但是还需要经过链接才能执行
gcc test.o -o test
上面就是链接的过程,可将重定位目标二进制文件,和库进行链接形成可执行程序
四、库
1.关于库的一些认识
我们知道,我们写完程序后最终要有链接过程,链接要与我们的头文件进行链接,而头文件的一些方法是由库给提供的
比如我们C语言的标准库在这里路径下
/usr/lib64/libc.so
所以这个C语言标准存在的本质就是一个文件,它有自己的路径
在linux种这个库有以.so结尾的,也有以.a结尾的
LInux:.so(动态库) .a(静态库)
windows : .dll(动态库) .lib(静态库)
所以我们上面的就是Linux系统默认的动态库
一般我们这个库是有自己的命名规则的:libname.so.XXX
这个命名中只有最开头的name这四个是不同的,所以我们只需要它就可以了
注意:我们现在的机器上,默认只会安装动态库,静态库是默认没有安装的
所以现在回过头来
方法的实现就是在库当中的!
库其实就是把源文件(.c),经过一定的翻译,然后打包,只给你提供一个文件即可,不用给你提供给太多的源文件,也可以达到隐藏源文件的目的
头文件提供方法的声明, 库文件提供方法的实现+ 我们自己的代码== 我们的软件
有了库就可以不用做很多重复的工作,可以站在巨人的肩膀上了
而我们在使用gcc的时候,是不用手动的去链接它的库的,gcc天生就是链接c语言的,里面早已经处理好了
对于gcc,它默认找的是c语言的库,所以它无法编译c++代码
2.与库的链接
我们的.o文件和库是如何链接的呢?
我们的链接方式有两种
- 动态链接
- 静态链接
1>动态链接
假如小明今年刚刚考上了高中,它比较喜欢玩游戏。
所以他问他的学长,哪里有网吧。
小明在某一天个自己列了一个清单:完成物理作业、数学作业、语文作业、玩游戏…
然后小明就像一个可执行程序一样,一条一条的完成,当遇到玩游戏的时候,由于之前学长(编译器)告诉过他网吧在哪里,所以他就可以去网吧玩游戏。然后打完以后再返回原来的程序中继续执行
在这个过程中,学长就像一个编译器,存储着地址,告诉小明去哪里找,小明就像一个可执行程序,网吧就像一个库,当去执行游戏的操作时候,就会跳转到对应的库执行,执行完毕以后返回到代码调用出,这个过程就是动态链接的过程。
网吧这个库也就是一个动态库,也称作共享库(因为可以有很多人去像小明一样),所以网吧只要一个就可以了
假如有一天网吧被查封了,那么就糟糕了,所有人都玩不了游戏了
所以说动态库不能缺失,一旦对应的动态库缺失,影响的不止一个程序,可能导致很多程序都无法正常运行!
我么可以用ldd
指令去查看某一个可执行程序它所依赖的动态库
如果一旦我们将这个库给删掉了,那么我们这个程序就无法跑了
其实我们系统中的很多指令就是用C/C++写的,因为他们本身就是可执行程序(大部分的指令都是用c语言写的)
2>静态链接
继续前面的故事,网吧被查封了以后
大家都没法上网了,于是这个老板开始了卖电脑
于是很多人都去自己买了电脑。
这时候当我们想要去上网的时候,直接用自己的电脑就可以了,再也不用去网吧了
上面的这种方式其实就是静态链接
这个电脑店就是静态库
并不像之前的动态一样给一个地址,然后去找动态库;而是直接将静态库里面的方法给拷贝过来。
当未来这个电脑店再次被查封的时候,也不会影响到我们了。我们也不关心它
在编译器使用静态库链接的时候,会使自己的方法拷贝到目标程序中,该程序以后不用再依赖静态库了!
3.验证
如下所示,是关于动态链接的验证
在linux中,编译形成可执行程序,默认采用的就是动态链接–需要提供动态库
如下是关于静态链接的验证
静态链接时需要加上-static选项
gcc test.c -o test_static -static
在linux中,如果要按照静态链接的方式,进行形成可执行程序,需要给添加static选项 — 也要提供静态库
不过在我们的系统中一般是默认没有安装静态库的
我们可以用如下命令去安装
sudo yum install -y glibc-static
我们可以明显的感觉到,静态链接以后,体积变大了。
如果使用ldd,会显示不是动态的可执行程序
前面是关于c语言的静态库,我们也可以装一下c++的静态库
sudo yum install -y libstdc++-static
4.一些问题
- 如果我们没有静态库,但是我们就要-static,行不行呢?
其实是不行的
- 如果我们没有动态库,只有静态库,而且gcc能找到静态库,能成功编译吗?
是可以的,因为gcc默认优先动态链接。-static的本质其实是改变优先级
注意:我们的程序不一定是纯的全部动态链接或者静态链接的,有可能是混合的
-static可以使得所有的链接要求全部变为静态链接,即只适配一次
5. file指令
我们可以直接使用file指令去查看是动态链接还是静态链接
6.动静态链接的优缺点
动态库的优点
动态库因为是共享库,有效的节省资源(节省磁盘空间,内存空间,网络空间等)
动态库的缺点
动态库一旦缺失,导致各个程序都无法运行
静态库的优点
静态库,不依赖库,程序可以独立运行
静态库的缺点
体积大,比较消耗资源
五、debug和release
我们已经很清楚,debug可以被追踪调试
这是因为在形成可执行程序的时候,添加了debug信息
而release就无法进行调试
这就注定了debug的体积比较大
我们的gcc默认是release版本的,如果我们要生成debug版本的,要加上-g选项
我们可以看到,无论是静态的还是动态的,在debug下都是要大一点的
我们可以去验证一下
我们可以用如下指令去将我们的可执行程序给以一种格式呈现出来
readelf -S test_debug
然后我们结合管道,就可以看到,原来的是没有debug信息,而用debug的是有debug信息的
扩展
可执行程序形成的时候,不是无序的二进制构成,是有自己的格式的,—可执行程序有自己的二进制格式—ELF格式