C++linux高并发服务器项目实践 day2

静态库的制作

库的定义和特点详情请看隔壁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主要帮助你完成下面四个方面的功能

  1. 启动程序,可以按照自定义的要求随心所欲的运行程序
  2. 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式)
  3. 当程序被停住时,可以检查此时程序中所发生的事
  4. 可以改变程序,将一个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 行数

断点操作的命令

  • 设置断点
    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

调试的命令

  • 运行GDB程序
    start(程序停在第一行)
    run(遇到断点才停)
  • 继续运行,到下一个断点停
    continue / c
  • 向下执行一行代码 (不会进入函数体)
    next / n
  • 变量操作
    print / p 变量名(打印变量值)
    ptype 变量名(打印变量类型)
  • 向下单步调试(遇到函数进入函数体)
    step / s
    finish (跳出函数体)
  • 自动变量操作
    display num(自动打印指定变量的值)
    info / i display
    undisplay 编号
  • 其他操作
    set var 变量名 = 变量值
    until (跳出循环)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值