python调用c++/c 共享库,开发板上编译的一些坑!
1、对于python,ctypes只能load动态库,但现在我的对象是一个静态库,而且我没有源代码,静态库在编译过程中没有加--fPIC参数,
所以我也没办法将其编译为动态库,有没有什么方法在python里可以调用静态库的函数?
答案:静态库.a 如果编译时没有加-fPIC参数,需要加上-fPIC重新编译生成,然后可以被c++/c程序引用,并编译生成共享库.so,被python调用。g++ 编译生成方式如下:
g++ -shared -fPIC -o libmyAPI.so myAPI.o g++ slamdata_for_py.cpp -shared -fPIC -o slamdata_for_py.so -std=c++11 -I/opt/fp100/slam_ws/slamware_sdk_linux-aarch64-gcc4.8/linux-aarch64-release/include -L/opt/fp100/slam_ws/slamware_sdk_linux-aarch64-gcc4.8/linux-aarch64-release/lib -lstdc++ -ldl -lrt -lm -lpthread -lrpos_framework -lrpos_robotplatforms_rpslamware -lboost_atomic -lboost_atomic -lboost_date_time -lboost_regex -lboost_system -lboost_thread -lboost_filesystem -lboost_random -lbase64 -ljsoncpp -lrlelib -lcrypto -lcurl -lssl g++ testpy.cpp -fPIC -shared -o libtest.so -std=c++11 g++ test.cpp -std=c++11 -o test -I/opt/fp100/slam_ws/slamware_sdk_linux-aarch64-gcc4.8/samples/slamapipy/include -I/opt/fp100/slam_ws/slamware_sdk_linux-aarch64-gcc4.8/linux-aarch64-release/include -L/opt/fp100/slam_ws/slamware_sdk_linux-aarch64-gcc4.8/linux-aarch64-release/lib -L../ -lslamapipy -lstdc++ -ldl -lrt -lm -lpthread -lrpos_framework -lrpos_robotplatforms_rpslamware -lboost_atomic -lboost_atomic -lboost_date_time -lboost_regex -lboost_system -lboost_thread -lboost_filesystem -lboost_random -lbase64 -ljsoncpp -lrlelib -lcrypto -lcurl -lssl
2、不同编译器涉及到binutils 版本不同,在开发板上调整binutils 版本:
第一、去下载源码包
点击该网页http://ftp.gnu.org/gnu/binutils/ , 选择一个相应的版本xxx
wget http://ftp.gnu.org/gnu/binutils/xxx
点击该网页http://ftp.gnu.org/gnu/binutils/ , 选择一个相应的版本xxx
wget http://ftp.gnu.org/gnu/binutils/xxx
第二、 安装
./configure -disable-werror
make && make install
./configure -disable-werror
make && make install
3、共享库编译与运行
编译共享库:
gcc -o libdl_func.so -fPIC -rdynamic -shared dl_func.c
选项-fPIC指示编译器将代码编译成位置独立的代码,一般需要以程序文件共享其函数或变量给其他程序文件的代码都应该以此选项进行编译,选项-rdynamic指示编译器所编译/链接的为共享库程序文件。由于要使用外部变量,因此需要-shared选项,否则编译器会抛出错误信息:undefined reference to `name',表示不能找到name变量。
编译事例程序:
gcc -o dl_demo1 -L./ -ldl_func dl_demo1.c
选项-L./ 指示编译器在当前目录下寻找共享库文件,-ldl_func指示需要的共享库文件名为libdl_func.so。
运行:
./dl_demo1
编译共享库:
gcc -o libdl_func.so -fPIC -rdynamic -shared dl_func.c
选项-fPIC指示编译器将代码编译成位置独立的代码,一般需要以程序文件共享其函数或变量给其他程序文件的代码都应该以此选项进行编译,选项-rdynamic指示编译器所编译/链接的为共享库程序文件。由于要使用外部变量,因此需要-shared选项,否则编译器会抛出错误信息:undefined reference to `name',表示不能找到name变量。
编译事例程序:
gcc -o dl_demo1 -L./ -ldl_func dl_demo1.c
选项-L./ 指示编译器在当前目录下寻找共享库文件,-ldl_func指示需要的共享库文件名为libdl_func.so。
运行:
./dl_demo1
4、cmake 指定gcc/g++的版本进行程序编译生成
cmake 指定gcc/g++版本 : export CC=/usr/local/bin/gcc export CXX=/usr/local/bin/g++ cmake /path/to/your/project make
5、虚拟机交叉编译环境搭建:
sudo add-apt-repository ppa:linaro-maintainers/toolchain sudo apt-get update sudo apt-get install gcc-**version**-aarch64-linux-gnu sudo apt-cache search aarch64 查看哪些版本可以安装; sudo apt-get install gcc-4.8-aarch64-linux-gnu 安装一个gcc开头的4.8版本的支持64bit ARM linux的交叉编译工具; sudo apt-get install gcc-aarch64-linux-gnu 然后再安装一个没有版本号的gcc-aarch64-linux-gnu; sudo apt-get install g++-4.8-aarch64-linux-gnu sudo apt-get install g++-aarch64-linux-gnu
以上步骤是安装支持ARM64位系统的交叉编译工具,
安装之后,用aarch64-linux-gnu-gcc -v可以查看里边的版本信息,里边有host是什么,target是什么。
6、.so 动态库 undefined symbol
1、首先排查,C++调用了c的库?是不是需要加上extern "c",尤其是类的动态库,需要用到工厂模式,create一个对象出来,该工厂函数需要extern "c"声明。
extern "C" CDbBase* create();
extern "C" void destroy(CDbBase* p);
--
CDbBase* create()
{return new CDbDb2;
}
void destroy(CDbBase* p)
{printf("destroy CDbDb2!\n");
delete p;
}
2、使用ldd -r xxx.so或者 nm -A xxx.so等命令,查看so有哪些符号未定义的。
3、在步骤2发现有很多未定义的符号,跟运行时undefined symbol符合,而且该符号是外部的系统的动态库里定义的,那目标就定位到自己写的动态库里,链接的过程时,是否把这些动态库给链接进来。
查找发现makefile编译动态库时,找不到链接符号也是允许编译通过的,那最好是加上限制条件,在makefile加上 -Xlinker --unresolved-symbols=ignore-in-shared-libs ,让其报错,把未定义的符号给报错出来。
4、根据makefile的报错,原来是忘了把外部动态库给 -l进来,并把动态库路径-L进来,即可。
makefile中没有指定对应的静态库
makefile 中修改实现:
HOME_TREE := ../../ #CURDIR是make的内嵌变量,自动设置为当前目彿 notdir -Xlinker --unresolved-symbols=ignore-in-shared-libs -shared -fPIC MODULE_NAME := $(notdir $(CURDIR)) #CC = aarch64-linux-gnu-gcc #CXX = aarch64-linux-gnu-g++ CC = gcc CXX = g++ OBJS := slamdata_for_py.o houghlines.o SRCS = CXXSRC := src/slamdata_for_py.cpp src/houghlines.cpp INCLUDE := -I./include -I. -I$(HOME_TREE)/linux-aarch64-release/include INCLUDE += $(shell pkg-config --cflags opencv) OPENCV_LIBS = $(shell pkg-config --libs opencv) CFLAGS = -Wall -g -O -fPIC ###需要加-fPIC CXXFLAGS = -std=c++11 -shared -fPIC -Xlinker --unresolved-symbols=ignore-in-shared-libs #LDFLAGS := -static LD_LIBS = -Xlinker "-(" \ -lstdc++ -ldl -lrt -lm -lpthread \ -lrpos_framework -lrpos_robotplatforms_rpslamware \ -lboost_atomic \ -lboost_chrono \ -lboost_date_time \ -lboost_regex \ -lboost_system \ -lboost_thread \ -lboost_filesystem \ -lboost_random \ -lbase64 \ -ljsoncpp \ -lrlelib \ -lcrypto \ -lcurl \ -lssl \ -Xlinker "-)" \ LDFLAGS += -L$(HOME_TREE)/linux-aarch64-release/lib $(LD_LIBS) $(OPENCV_LIBS) TARGET = libslamapipy.so LIBPATH = ./libs/ vpath %.h ./include $(HOME_TREE)/linux-aarch64-release/include all:$(TARGET) $(OBJS):$(CXXSRC) $(CXX) -std=c++11 $(INCLUDE) -c -fPIC $^ $(TARGET):$(OBJS) $(CXX) $(CXXFLAGS) $(OBJS) -o $(TARGET) $(LDFLAGS) clean: rm -f *.o rm -f *.so rm -f $(LIBPATH)*
生成.so共享库一定不要静态链接(makefile 红字部分)。-Xlinker 可以解决库库之间相互依赖顺序问题。