一.问题场景

在完成交易系统的程序里面,使用了libevent库封装网络部分的代码,开发环境是自己的虚拟机,是有互联网的,可以下载libevent。

但是生产环境托管在机房内的机器上,这个机房只有局域网用于交易,没有互联网。所以就无法使用yum install、wget、git clone等需要外网的操作。

并且还有一个问题,就是环境是否一致,如果手动在实盘机上编译安装libevent,可能导致版本与开发环境不一样,例如开发用libevent 2.1.12,实盘机装了2.0.21。依赖链就会断裂。

二.自包含部署的技术方案

上面的问题所以打算用动态库本地打包的方法,做到库与程序绑定,无需修改系统环境,减少对托管机环境的依赖。

2.1把动态库复制到本地lib目录下

首先需要查看程序运行时需要依赖的库,通过命令“ldd /usr/lib64/libevent.so”

这四个按照顺序分别是:内核虚拟库(无需处理);系统线程库;系统C库;动态链接库

所以只需要复制libevent.so和libevent_pthreads.so

复制库文件到项目目录:

cp /usr/lib64/libevent.so /home/tcy/PlaneGM/lib/
cp /usr/lib64/libevent_pthreads.so /home/tcy/PlaneGM/lib/

2.2把需要的库添加到build里面

存在一个新的问题:lib下有libevent.so和libevent_pthreads.so这两个程序运行时会用到的动态库, 然后生成build可执行文件之后放在一个新的虚拟机上就可以直接运行,所以就需要更改配置文件 需要在编译生成时把这两个文件复制到build下的lib里面

在配置文件中复制动态库

# 自动复制所需的动态库到build/lib
add_custom_command(TARGET plane POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy
        ${CMAKE_SOURCE_DIR}/lib/libevent.so
        ${CMAKE_BINARY_DIR}/lib/
    COMMAND ${CMAKE_COMMAND} -E copy
        ${CMAKE_SOURCE_DIR}/lib/libevent_pthreads.so
        ${CMAKE_BINARY_DIR}/lib/
    COMMAND ${CMAKE_COMMAND} -E copy
        ${CMAKE_SOURCE_DIR}/lib/libEESTraderApi_ef.so
        ${CMAKE_BINARY_DIR}/lib/
    COMMENT "Copying required shared libraries to build directory"
)

2.3文件权限问题

把build文件夹复制到新的虚拟机上之后 ./plane会报错 :[tcy2@localhost build]$ ./plane bash: ./plane: Permission denied

报错原因是可执行文件plane没有执行权限。

为什么会出现这个问题

①Linux中新建的文件默认权限是 -rw-r--r--(644),没有执行权限(x)

②CMake生成的可执行文件有时不会自动设置+x权限,特别是当文件系统或构建环境有特殊配置时。

解决方案是:

①可以在编译完成后,在编译机器上赋予执行权限,然后再将整个build目录复制到新的虚拟机上

②在新的虚拟机上赋予执行权限

chmod +x plane

本来想直接在编译器上赋予权限之后 这样直接复制粘贴到新的虚拟机上就可以运行了,但是出现了一个问题:在原来的编译器上赋予执行权限之后,将build复制到新的虚拟机上运行不了,但是在新的虚拟机上用命令chmod +x plane加上之后就能运行了。

所以还是推荐使用第二个方案。

三.运行时关于动态库的问题

程序在用到动态库时 虽然编译会通过 但是运行的时候可能会报错 原因是他在运行时才会加载

3.1动态库的加载时机


(1)编译时(静态检查)
仅检查符号是否存在
编译器(如 gcc)和链接器(ld)会验证程序调用的函数/符号是否在动态库中声明过(通过头文件和链接选项 -lxxx),但不会验证动态库文件本身是否存在或路径是否正确。

不加载库的代码
编译阶段只记录依赖关系(如 libevent.so 是必需的),但不会将库的代码嵌入可执行文件。

(2)运行时(动态加载)
动态链接器(ld-linux)负责加载
程序启动时,动态链接器会根据以下顺序查找并加载动态库:

编译时指定的库路径(如 -Wl,-rpath=/custom/lib)。

环境变量 LD_LIBRARY_PATH 指定的路径。

系统默认库路径(如 /lib64、/usr/lib64)。

此时才会验证库文件是否存在
如果库文件丢失、权限不足或软链接(Symbolic Link)损坏,运行时才会报错(如 error while loading shared libraries: xxx.so: cannot open shared object file)。

3.2复制正确的动态库和软链接

查看程序运行时依赖的动态库

这种箭头指向的是软链接的动态库文件,箭头左侧是链接文件,右侧是目标文件。并且需要注意的是在复制软链接的时候要加上”-P“保留链接结构,否则就会失效。

首先查看这个库的详细信息

[admin@localhost PlaneYD]$ ls -l /usr/lib64/libevent*
lrwxrwxrwx. 1 root root     21 Apr  3 08:57 /usr/lib64/libevent-2.0.so.5 -> libevent-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 297792 Jun 14  2014 /usr/lib64/libevent-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     26 Apr  3 08:57 /usr/lib64/libevent_core-2.0.so.5 -> libevent_core-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 179800 Jun 14  2014 /usr/lib64/libevent_core-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     26 Apr 23 14:16 /usr/lib64/libevent_core.so -> libevent_core-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     27 Apr  3 08:57 /usr/lib64/libevent_extra-2.0.so.5 -> libevent_extra-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 133864 Jun 14  2014 /usr/lib64/libevent_extra-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     27 Apr 23 14:16 /usr/lib64/libevent_extra.so -> libevent_extra-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     29 Apr  3 08:57 /usr/lib64/libevent_openssl-2.0.so.5 -> libevent_openssl-2.0.so.5.1.9
-rwxr-xr-x. 1 root root  24456 Jun 14  2014 /usr/lib64/libevent_openssl-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     29 Apr 23 14:16 /usr/lib64/libevent_openssl.so -> libevent_openssl-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     30 Apr  3 08:57 /usr/lib64/libevent_pthreads-2.0.so.5 -> libevent_pthreads-2.0.so.5.1.9
-rwxr-xr-x. 1 root root  11200 Jun 14  2014 /usr/lib64/libevent_pthreads-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     30 Apr 23 14:16 /usr/lib64/libevent_pthreads.so -> libevent_pthreads-2.0.so.5.1.9
lrwxrwxrwx. 1 root root     21 Apr 23 14:16 /usr/lib64/libevent.so -> libevent-2.0.so.5.1.9

根据上面查看到的程序运行时所需要的动态库在在终端进行复制,注意箭头两边的文件都需要复制,并且格式也要正确

 复制完成后查看就是最后的样子。

3.3C++编译指定新版libstdc++库

程序运行时报错:

[root@localhost my_quote_server]# /usr/local/gcc-11.2.0/bin/g++ -o main main.cpp -std=c++17 -lpthread
[root@localhost my_quote_server]# ./main
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.11' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.13' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./main)

说明出现了标准库不兼容的问题,系统仍然在使用旧版的libstdc++.so.6

解决方法是A[确认新库路径]->B[设置运行环境]

首先确认新库路径,找到GCC 11.2.0的库位置,通常在安装目录下的lib64/或lib/:

  ls -l /usr/local/gcc-11.2.0/lib64/libstdc++.so*

输出示例:确保存在新版库 

正确创建软链接

删除错误的链接

sudo rm -f /usr/lib64/libstdc++.so.6

创建正确指向的软链接(使用绝对路径)

sudo ln -s /usr/local/gcc-11.2.0/lib64/libstdc++.so.6.0.29 /usr/lib64/libstdc++.so.6

验证链接状态

ls -l /usr/lib64/libstdc++.so*

输出示例:

至此整个程序在编译以及运行的时候都不会报错了。

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐