How to compile a c++ application using static opencv libraries within docker How to compile a c++ application using static opencv libraries within docker docker docker

How to compile a c++ application using static opencv libraries within docker


After a lot of experimentation I finally got something working! There were a few issues that are all fixed in this Dockerfile. In order to reproduce this, create a Dockerfile with the following contents, and create another file called app.cpp with the simple code from my question above, in the same folder.

I will explain what the issues were below:

FROM alpine:3.8 as compilerRUN 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/repositoriesRUN 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/clangENV CXX /usr/bin/g++ENV OPENCV_VERSION='3.4.2' DEBIAN_FRONTEND=noninteractiveRUN mkdir /opt && cd /opt && \  wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \  unzip ${OPENCV_VERSION}.zip && \  rm -rf ${OPENCV_VERSION}.zipRUN 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/pkgconfigCOPY app.cpp app.cppRUN g++ -Wl,-Bstatic -static-libgcc -std=c++11 \    app.cpp \     -o /app \    $(pkg-config --cflags --libs -static opencv) \    -lgfortran -lquadmathFROM alpine    COPY --from=compiler /app /bin/app

Problems

Linker

There were indeed files that needed linking that weren't present, there were two reasons for this:

  • The pkg-config command is supposed to emit all of the necessary flags for compilation, but in my earlier attempt I hadn't included the -static flag to pkg-config. When you add the -static flag it makes sure to link the extra required packages. I saw a few people run into this problem with the solution of adding the extra flags like -pthread, but I found that the -static flag did this for me and so was preferable.
  • ld: cannot find -lgcc_s error. This appeared to be fixed by adding the -static-libgcc flag to g++. Some of this is still a mystery to me.

Missing Static Libraries

There were two libraries that I wanted to be included as static which needed to be acquired from sources other than apk. These were libjasper and libwebp. There are build steps above that acquire and build these as necessary and copy the resources into the required place.

More missing links

For reasons I can't yet explain pkg-config didn't provide the last two necessary flags. Those were -lgfortran and -lquadmath.

Notes about this Solution

I switched to alpine linux, just because I had read that some people had success with that, I'm sure the same could be done with Ubuntu. It did result in a much smaller image, so I do like that. This is about 900mb for the intermediate image, which, while huge, is much smaller than the 1.9GB Ubuntu image.

The actual resulting image is about 44mb including all of the statically linked OpenCV libs. This seems like a good solution for those that need a small docker image to run a single C++ bin.