本文最后更新于 almost 3 years ago,文中所描述的信息可能已发生改变。
前言
笑死,搞这个halcon环境,从c++编译so库到JNA调用再到打包成镜像已经熬走两位中级JAVA工程师了,到头来还是我跑完了整个流程,简历经验+1(熟练使用docker)
牛排能有什么坏心思,只想多挣钱罢了…
正文
先来回忆一下,之前已经实现了 halcon导出C++代码并打包成so库给JAVA的JNA调用 。但实际项目是需要部署到k8s上的,于是通过 【Paddle】用docker打包paddle文字识别服务 简单熟悉了一下通过编写DockerFile构建镜像的过程。
构建过程
FROM ubuntu
# Switch to root user to install additional software
USER 0
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
ENV LD_LIBRARY_PATH=/opt/halcon/lib/x64-linux
ADD ./halcon /opt/halcon
ADD ./sknp /home/sknp
# JAVA环境
ADD ./jdk1.8.0_291 /usr/local/jdk1.8.0_291
ENV JAVA_HOME /usr/local/jdk1.8.0_291
ENV JRE_HOME /usr/local/jdk1.8.0_291/jre
ENV PATH $JAVA_HOME/bin:$JRE_HOME/bin:$PATH
RUN chmod -R 755 /usr/local/jdk1.8.0_291/
RUN apt-get update -q && \
apt-get install -q -y --no-install-recommends \
bzip2 \
ca-certificates \
git \
libglib2.0-0 \
libsm6 \
libxext6 \
libxrender1 \
mercurial \
openssh-client \
procps \
subversion \
wget \
gcc \
g++ \
clang \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER 1000
apt install中 gcc
、g++
、clang
是必须的,用于编译cpp代码,其他包的延用之前anaconda环境,具体哪些有用哪些没用就交给读者去辨别啦~
说明:
ENV 命令中:LD_LIBRARY_PATH的值是halcon动态库的所在路径;
ADD 命令中:
halcon
是halcon在x64-linux平台的安装目录,通常是/opt/halcon/
;sknp
是我用于验证的demo;
很简单吧,以上配置还可以通过删除demo和halcon安装目录中的多余文件,实现进一步精简,最终从17G缩减到1.74G!!!
根本不需要安装halcon运行库!!!
踩坑心得
Chapter 1
在虚拟机上运行成功后,便着手移植到docker镜像中,由于运行 install-linux.sh
需要手动输入配置,无法直接build,所以想到可以从虚拟机复制整个halcon安装目录(完整版10GB+)
Chapter 2
为了达到精简镜像的目的,决定安装halcon的运行库(166MB),基础镜像采用带vnc的centos7
BUT!centos7自带的g++、gcc还停留在4.8版本,而我编译的cpp使用9.3
于是参考 CentOS 7.8使用devtoolset-9使用高版本gcc version 9.3.1_Gblfy_Blog-CSDN博客 进行升级:
yum install centos-release-scl -y
yum install devtoolset-9 -y
#临时覆盖系统原有的gcc引用
scl enable devtoolset-9 bash
# 查看gcc版本
gcc -v
虽然顺利升级了,但此时还是无法使用,年轻的牛排还未意识到是halcon运行库缺少某些文件导致的
Chapter 3
在尝试centos7后发现它的gcc、g++贼落后,于是使用ubuntu作为基础镜像,而后修改了 install-linux.sh
实现无人值守安装。此时依然提示无法找到要链接的动态库…
Chapter 4
又回到最初的起点,呆呆的坐在电脑前🎵
经过验证,完整版的halcon能用,就是太大了。只好硬着头皮删掉里面的无用文件,真香!
Chapter 5
至此,从C++代码编译so库,再到JNA调用,再到现在的镜像构建,由本 初级工程师 攻克完成,最终镜像定格在1.74GB
最后
若使用
install-linux.sh
安装,需要修改脚本,将其中的 $myread (相当于python的input)后的变量赋值(赋值时不能有不必要的空格),达到缺省安装的效果;若想让LD_LIBRARY_PATH变量生效,需要添加
ENV LD_LIBRARY_PATH=/opt/halcon/lib/x64-linux
,而不是在容器中 source;关于软连接问题,若替换的halcon动态库如与原本的文件名不同,需要重新建立软连接:
bashln -s libhalcon.so.20.11.1 libhalcon.so ln -s libhalconcpp.so.20.11.1 libhalconcpp.so
不需要花里胡哨,只要把halcon完整版的安装目录拷贝到容器的
/opt/
下,配置LD_LIBRARY_PATH,完事!
还有一件事
之前一直搞不懂的JNA接收C++返回字符串的乱码问题,是因为halcon的字符串类的转换问题,可以通过以下代码转换:
...
HString str = hv_res.S();
char* pChText = new char[255];
memset(pChText, 0x00, 255);
// str.Text() 得到 const char*类型
sprintf(pChText, "%s", str.Text()); // 格式化字符串
return pChText;
好了,先说这么多,吃饭去了拜拜~