1. 程式人生 > 其它 >編譯,發版,連結庫問題

編譯,發版,連結庫問題

一般發版我們就發一個.so和標頭檔案。
標頭檔案說明類的方法呼叫,so是方法的實現。比如opencv庫就是標頭檔案和so。就提供兩個資料夾一個include和lib。
但是我們工程還依賴於各種庫,這個時候你除了提供以上2個檔案還需要提供所用到的第三方庫簡稱3rdparty。
我們現在工程比較麻煩,需要在不同平臺下面執行,比如1070,2080,3090,寒武紀。每個平臺下面所依賴的庫不同。
所以我們現在用的方法是提供各個平臺的庫在資料夾3rdparty下面,然後再寫一個配置環境變數的shell指令碼。
這個指令碼可自動識別當前是哪個平臺比如1070,還是寒武紀。然後export當前平臺所對應的3rdparty。
具體來說就是如下shell程式碼:

#!/bin/bash
if test $( nvidia-smi | grep 'GPU'| wc -l ) -eq 0 
then
    echo "start on cambricon"
    export LD_LIBRARY_PATH=$PWD/../hwj_lib/:$PWD/../3rdlib/libboost:$PWD/../3rdlib/opencv-3.4.10:$PWD/../3rdlib/glog:$PWD/../3rdlib/gflags:$PWD/../3rdlib/caffe_hwj/:$PWD/../3rdlib/libtorch_hwj:$PWD/../3rdlib/cuda_10:$PWD/../3rdlib/cambricon/:$PWD/../3rdlib/atlas:$PWD/../3rdlib/lib:$PWD/../3rdlib/protobuf:$PWD/../3rdlib/python2:$PWD/../3rdlib/lib_gtk/:$PWD/../3rdlib/freetype:$PWD/../nvidia_lib:$PWD/../3rdlib/curl/
else
    if test $( nvidia-smi -L | grep 'TX 1070' | wc -l ) -gt 0
    then
        echo "start on nvidia 1070"
        export LD_LIBRARY_PATH=$PWD/../3rdlib/libboost:$PWD/../3rdlib/opencv-3.4.10:$PWD/../3rdlib/glog:$PWD/../3rdlib/gflags:$PWD/../3rdlib/caffe_8:$PWD/../3rdlib/libtorch_8:$PWD/../3rdlib/cuda_8:$PWD/../3rdlib/lib:$PWD/../3rdlib/protobuf:$PWD/../3rdlib/python2:$PWD/../3rdlib/atlas:$PWD/../3rdlib/lib_gtk/:$PWD/../3rdlib/freetype:$PWD/../lib:$PWD/../3rdlib/cambricon/:$PWD/../3rdlib/curl/
    fi
    if test $( nvidia-smi -L | grep 'TX 1080' | wc -l ) -gt 0
    then
        echo "start on nvidia 1080"
        export LD_LIBRARY_PATH=$PWD/../3rdlib/libboost:$PWD/../3rdlib/opencv-3.4.10:$PWD/../3rdlib/glog:$PWD/../3rdlib/gflags:$PWD/../3rdlib/caffe_8:$PWD/../3rdlib/libtorch_8:$PWD/../3rdlib/cuda_8:$PWD/../3rdlib/lib:$PWD/../3rdlib/protobuf:$PWD/../3rdlib/python2:$PWD/../3rdlib/atlas:$PWD/../3rdlib/lib_gtk/:$PWD/../3rdlib/freetype:$PWD/../lib:$PWD/../3rdlib/cambricon/:$PWD/../3rdlib/curl/
    fi
   
fi

當我接手一個新需求,就是單獨實現一個識別功能只用cpu,同樣的也是需要適應各個平臺。踩了不少坑,最後的最後向著我們工程的方法靠攏就解決了!!!

下面是雜雜念:

原始碼編譯工程資料夾是原始碼,在本地機器上編譯通過。
走了不少彎路,一開始隨便在一臺電腦上編譯,成功瞭然後拿到另外一臺電腦編譯,然後有的電腦好使有的就會報錯!
能編譯成功,但是一執行就報非法指令。

車檢工程發版的庫檔案有3,4個,比如在1070卡上面有三個庫資料夾,3rdparty_10,3rdparty_20,3rdparty_30.
這裡面的庫檔案很重要,和電腦配置息息相關。應該說這裡的庫檔案和當前電腦的配置有關。各個庫之間的依賴關係也都是對的。但是具體哪些庫和什麼配置有關或者哪些庫依賴與哪些配置我現在還不清楚。最拿基本的caffe來說,不同平臺需要編譯不同版本的caffe庫,因為在1070上面caffe依賴的cuda是8.0. 在2080卡上面caffe依賴的cuda是10.0. 所以不同平臺各個庫都有對應的依賴關係。

現在編譯也和車檢發版一樣。在不同平臺上面編譯用對應的3rdparty編譯就可以了。

但是發版的時候只需要釋出庫檔案就可以了,就是釋出/lib/libchejian.so這個庫檔案和對應的標頭檔案就可以了!!
但是依賴的第三方庫也需要提供。這裡可以直接用車檢工程釋出的第三方庫就可以。因為是一樣的。
在執行的時候首先需要執行source chejian_redis_env.sh。可以根據當前硬體初始化環境LD_LIBRARY_PATH.

資料夾bin下面的可執行檔案就是呼叫libchejian.so來執行,這個可以供我們測試當前環境是否可以跑。

現在有個疑問是在原始碼編譯的時候比如我們需要放boost的標頭檔案,然後編譯libchejian.so。
在發版的時候只需要釋出libchejian.so和其標頭檔案,這個時候只需要放置boost庫檔案不需要boost的標頭檔案。
寫著寫著這些疑問的時候好像又理解了。
原始碼編譯工程的時候需要用到boost的標頭檔案和庫,當你編譯好工程的時候生成你自己的so庫。別人用你這個庫你只需要提供庫和標頭檔案。
你的庫所依賴的其他庫你提供庫就可以,不需要標頭檔案了,因為標頭檔案都編譯在你自己庫裡面了。如此。

用的caffe庫是寒武紀資料夾下面的,然後編譯出來在寒武紀和我的電腦i7上面是可以執行跑的,但是在i5機器跑不了。
可以編譯出來庫,但是一執行就報錯!報非法指令。然後gdb執行,看錯誤。

root@-desktop:/home/yhl/yanzhengma_1022_0/yanzhengma/bin# gdb
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file cpu_test 
Reading symbols from cpu_test...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/yhl/yanzhengma_1022_0/yanzhengma/bin/cpu_test 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffd7ff8700 (LWP 6312)]
[New Thread 0x7fffd77f7700 (LWP 6313)]
[New Thread 0x7fffd4ff6700 (LWP 6314)]

Thread 1 "cpu_test" received signal SIGILL, Illegal instruction.
0x00007fffefa17fc3 in CryptoPP::DetectX86Features () at cpu.cpp:262
262	cpu.cpp: 沒有那個檔案或目錄.
(gdb) 

然後把caffe換成cuda8的caffe,然後報protobuf未定義的引用什麼的。。。
無解

然後我突然想到在發版伺服器70.209上面,分了好幾個3rdparty資料夾,發版哪個就軟連線哪個。就說明各個平臺的庫是不一樣的。
而且有個重要的點就是,我發現演算法提供給軟體部演算法庫裡面的3rdparty裡面有些庫是沒有標頭檔案的,比如我一開始到一臺電腦上面去原始碼編譯我的程式碼,然後有的電腦就會報缺少boost標頭檔案,我一看我3rdparty下面確實只提供了庫,沒有提供標頭檔案。然後只能網上百度sudo apt-get 安裝庫。然後就可以。
於裡超說是因為你編譯的時候是需要標頭檔案的,編譯好了就在庫裡面了。

所以一般而言,我們演算法編譯出來的庫只需要提供其他庫的.so,標頭檔案不需要提供。因為其他庫標頭檔案已經被你編譯到當前so庫中了,後面只需要提供其他庫的so檔案。

寫的好亂,我只當我自己的記錄。在此過程中還是出現了好多報錯,我都感覺無從下手,比如
libXXX.so依賴於XXX,not found
未定義的引用

突然想起來,一個問題現象是,就是我用別人的機器來跑我的這個識別的demo。然後編譯的時候一堆錯誤啊,無從下手,然後讓同事看,然後同事最後解決了說我這個工程所依賴的庫和這個電腦上面所需要的一樣,
然後就呼叫這個電腦其他路徑下面的庫了,他把在一個地方指定搜尋庫路徑註釋掉就好了,在系統哪個目錄下面,什麼/etc/ld_conf.so之類的地方,是一個文字可以寫路徑,具體忘記了。
但是我想說的是,我在
cmakelist檔案中已經指定了各個庫路徑,比如如下:

set(BOOST_ROOT ${CMAKE_SOURCE_DIR}/3rdparty/libboost)
include_directories(${BOOST_ROOT}/include)
link_directories(${BOOST_ROOT}/lib)

cmakelist已經指定了,它還是會優先找其他地方啊。
可能cmakelis指定的庫路徑優先順序比系統其他某處指定的路徑優先順序低。先在系統指定路徑下面找到了這個庫就不在其他地方找了。
所以這個時候你指定的庫優先在其他地方找到了就不會用你自己指定的庫了。

好記性不如爛鍵盤---點滴、積累、進步!