静态库的制作
库的定义和特点详情请看隔壁c++阶段学习的day10查看
静态库命名规则
- Linux: libxxx.a
- lib:固定前缀
- xxx:库的名字,自定义
- .a:固定后缀
- windows:libxxx.lib
静态库的制作
- gcc获得.o文件
- 将.o文件打包,使用ar工具(archive)
ar rcs libxxx.a xxx.o xxx.o
r- 将文件插入备存文件中 c-建立备存文件 s-索引
sudo apt install tree
安装tree插件,用来更方便的查看目录下文件
将隔壁做的mylib.h、mylib.c 、mydll.c、mydll.h文件通过vscode传入虚拟机后,使用下列代码生成.o文件
gcc -c mylib.c
这里我尝试了编译mydll.c文件,因为这个文件为动态库文件,故编译阶段会报错。编译完成后,可以通过ls命令查看生产了mylib.o文件
.h作为头文件不需要编译
若一个完整程序如上图,想要在linux中编译main.c
需要输入代码
gcc main.c
但是这时会报错,找不到头文件,也找不到库中定义的引用
所以完整运行代码应该为
gcc main.c -o app -I ./include/ -l calc -L ./lib
这里的calc为静态库的名称而非文件夹名
大写I是找头文件 小写L是找静态库
动态库的制作
命名规则
- LInux:libxxx.so
- lib:固定前缀
- xxx:库的名字,自定义
- .so:固定后缀
- Windows:libxxx.dll
制作
- gcc 得到.o文件,得到和位置无关的代码
gcc -c -fpic/-fPIC a.c b.c
- gcc得到动态库
gcc -shared a.o b.o -o libcalc.so
使用
跟静态库类似,使用动态库时,需要制定好头文件和库文件的目录
gcc main.c -o main -I include/ -L lib/ -l calc
这样直接执行,会动态库加载失败
动态库与静态库的区别
- 静态库:GCC进行链接时,会把静态库中代码打包到可执行文件中
- 动态库:GCC进行链接时,动态库的代码不会被打包到可执行文件中
- 程序启动之后,动态库会被动态加载到内存中,通过ldd命令检查动态库依赖关系
ldd main.c
解决动态库连接失败问题
如何定位共享文件呢?
当系统加载可执行代码时,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成,它先后搜索elf文件的DT_RPATH段–》环境变量LD_LIBRARY_PATH—》/etc/ld.so.cache文件列表–》/lib/,/usr/lib目录找到库文件后将其载入内存
env
用于查看当前环境变量,一般由键和值,中间以‘=’连接
且一个键可以有多个值,多个值之间,以‘:’连接
方法一
可以使用以下代码,来改变环境变量,以此导入动态库,主要是需要:后面的东西
export LD_LIBRARY_PATH= $LD_LIBRARY_PATH:/home/Linux/lesson06/lib
以这种方法配置的环境变量为临时配置,当关闭当前终端,打开别的终端时,依然会报错,编译失败
方法二
在home目录下,用vim打开bashrc,使用ctrl+g跳转最后一行,o来插入上面那行代码
然后ESC进入Command模式,输入下述代码,回车就可以强制保存并退出
:wq
输入以下代码,使修改生效,两段代码效果一致
. .bashrc
source .bashrc
我这里报了export:“” :not a valid identifier,应该是环境变量写错了,检查后发现,是在export的后面一长串里面加了空格,切记在linux中这种地方不能加空格
同理,用以下代码进入管理员权限下的地址添加以上修改内容,同样是在末尾加入
sudo vim /etc/profile
因为是管理员权限进入的,所以要输入密码
source /etc/profile
用这个代码使修改生效
用以下代码可以查看修改完的环境变量是否生效
ldd 加上已经编译好文件
echo $LD_LIBRARY_PATH
方法三
用以下代码进入对应文件,换行后添加需要的路径
sudo vim /etc/ld.so.conf
因为/etc/ld.so.cache是二进制文件,我们没有权限直接修改,故我们需要进入conf来间接修改它
使用下面的代码来使用该修改
sudo ldconfig
方法四
将动态库文件,放入/lib/,/usr/lib目录
但是不推荐这种方法,因为该目录下有很多库文件,容易找不到,后期不容易修改
静态库和动态库的对比
静态库的优缺点
优点:
- 静态库被打包到应用程序中加载速度快
- 发布程序无需提供静态库,移植方便
缺点:
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦
动态库的优缺点
优点:
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
缺点:
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库
Makefile
什么是Makefile
Makefile带来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释Makefile文件中指令的命令工具,一般来说,大多数的IDE都有这个命令
Makefile文件命名和规则
- 文件命名:makefile或者Makefile
- Makefile规则:
- 一个Makefile文件中可以有一个或者多个规则
目标 ...: 依赖 ...
命令(shell 命令)
...
- 目标:最终要生成的文件(伪文件除外)
- 依赖:生成目标所需要的文件或是目标
- 命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
- Makefile中的其他规则一般都是为了第一条规则服务的
Makefile的使用
对于若干个.c文件,想要使用Makefile来处理他们,需要用
vim Makefile
命令来新建一个Makefile文件,其中内容按照上述的规则来输入
例如:
app:sub.c add.c mult.c div.c main.c
gcc sub.c add.c mult.c div.c main.c -o app
同时想要使用Make命令,还需要安装make插件
sudo apt install make
输入以下指令,来运行makefile
make
工作原理
- 命令在执行之前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
- 如果不存在,向下检查其他的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令
- 检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- 如果依赖的时间比目标的时间晚,需要重新生成目标
- 如果依赖的时间比目标的时间晚,目标不需要更新,对应规则中的命令不需要被执行
正常来说只执行第一个规则,下面的规则只有用到才执行
更新哪怕源文件只是多了个换行符,make命令后,也会重新加载对应规则
变量
- 自定义变量
变量名 = 变量值 var = hello - 预定义变量
AR:归档维护程序的名称,默认值为ar
CC:C编译器的名称,默认为cc
CXX:C++编译器的名字,默认值为g++
$@:目标的完整名称
$<:第一个依赖文件的名称
$^:所有的依赖文件 - 获取变量的值
$(变量名)
ubuntu 22.04.2版本的中文输入法设置
在设置里面将系统语言调成中文后
在键盘界面,选择汉语,然后点+号,选择汉语,选择智能拼音
就能在vm中输入拼音和中文了
模式匹配
%.o:%.c
- %:通配符,匹配一个字符串
- 两个%匹配的是同一个字符串
%.o:%.c
gcc -c $< -o $@
函数
$(wildcard PATTERN…)
-$(wildcard PATTERN…)
- 功能:获取指定目录下指定类型的文件列表
- 参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
- 返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
例如:
$(wildcard *.c ./sub/*.c)
返回值格式:a.c b.c c.c d.c e.c f.c
$(patsubst ,,
)
$(patsubst ,,
)
- 功能:查找
中的单词(单词以“空格”、“Tab”或“回车”“换行”分割)是否符合模式,如果匹配的话,则以替换 - 可以包括通配符’%‘,表示任意长度的字串。如果中也包含’%‘,那么,中的这个’%'将是中的那个%所代表的字串。(可以用‘\’来转义,以‘%’来表示真实含义的‘%’字符)
- 返回:函数返回被替换过后的字符串
例如:
$(patsubust %.c,%.o,x.c bar.c)
返回值格式:x.o bar.o
clean:
rm *.o
如果在make中加入一个规则,如上,可以使用以下规则,可以单独执行该规则
make clean
touch 文件名
上述代码可以生产一个文本文件
这里生产一个clean文件,再次使用make clean,会发现报“clean”已是最新,这是因为clean在写规则的时候,没有依赖,所以更新检测的规则依赖比目标更新是无法达成的,故会报“最新”
GDB调试
什么是GDB
GDB是由GNU软件系统社区提供的调试工具,同GCC配套组成了一套完整的开发环境,GDB是许多Linux和Unix系统的标准开发环境
一般来说,GDB主要帮助你完成下面四个方面的功能
- 启动程序,可以按照自定义的要求随心所欲的运行程序
- 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式)
- 当程序被停住时,可以检查此时程序中所发生的事
- 可以改变程序,将一个BUG产生的影响修正从而测试其他BUG
准备工作
通常,在为调试而编译时,我们会()关掉编译器的优化选项(‘-o’),并打开调试选项(‘-g’)。另外,‘-wall’在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的BUG
‘-g’选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证GDB能找到源文件
在vim 一个文本文件是时候,可以用下述代码,令该文件里面的每一行前加上序号
:set num
GDB命令
- 启动和退出
gdb 可执行文件
quit - 给程序设置参数/获取设置参数
set args 10 20
show args - GDB使用帮助
help - 查看当前文件代码
list/l (从默认位置显示)
list/l 行号 (从指定的行显示)
list/l 函数名 (从指定的函数显示) - 查看非当前文件代码
list/l 文件名:行号
list/l 文件名:函数名 - 设置显示的行数
show list/listsize
set list/listsize 行数
断点操作的命令文章来源:https://www.toymoban.com/news/detail-418809.html
- 设置断点
break / b 行号
break / b 函数名
break / b 文件名:行号
break / b 文件名:函数 - 查看断点
info / i break/b - 删除断点
delete / del / d 断点编号 - 设置断点无效
disable / dis 断点编号 - 设置断点生效
enable / ena 断点编号 - 设置条件断点(一般用在循环的位置)
break / b 10 if i == 5
调试的命令文章来源地址https://www.toymoban.com/news/detail-418809.html
- 运行GDB程序
start(程序停在第一行)
run(遇到断点才停) - 继续运行,到下一个断点停
continue / c - 向下执行一行代码 (不会进入函数体)
next / n - 变量操作
print / p 变量名(打印变量值)
ptype 变量名(打印变量类型) - 向下单步调试(遇到函数进入函数体)
step / s
finish (跳出函数体) - 自动变量操作
display num(自动打印指定变量的值)
info / i display
undisplay 编号 - 其他操作
set var 变量名 = 变量值
until (跳出循环)
到了这里,关于C++linux高并发服务器项目实践 day2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!