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 可以解決庫庫之間相互依賴順序問題。