1、打包你的C++程序
一個良好的可移植的C++程序應該包含可執行文件、依賴的動態庫、以及參數和數據項。其中,依賴的動態庫需要ldd命令查看,如下圖:
通過ldd ./yourexe 可快速的查看你的程序所依賴的動態庫文件和他們所在的文件位置,為了方便,接下來使用腳本ldd.sh將他們拷貝至特定文件夾:
1 function useage() 2 { 3 cat << EOU 4 Useage: bash $0 <path to the binary> <path to copy the dependencies> 5 EOU 6 exit 1 7 } 8 9 #Validate the inputs 10 [[ $# < 2 ]] && useage 11 12 #Check if the paths are vaild 13 [[ ! -e $1 ]] && echo "Not a vaild input $1" && exit 1 14 [[ -d $2 ]] || echo "No such directory $2 creating..."&& mkdir -p "$2" 15 16 #Get the library dependencies 17 echo "Collecting the shared library dependencies for $1..." 18 deps=$(ldd $1 | awk 'BEGIN{ORS=" "}$1\ 19 ~/^\//{print $1}$3~/^\//{print $3}'\ 20 | sed 's/,$/\n/') 21 echo "Copying the dependencies to $2" 22 23 #Copy the deps 24 for dep in $deps 25 do 26 echo "Copying $dep to $2" 27 cp "$dep" "$2" 28 done 29 30 echo "Done!"
使用的方法:ldd.sh yourexe(可執行文件) des_path(目標文件夾)。此后,獲取到所有依賴的動態庫文件之后,將可執行文件、庫文件一起打包即可移植到其他電腦運行,當然還需要指定程序運行時查找動態庫的路徑。(ubuntu系統下查找路徑常為:/lib .usr/lib /usr/local/lib) 可以修改環境變量的方式將庫文件路徑加入到環境變量中,告訴系統在程序運行時到哪里去找依賴庫,因此運行腳本run.sh可以這樣寫:
1 path_curr=$(cd `dirname $0`; pwd) 2 #dirname $0,取得當前執行的腳本文件的父目錄 3 #cd `dirname $0`,進入這個目錄(切換當前工作目錄) 4 #pwd,顯示當前工作目錄(cd執行后的) 5 6 # add share lib path to system 7 export PATH="${path_curr}:$PATH" 8 export LD_LIBRARY_PATH="${path_curr}:$LD_LIBRARY_PATH" 9 10 # print for debug 11 #echo $LD_LIBRARY_PATH 12 #ldd ./main 13 14 # execute 15 ./yourexename $prama1 $prama2 $3prama3 16 # $0 $1 $2 $3 is the parameters from Terminal
因此現在打包之后的文件夾中應該包含——所有動態庫文件(.so)、可執行文件(exe)及數據文件、啟動腳本(.sh)。
2、Docker理解與使用
為什么要用Docker?假設有這樣一個場景,你在你的ubuntu中編寫並編譯通過了的程序需要交付給測試人員測試,如何做?直接發可執行文件?當然不行,這樣你的測試人員會問你為什么我運行報錯,你會說缺少一個某某庫,你編譯一下某某庫再運行吧,顯然,這是一種極其不合理的測試方式,換一台電腦就要重新配置,將浪費大量的時間。或者你可以說把你的電腦拷貝給測試人員,這很傳統也很好地解決了這個問題,docker解決了“把你的電腦拷貝”這個問題。你可以利用docker制造一個與你的電腦環境相同的母本(image)並上傳到你的個人倉庫(dockerhub),測試人員只需要到倉庫pull你的image,並根據你的image創造一個一摸一樣的運行環境(container)即可解決問題。這與GitHub相似,因此上手非常容易。
制造image——Dockerfile的書寫。想要制造與本地環境相同的image,必須利用Dockerfile來實現,這類似於CmakeLists能很好地聲明預編譯組織結構一樣,Dockerfile能很好地說明將要生成的Image中應該包含什么,做什么。例如,我想要一個基於Ubuntu16.04的image,並且拷貝我本地的可執行文件和庫文件以及其他數據或是配置文件(步驟1里面說明),具體的Dockerfile語法參考Dockerfile命令詳解。我的Dockerfile如下:
1 FROM ubuntu:16.04 2 3 RUN apt-get update 4 RUN apt-get install -y ocl-icd-opencl-dev 5 6 RUN mkdir /usr/src/OESM_Rebuild 7 RUN mkdir /usr/src/OESM_Rebuild/build 8 9 10 11 12 COPY so_lib /usr/src/OESM_Rebuild/build 13 COPY resource /usr/src/OESM_Rebuild/build 14 15 16 17 RUN ["chmod", "a+x", "/usr/src/OESM_Rebuild/build/run.sh"] 18 19 WORKDIR /usr/src/OESM_Rebuild/build 20 21 22 CMD ./run.sh
Dockers 幾個常見命令:
sudo apt-get install docker-ce —— 下載安裝Docker社區版
docker images —— 查看本地的images(會以列表形式顯示本地的images)
docker rmi IMAGE ID —— 刪除特定ID的image
docker ps -a ——查看本地所有容器
docker rm CONTAINER ID —— 刪除特定ID的容器
docker login —— 登錄你的Docker
docker push IMAGE:TAG ——上傳image到你的倉庫
docker pull IMAGE:TAG ——拉取Image
docker save -o filepath.tar IMAGE —— 保存image到壓縮包
docker load -i filepath.tar —— 從壓縮包中加載image
最重要的命令:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] ——理解為參考某鏡像並生成容器運行。這里的COMMOND會覆蓋Dockerfile中的CMD命令作為容器生成后的第一條指令。
通過dockerfile書寫生成鏡像image后,可以通過save命令保存成壓縮包,隨后可以通過load加載壓縮包生成鏡像(這個速度比Dockerfile要快),因此現在具有鏡像壓縮包后只要調用load命令和docker run命令似乎就可以在別的電腦運行自己的程序了。但還是有問題,引文我的C++利用了PCL點雲庫和OpneCV圖形庫,會具有許多GUI界面,直接docker run會報錯:cannot open display。問題很好理解,你的容器不知道該去哪兒顯示這些界面,要知道它可不能直接用你的電腦屏幕,因此查找解決辦法。
因此最終包括的內容包括:image.tar、docker_run.sh其中docker_run內容如下:
1 apt-get install -y x11-xserver-utils 2 3 xhost + 4 5 docker load -i oesm_rebuild.tar 6 7 docker run -i -t \ 8 -v /etc/localtime:/etc/localtime:ro \ 9 -v /tmp/.X11-unix:/tmp/.X11-unix \ 10 -e DISPLAY=unix$DISPLAY \ 11 -e GDK_SCALE \ 12 -e GDK_DPI_SCALE \ 13 oesm_rebuild:v1