跨多个环境动态链接提升
Posted
技术标签:
【中文标题】跨多个环境动态链接提升【英文标题】:Dynamically linking boost across multiple environments 【发布时间】:2019-08-09 15:25:58 【问题描述】:所以我正在尝试为二进制文件设置一个运行 docker 环境。 我试图使运行 docker 映像尽可能小。 二进制依赖于 boost,并且是使用 cmake 构建的
Cmake
cmake_minimum_required(VERSION 3.15)
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK)
set(Boost_NO_BOOST_CMAKE ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.70.0 REQUIRED COMPONENTS locale exception serialization system timer regex
thread program_options chrono filesystem iostreams)
include_directories($Boost_INCLUDE_DIRS SYSTEM)
增强功能取自源代码压缩包并构建为相当新的。 我使用本地机器构建(可以执行二进制没问题)。 然后,我构建了一个 docker 映像,我还从源代码安装/构建了 boost,并将二进制文件从我的本地计算机复制到 docker。
当我在 docker 中执行时,我在运行二进制文件时会丢失符号。
Docker 内部 - 二进制运行
root@200f0fb753fc:/opt/bin# ./run_bin
./run_bin: symbol lookup error: ./run_bin: undefined symbol: _ZN5boost9iostreams4zlib6finishE
我可以看到它可以找到正确的共享对象文件就好了
Docker 内部 - ldd
root@200f0fb753fc:/opt/bin# ldd ./run_bin
linux-vdso.so.1 (0x00007ffd54576000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd02fb46000)
libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007fd02f8b9000)
libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007fd02f3ee000)
libboost_regex.so.1.70.0 => /usr/lib/libboost_regex.so.1.70.0 (0x00007fd02f131000)
libboost_thread.so.1.70.0 => /usr/lib/libboost_thread.so.1.70.0 (0x00007fd02ef0d000)
libboost_filesystem.so.1.70.0 => /usr/lib/libboost_filesystem.so.1.70.0 (0x00007fd02ecf1000)
libboost_iostreams.so.1.70.0 => /usr/lib/libboost_iostreams.so.1.70.0 (0x00007fd02eae2000)
libboost_date_time.so.1.70.0 => /usr/lib/libboost_date_time.so.1.70.0 (0x00007fd02e8d0000)
libaerospike.so => /usr/lib/libaerospike.so (0x00007fd02e61c000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd02e293000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd02e07b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd02dc8a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd0304dc000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd02da86000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd02d6e8000)
root@200f0fb753fc:/opt/bin# find / -name "libboost_iostreams.so.1.70.0"
/usr/lib/libboost_iostreams.so.1.70.0
我可以在 cmake 上设置一个选项来启用在另一个环境中运行它吗?
或者是我试图做的根本错误?
【问题讨论】:
您是使用 Docker 构建源代码(当它构建映像时),还是在外部构建它然后安装它? 在外部构建并复制到 docker 映像中 - 两者都使用相同版本的 boost 为什么不在你的 Dockerfile 中构建它?那么就不会有跨平台问题了。 您的 Dockerfile 甚至可以从 SCM 中提取代码。 出于资源原因,我试图使 docker 映像尽可能小。我的目标是在其他地方构建并拥有一个最低限度的 docker 映像来运行二进制文件。添加所有用于构建的依赖项会使图像膨胀 【参考方案1】:据我所知,在小型 Docker 映像中构建二进制文件的最简单解决方案是使用 use multi-stage build Dockerfile
和 alpine 容器。
使用multi-stage build
你的Dockerfile
可以使用cmake
以及二进制文件依赖的任何库在一个(大的“臃肿”)映像中构建二进制文件,然后只需将可执行文件及其所需的任何文件复制到一个干净的文件中(小)alpine
图片。例如:
Dockerfile
FROM alpine:3.10 AS build
# Load build packages
RUN apk --update add --no-cache \
build-base \
cmake \
boost boost-dev
# The cmake boost variables
ENV BOOST_INCLUDEDIR /usr/include
ENV BOOST_LIBRARYDIR /usr/lib
WORKDIR /opt
COPY . <project-name>
WORKDIR /opt/<project-name>
RUN mkdir build \
&& cd build \
&& cmake \
-DBOOST_INCLUDEDIR=$BOOST_INCLUDEDIR \
-DBOOST_LIBRARYDIR=$BOOST_LIBRARYDIR \
-DCMAKE_BUILD_TYPE=Release \
..
&& make
# Create a clean alpine image for the binary
FROM alpine:3.10
# Copy the binary into the clean alpine image
COPY --from=build /opt/<project-name>/build/<binary-name> /bin/<binary-name>
# Copy the required library files into the clean alpine image
COPY --from=build /usr/lib/<library-names>.* /usr/lib/
# Run binary on entry
ENTRYPOINT ["/bin/<binary-name>"]
构建命令
docker build . -t <image-name>:<ver>
Docker 创建了两个镜像:一个是构建二进制文件的大镜像,另一个是仅包含二进制文件及其依赖项的较小(标记)镜像。
注意:alpine:3.10
apk
安装 boost
1.69.0 库。
您可能需要在第一个图像中构建您需要的boost
的特定版本,并将相关的.so
文件复制到第二个图像。
【讨论】:
不幸的是,我正在处理的项目依赖于不容易安装的 boost 1.70,它需要从源代码构建。我当前的解决方案与您上面的解决方案类似,但是我获得了 boost 源 tarball 并自己在 docker 映像中构建它。然后将人工制品复制到正在运行的图像中以进行动态链接。 我正在寻找是否可以在 boost 中配置链接,以便它不依赖于相同的确切 .so 库,因此我可以使用本地构建的二进制文件以及在 docker 中构建的更好开发者调试。使用您的解决方案,它们与来自 apt 包的 so 相同,因此它可以在此保护中工作以上是关于跨多个环境动态链接提升的主要内容,如果未能解决你的问题,请参考以下文章