ubuntu16.04 利用Docker 部署C++ Gui项目(OpenCV PCL动态库集成)


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

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM