基本概念我就不介绍了,网上有很多资料大家可以参考,我这里主要介绍工程实现。起初是因为买的摄像头涉及到二次开发,然后对方只给了一个静态库(.a文件)和一个头文件(.h),然后提供了一个说明文档,让我自己去开发,最开始还以为很简单,结果中途遇到各种问题。
1、静态库信息
首先,c语言生成的静态库(.a文件)和c++生成的静态库(.a文件)有点不一样,例如c调用c++生成的静态库和c++调用c++生成的静态库,过程会有细微的差别,这个大家可以查一下。所以对于拿到的第三方静态库,可以使用一下命令查看其相关信息:
#列出静态库(.a文件中)包含的所有.o文件及其对应的函数
nm -C *.a #-C的作用为输出符号重组过的函数名的原始名称
#列出.a文件中的所有.a文件,并显示来源于.cpp还是.c文件,显示的是符号重组后的函数名
readelf -s *.a
例如我手头的静态库用第二个命令后就显示的一些.cpp,表明来源于c++代码。
其次,还要了解该静态库所属平台,因为跨平台是没办法使用的,比如我手头的静态库是在x86_64下生成的,我直接拿到jetson nx上用,就会提示错误:/usr/bin/ld: skipping incompatible ./*.a when searching for .
错误原因就是静态库的编译环境与使用静态库的编译环境不一致造成的,使用以下两个命令查看当前系统的架构:
命令行下直接输入
uname -a
#命令行下直接输入
arch
例如我的板子输出为aarch64,表明属于AMD架构,pc机上一般输出为x86_64,然后再用以下命令查看静态库所属的架构:
#其中的Machine会显示属于哪个平台
readelf -h *.a
#以下命令会显示属于32位还是64位
objdump -p *.a
如果静态库所属架构与当前架构不一致,是没办法使用的,所以在生成静态库的时候一定要搞清楚当前平台和目标平台的架构是否一致,如果不一致,在生成静态库文件的时候必须使用交叉编译。
ps:我没有拿到源码,所以没办法自己交叉编译,只能找供应商帮忙重新生成,对方一脸不乐意,真的哭啦,还好最开始签了合同的,不然真的就gg了,所以大家在拿到静态库的时候最好先跟对方说明自己平台的情况,或者拿到源码。
2、交叉编译环境下静态库的制作和使用
首先是交叉编译环境的安装,我的架构是aarch64的,所以直接利用如下命令安装对应的交叉编译环境:
sudo apt-get install gcc-aarch64-linux-gnu
#安装成功后使用以下命令查看版本信息以确认是否安装成功
aarch64-linux-gnu-gcc -v
#安装c++的交叉编译
sudo apt install g++-aarch64-linux-gnu
#安装成功后使用以下命令查看是否安装成功
aarch64-linux-gnu-g++ -v
下面介绍下交叉编译的方法,顺便提一句,对于已经生成的静态库,是没办法交叉编译的,只能对源码进行交叉编译。对方让我自己对静态库交叉编译,各种查资料都没找到,还以为自己太菜了,结果后面老板给我讲这是不可行的,当时真想打人。
自己先编译好.cpp文件和头文件.h,记住头文件命名要采用如下格式,这些大家自己再查查资料,代码在板子上,就不细说了
然后使用以下命令生成.o文件
aarch64-linux-gnu-g++ -o hello.o -c hello.cpp
#非交叉编译环境下,只需将命令修改为
g++ -o hello.o -c hello.cpp
然后使用以下命令生成静态库(.a文件)
ar cr libhello.a hello.o
对于多个.o文件,可以打包到一个静态库中,使用以下命令
ar cr libhello.a hello.o happy.o
这样生成的静态库(.a文件)就可以在aarch64下使用了,例如
g++ main.cpp -o main -L. -lhello
如果中途提示错误 unresolvable R_AARCH64_ADR_PREL_PG_HI21 relocation against symbol '@@GLIBCXX’错误,使用以下命令解决,就是提示使用的是静态库
g++ -o main main.cpp -static -lhello -L.
3、调用静态库(.a文件)生成动态库,供python调用
首先编译好调用静态库的new_main.cpp文件,只需include静态库匹配的头文件.h,即可在当前new_main.cpp文件中直接使用静态库中的函数,为了使得当前new_main.cpp中的函数能够被python调用,所有函数都需编辑extern “C”{}中,例如
然后开始生成动态库.so文件:
#首先将.cpp文件编译为.o文件
g++ -o new_main.o -shared -fPIC -c new_main.cpp
#将.o文件打包为动态库.so文件,同时链接静态库.a文件
g++ -o libxxx.so new_main.o -shared -fPIC -L. -lxxx
#libxxx.so中的xxx表示生成的动态库名,xxx自己设置,-lxxx代表静态库文件xxx.a
动态库生成之后,直接在python中使用以下命令就可以调用动态库中的函数啦:
from ctypes import *
dll = cdll.LoadLibrary("./libxxx.so")