如何编译c++;在docker中使用静态opencv库的应用程序 我在C++中构建了第一个基于OpenCV的应用程序。我的目标是构建一个中间docker映像,该映像可以静态编译应用程序,以便它可以在生成的较小映像中独立运行。我愿意在这一步中使用任何docker图像,但为了让您能够准确地看到我所拥有的内容,这里有一个docker文件来重现整个环境: FROM ubuntu:18.04 as compiler ENV OPENCV_VERSION='3.4.2' DEBIAN_FRONTEND=noninteractive RUN apt-get -y update && \ apt-get -y upgrade && \ apt-get -y dist-upgrade && \ apt-get -y autoremove && \ apt-get install -y build-essential cmake RUN apt-get install -y qt5-default libvtk6-dev RUN apt-get install -y zlib1g-dev libjpeg-dev libwebp-dev libpng-dev libtiff5-dev libopenexr-dev libgdal-dev RUN apt-get install -y libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev yasm libopencore-amrnb-dev libopencore-amrwb-dev libv4l-dev libxine2-dev RUN apt-get install -y unzip wget RUN wget --progress=dot:giga https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q ${OPENCV_VERSION}.zip && \ rm ${OPENCV_VERSION}.zip && \ mv opencv-${OPENCV_VERSION} OpenCV && \ cd OpenCV && \ mkdir build && \ cd build && \ cmake \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_QT=ON \ -D WITH_OPENGL=ON \ -D FORCE_VTK=ON \ -D WITH_TBB=ON \ -D WITH_GDAL=ON \ -D WITH_XINE=ON \ -D BUILD_EXAMPLES=OFF \ -D ENABLE_PRECOMPILED_HEADERS=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_opencv_apps=OFF \ .. && \ make -j4 && \ make install && \ ldconfig COPY compile-test.cpp compile-test.cpp RUN g++ -std=c++11 -static compile-test.cpp -o /app $(pkg-config --cflags --libs opencv) 我可以编译我的C++应用程序而不使用DIANIC LIBS,但是这会创建一个巨大的DOCKER图像,我真的希望能够建立独立的二进制文件,以最小的大小。

如何编译c++;在docker中使用静态opencv库的应用程序 我在C++中构建了第一个基于OpenCV的应用程序。我的目标是构建一个中间docker映像,该映像可以静态编译应用程序,以便它可以在生成的较小映像中独立运行。我愿意在这一步中使用任何docker图像,但为了让您能够准确地看到我所拥有的内容,这里有一个docker文件来重现整个环境: FROM ubuntu:18.04 as compiler ENV OPENCV_VERSION='3.4.2' DEBIAN_FRONTEND=noninteractive RUN apt-get -y update && \ apt-get -y upgrade && \ apt-get -y dist-upgrade && \ apt-get -y autoremove && \ apt-get install -y build-essential cmake RUN apt-get install -y qt5-default libvtk6-dev RUN apt-get install -y zlib1g-dev libjpeg-dev libwebp-dev libpng-dev libtiff5-dev libopenexr-dev libgdal-dev RUN apt-get install -y libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev yasm libopencore-amrnb-dev libopencore-amrwb-dev libv4l-dev libxine2-dev RUN apt-get install -y unzip wget RUN wget --progress=dot:giga https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q ${OPENCV_VERSION}.zip && \ rm ${OPENCV_VERSION}.zip && \ mv opencv-${OPENCV_VERSION} OpenCV && \ cd OpenCV && \ mkdir build && \ cd build && \ cmake \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_QT=ON \ -D WITH_OPENGL=ON \ -D FORCE_VTK=ON \ -D WITH_TBB=ON \ -D WITH_GDAL=ON \ -D WITH_XINE=ON \ -D BUILD_EXAMPLES=OFF \ -D ENABLE_PRECOMPILED_HEADERS=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_opencv_apps=OFF \ .. && \ make -j4 && \ make install && \ ldconfig COPY compile-test.cpp compile-test.cpp RUN g++ -std=c++11 -static compile-test.cpp -o /app $(pkg-config --cflags --libs opencv) 我可以编译我的C++应用程序而不使用DIANIC LIBS,但是这会创建一个巨大的DOCKER图像,我真的希望能够建立独立的二进制文件,以最小的大小。,c++,opencv,docker,g++,C++,Opencv,Docker,G++,正如您所看到的,我正在从源代码处编译OpenCV,包括标志BUILD\u SHARED\u LIBS=OFF,以确保获得.a静态LIBS,而不是。因此动态LIBS。我从A中得到了一个提示,并修改它,以便在我使用C++时,用DOCKER省略一些Python的东西。 因为我在实际应用程序中遇到了很多麻烦,所以我继续创建了一个更简单的应用程序,它在编译过程中也会崩溃。我相信这与包含的cflags和libs有关。这个问题目前超出了我的理解力。当我在compile命令上调整一个include时,我会遇到堆

正如您所看到的,我正在从源代码处编译OpenCV,包括标志
BUILD\u SHARED\u LIBS=OFF
,以确保获得
.a
静态LIBS,而不是
。因此
动态LIBS。我从A中得到了一个提示,并修改它,以便在我使用C++时,用DOCKER省略一些Python的东西。 因为我在实际应用程序中遇到了很多麻烦,所以我继续创建了一个更简单的应用程序,它在编译过程中也会崩溃。我相信这与包含的
cflags
libs
有关。这个问题目前超出了我的理解力。当我在compile命令上调整一个include时,我会遇到堆积如山的错误,这些错误似乎会发生变化。这是我试图编译的最简单的应用程序。它实际上什么都不做,但它确实包含一个lib

#include "opencv2/imgcodecs.hpp"
using namespace cv; 
Mat img;

int main( int argc, char** argv ) {
  img = cv::imread( argv[1], IMREAD_COLOR );
}
然后我试着这样编译:

g++ -std=c++11 -static compile-test.cpp -o /app $(pkg-config --cflags --libs opencv)
它最终会变成一堆错误,太长了,无法完全粘贴到这里

//usr/local/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o): In function `cv::JpegEncoder::write(cv::Mat const&, std::vector<int, std::allocator<int> > const&)':
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0xf8): undefined reference to `jpeg_CreateCompress'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x105): undefined reference to `jpeg_std_error'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x2b5): undefined reference to `jpeg_set_defaults'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x2d0): undefined reference to `jpeg_set_quality'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x2fe): undefined reference to `jpeg_quality_scaling'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x30d): undefined reference to `jpeg_quality_scaling'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x367): undefined reference to `jpeg_default_qtables'
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3MatERKSt6vectorIiSaIiEE+0x379): undefined reference to `jpeg_start_compress'
grfmt_jpeg.cpp:
...
collect2: error: ld returned 1 exit status
//usr/local/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o):在函数'cv::JpegEncoder::write(cv::Mat const&,std::vector const&')中:
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0xf8):对“jpeg_CreateCompress”的未定义引用
grfmt_jpeg.cpp:(.text._zn2cv11jpegencoder5 writeerkns_3materkst6vectorisaiee+0x105):对“jpeg标准错误”的未定义引用
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0x2b5):未定义对“jpeg设置默认值”的引用
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0x2d0):未定义对“jpeg设置质量”的引用
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0x2fe):对“jpeg质量缩放”的未定义引用
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0x30d):对“jpeg质量缩放”的未定义引用
grfmt_jpeg.cpp:(.text._zn2cv11jpegencoder5 writeerkns_3materkst6vectorisaiee+0x367):对“jpeg_default_qtables”的未定义引用
grfmt_jpeg.cpp:(.text._ZN2cv11JpegEncoder5writeERKNS_3materkst6vectorisaiee+0x379):对“jpeg_start_compress”的未定义引用
grfmt_jpeg.cpp:
...
collect2:错误:ld返回了1个退出状态
有些事情我已经试过了
  • 开始搜索每个看似独特的编译错误,并在编译代码末尾添加相关标志
  • 对一些include标志进行重新排序,但要有效地做到这一点,数量太多了
  • 使用
    opencv-dev
    包而不是自己编译,但似乎您无法做到这一点,希望使用静态libs

经过大量的实验,我终于找到了工作!在此
Dockerfile
中有几个问题都已解决。为了重现这一点,请创建一个包含以下内容的Dockerfile,并在同一文件夹中使用上面问题中的简单代码创建另一个名为
app.cpp
的文件

我将在下面解释这些问题:

FROM alpine:3.8 as compiler

RUN echo -e '@edgunity http://nl.alpinelinux.org/alpine/edge/community \
    @edge http://nl.alpinelinux.org/alpine/edge/main \
    @testing http://nl.alpinelinux.org/alpine/edge/testing \
    @community http://dl-cdn.alpinelinux.org/alpine/edge/community' \
    >> /etc/apk/repositories

RUN apk add --update --no-cache \
      build-base \
      openblas-dev \
      unzip \
      wget \
      cmake \
      g++ \
      libjpeg  \
      libjpeg-turbo-dev \
      libpng-dev \
      jasper-dev \
      tiff-dev \
      libwebp-dev \
      clang-dev \
      linux-headers 

ENV CC /usr/bin/clang
ENV CXX /usr/bin/g++
ENV OPENCV_VERSION='3.4.2' DEBIAN_FRONTEND=noninteractive

RUN mkdir /opt && cd /opt && \
  wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \
  unzip ${OPENCV_VERSION}.zip && \
  rm -rf ${OPENCV_VERSION}.zip

RUN mkdir -p /opt/opencv-${OPENCV_VERSION}/build && \
  cd /opt/opencv-${OPENCV_VERSION}/build && \
  cmake \
    -D BUILD_DOCS=OFF \
    -D BUILD_EXAMPLES=OFF \
    -D BUILD_opencv_apps=OFF \
    -D BUILD_opencv_python2=OFF \
    -D BUILD_opencv_python3=OFF \
    -D BUILD_PERF_TESTS=OFF \
    -D BUILD_SHARED_LIBS=OFF \ 
    -D BUILD_TESTS=OFF \
    -D CMAKE_BUILD_TYPE=RELEASE \
    -D ENABLE_PRECOMPILED_HEADERS=OFF \
    -D FORCE_VTK=OFF \
    -D WITH_FFMPEG=OFF \
    -D WITH_GDAL=OFF \ 
    -D WITH_IPP=OFF \
    -D WITH_OPENEXR=OFF \
    -D WITH_OPENGL=OFF \ 
    -D WITH_QT=OFF \
    -D WITH_TBB=OFF \ 
    -D WITH_XINE=OFF \ 
    -D BUILD_JPEG=ON  \
    -D BUILD_TIFF=ON \
    -D BUILD_PNG=ON \
  .. && \
  make -j$(nproc) && \
  make install && \
  rm -rf /opt/opencv-${OPENCV_VERSION}

RUN wget --progress=dot:giga https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.0-linux-x86-64.tar.gz && \
    pwd && \
    tar -xzf libwebp-1.0.0-linux-x86-64.tar.gz && \
    mv /libwebp-1.0.0-linux-x86-64/lib/libwebp.a /usr/lib && \
    rm -rf /libwebp*

RUN wget --progress=dot:giga http://www.ece.uvic.ca/~frodo/jasper/software/jasper-2.0.10.tar.gz && \
    tar -xzf jasper-2.0.10.tar.gz && \
    cd jasper-2.0.10 && \
    mkdir BUILD && \
    cd BUILD && \
    cmake -DCMAKE_INSTALL_PREFIX=/usr    \
      -DCMAKE_BUILD_TYPE=Release     \
      -DCMAKE_SKIP_INSTALL_RPATH=YES \
      -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/jasper-2.0.10 \
      -DJAS_ENABLE_SHARED=FALSE \
      ..  && \
    make install && \
    rm -rf /jasper-2.0.10*

ENV PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:/usr/lib/pkgconfig

COPY app.cpp app.cpp

RUN g++ -Wl,-Bstatic -static-libgcc -std=c++11 \
    app.cpp \ 
    -o /app \
    $(pkg-config --cflags --libs -static opencv) \
    -lgfortran -lquadmath

FROM alpine    
COPY --from=compiler /app /bin/app
问题 连接器 确实有需要链接的文件不存在,原因有两个:

  • pkg config
    命令应该发出编译所需的所有标志,但在我之前的尝试中,我没有将
    -static
    标志包含到
    pkg config
    中。当您添加
    -static
    标志时,它确保链接额外需要的包。我看到一些人在添加额外标志(如
    -pthread
    )的解决方案中遇到了这个问题,但我发现
    -static
    标志为我做到了这一点,因此更可取
  • ld:找不到-lgcc\u s
    错误。通过将
    -static libgcc
    标志添加到
    g++
    中,似乎可以解决这个问题。其中一些对我来说仍然是个谜
缺少静态库 有两个库我想作为静态库包含,它们需要从apk以外的源获取。这些是
libjasper
libwebp
。上面有一些构建步骤,可以根据需要获取和构建这些步骤,并将资源复制到所需的位置

更多缺失的链接 出于无法解释的原因,
pkg config
没有提供最后两个必要的标志。这些是
-lgfortran
-lquadmath

关于此解决方案的注释 我转向了alpine linux,只是因为我读到一些人在这方面取得了成功,我相信Ubuntu也可以做到这一点。它确实导致了一个更小的图像,所以我喜欢这样。中间映像的大小约为900mb,虽然很大,但比1.9GB的Ubuntu映像小得多


实际生成的图像约为44mb,包括所有静态链接的OpenCV库。对于那些需要一个小码头工人图像运行单个C++库的人来说,这似乎是一个很好的解决方案。Aafaik静态版本中有很多额外的lib。我想这可能是我的全部问题。我只是不确定什么需要链接,以及链接的顺序。我不知道心理算法是什么,除了谷歌搜索每个错误,它似乎仍然不能告诉我链接的顺序。我尝试了你的代码,尽管你去掉了大部分依赖项