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