From cb1c72dac557d90c2fdd4ece5acee5405ca3267d Mon Sep 17 00:00:00 2001
From: Georgy Kirichenko <georgy@tarantool.org>
Date: Sun, 8 Jul 2018 21:52:00 +0300
Subject: [PATCH] Tarantool static build ability

A possibility to build tarantool with included library dependencies.
Use the flag -DBUILD_STATIC=ON to build statically against curl, readline,
ncurses, icu and z.
Use the flag -DOPENSSL_USE_STATIC_LIBS=ON to build with static
openssl

Changes:
  * Add FindOpenSSL.cmake because some distributions do not support the use of
  openssl static libraries.
  * Find libssl before curl because of build dependency.
  * Catch all bundled libraries API and export then it in case of static
  build.
  * Rename crc32 internal functions to avoid a name clash with linked libraries.

Notes:
  * Bundled libyaml is not properly exported, use the system one.
  * Dockerfile to build static with docker is included

Fixes #3445
---
 CMakeLists.txt           |  60 ++++----
 Dockerfile.staticbuild   |  90 ++++++++++++
 cmake/BuildMisc.cmake    |  10 ++
 cmake/FindCURL.cmake     |  22 ++-
 cmake/FindICU.cmake      |  22 ++-
 cmake/FindLibYAML.cmake  |   8 +-
 cmake/FindOpenSSL.cmake  | 291 +++++++++++++++++++++++++++++++++++++++
 cmake/FindReadline.cmake |  34 +++--
 cmake/FindTermcap.cmake  |   8 +-
 cmake/FindZSTD.cmake     |   7 +-
 cmake/compiler.cmake     |  42 ++++--
 extra/mkexports          |  14 +-
 src/CMakeLists.txt       |  48 +++++--
 third_party/crc32.c      |   6 +-
 third_party/crc32.h      |   6 +-
 15 files changed, 597 insertions(+), 71 deletions(-)
 create mode 100644 Dockerfile.staticbuild
 create mode 100644 cmake/FindOpenSSL.cmake

diff --git a/CMakeLists.txt b/CMakeLists.txt
index cea4a7d3e0..bf68d1875b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -286,6 +286,40 @@ find_package_message(MODULE_LIBPATH "Lua package.cpath: ${MODULE_LIBPATH}"
 
 add_custom_target(build_bundled_libs)
 
+# Debian: missing zstd_static.h in libzstd-dev
+# Fedora: not found
+# => use bundled version by default
+
+option(ENABLE_BUNDLED_ZSTD "Enable building of the bundled zstd" ON)
+if (ENABLE_BUNDLED_ZSTD)
+    include(BuildZSTD)
+    zstd_build()
+    add_dependencies(build_bundled_libs zstd)
+else()
+    set(ZSTD_FIND_REQUIRED ON)
+    find_package(ZSTD)
+endif()
+
+#
+# OpenSSL
+#
+find_package(OpenSSL)
+if (OPENSSL_FOUND)
+    message(STATUS "OpenSSL ${OPENSSL_VERSION} found")
+    include_directories(${OPENSSL_INCLUDE_DIR})
+else()
+    message(FATAL_ERROR "Could NOT find OpenSSL development files (libssl-dev/openssl-devel package)")
+endif()
+
+#
+# OpenSSL can require Z library (depending on build time options), so we add
+# it to libraries list in case of static build.
+#
+if(BUILD_STATIC)
+    find_library(Z_LIBRARY libz.a)
+    set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ${Z_LIBRARY})
+endif()
+
 #
 # Curl
 #
@@ -404,32 +438,6 @@ endif()
 # zstd
 #
 
-# Debian: missing zstd_static.h in libzstd-dev
-# Fedora: not found
-# => use bundled version by default
-
-option(ENABLE_BUNDLED_ZSTD "Enable building of the bundled zstd" ON)
-if (ENABLE_BUNDLED_ZSTD)
-    include(BuildZSTD)
-    zstd_build()
-    add_dependencies(build_bundled_libs zstd)
-else()
-    set(ZSTD_FIND_REQUIRED ON)
-    find_package(ZSTD)
-endif()
-
-#
-# OpenSSL
-#
-
-find_package(OpenSSL)
-if (OPENSSL_FOUND)
-    message(STATUS "OpenSSL ${OPENSSL_VERSION} found")
-    include_directories(${OPENSSL_INCLUDE_DIR})
-else()
-    message(FATAL_ERROR "Could NOT find OpenSSL development files (libssl-dev/openssl-devel package)")
-endif()
-
 #
 # Third-Party misc
 #
diff --git a/Dockerfile.staticbuild b/Dockerfile.staticbuild
new file mode 100644
index 0000000000..7560d0ef83
--- /dev/null
+++ b/Dockerfile.staticbuild
@@ -0,0 +1,90 @@
+FROM centos:7
+
+RUN yum install -y epel-release
+RUN yum install -y yum install https://centos7.iuscommunity.org/ius-release.rpm
+
+RUN set -x \
+    && yum -y install \
+        libstdc++ \
+        libstdc++-static \
+        readline \
+        openssl \
+        lz4 \
+        binutils \
+        ncurses \
+        libgomp \
+        lua \
+        curl \
+        tar \
+        zip \
+        unzip \
+        libunwind \
+        libcurl \
+    && yum -y install \
+        perl \
+        gcc-c++ \
+        cmake \
+        lz4-devel \
+        binutils-devel \
+        lua-devel \
+        make \
+        git \
+        autoconf \
+        automake \
+        libtool \
+        wget
+
+RUN yum -y install ncurses-static readline-static zlib-static pcre-static glibc-static
+
+RUN set -x && \
+    cd / && \
+    curl -O -L https://www.openssl.org/source/openssl-1.1.0h.tar.gz && \
+    tar -xvf openssl-1.1.0h.tar.gz && \
+    cd openssl-1.1.0h && \
+    ./config && \
+    make && make install
+
+RUN set -x && \
+    cd / && \
+    git clone https://github.com/curl/curl.git && \
+    cd curl && \
+    git checkout curl-7_59_0 && \
+    ./buildconf && \
+    LD_LIBRARY_PATH=/usr/local/lib64 LIBS=" -lssl -lcrypto -ldl" ./configure --enable-static --enable-shared --with-ssl && \
+    make -j && make install
+
+RUN set -x && \
+    cd / && \
+    wget http://download.icu-project.org/files/icu4c/62.1/icu4c-62_1-src.tgz && \
+    tar -xvf icu4c-62_1-src.tgz && \
+    cd icu/source && \
+    ./configure --with-data-packaging=static --enable-static --enable-shared && \
+    make && make install
+
+RUN set -x && \
+    cd / && \
+    LD_LIBRARY_PATH=/usr/local/lib64 curl -O -L http://download.savannah.nongnu.org/releases/libunwind/libunwind-1.3-rc1.tar.gz && \
+    tar -xvf libunwind-1.3-rc1.tar.gz && \
+    cd libunwind-1.3-rc1 && \
+    ./configure --enable-static --enable-shared && \
+    make && make install
+
+COPY . /tarantool
+
+RUN set -x && \
+    cd tarantool && \
+    git submodule init && \
+    git submodule update
+
+RUN set -x \
+    && (cd /tarantool; \
+       cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+             -DENABLE_DIST:BOOL=ON \
+             -DBUILD_STATIC=ON \
+             -DOPENSSL_USE_STATIC_LIBS=ON \
+             .) \
+    && make -C /tarantool -j
+
+RUN cd /tarantool && make install
+
+ENTRYPOINT /bin/bash
diff --git a/cmake/BuildMisc.cmake b/cmake/BuildMisc.cmake
index 20ecb4f630..dc33198e4a 100644
--- a/cmake/BuildMisc.cmake
+++ b/cmake/BuildMisc.cmake
@@ -33,5 +33,15 @@ macro(libmisc_build)
 
     add_library(misc STATIC ${misc_src})
 
+    if (HAVE_OPENMP)
+        target_compile_options(misc PRIVATE "-fopenmp")
+        if(BUILD_STATIC)
+            set(GOMP_LIBRARY libgomp.a)
+        else()
+            set(GOMP_LIBRARY gomp)
+        endif()
+        target_link_libraries(misc ${GOMP_LIBRARY} pthread)
+    endif()
+
     unset(misc_src)
 endmacro(libmisc_build)
diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake
index dc7dc07354..e2e2c6f201 100644
--- a/cmake/FindCURL.cmake
+++ b/cmake/FindCURL.cmake
@@ -16,6 +16,18 @@
 #   CURL_FOUND          - True if curl found.
 #   CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8)
 
+if(BUILD_STATIC)
+    set(CURL_LIB_NAME libcurl.a)
+    set(NGHTTP2_LIB_NAME libnghttp2.a)
+else()
+    set(CURL_LIB_NAME curl)
+    set(NGHTTP2_LIB_NAME nghttp2)
+endif()
+
+# Curl may require nghttp library, search for it and add to dependicies if
+# found
+find_library(NGHTTP2_LIBRARY NAMES ${NGHTTP2_LIB_NAME})
+
 if(DEFINED CURL_ROOT)
     set(CURL_FIND_OPTS NO_CMAKE NO_CMAKE_SYSTEM_PATH)
     set(CURL_FIND_LIBRARY_HINTS "${CURL_ROOT}/lib")
@@ -36,7 +48,7 @@ mark_as_advanced(CURL_INCLUDE_DIR)
 
 # Look for the library (sorted from most current/relevant entry to least).
 find_library(CURL_LIBRARY NAMES
-    curl
+    ${CURL_LIB_NAME}
   # Windows MSVC prebuilts:
     curllib
     libcurl_imp
@@ -67,8 +79,14 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL
 
 if(CURL_FOUND)
   set(CURL_LIBRARIES ${CURL_LIBRARY})
+  if(BUILD_STATIC)
+    # in case of a static build we have to add curl dependencies
+    if(NOT "${NGHTTP2_LIBRARY}" STREQUAL "NGHTTP2_LIBRARY-NOTFOUND")
+      set(CURL_LIBRARIES ${CURL_LIBRARIES} ${NGHTTP2_LIBRARY})
+    endif()
+  endif()
   set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR})
-  set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARIES})
+  set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} pthread dl)
   set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
   check_c_source_runs("
     #include <curl/curl.h>
diff --git a/cmake/FindICU.cmake b/cmake/FindICU.cmake
index ad8ce600de..26f0683f34 100644
--- a/cmake/FindICU.cmake
+++ b/cmake/FindICU.cmake
@@ -21,11 +21,27 @@ find_path(ICU_INCLUDE_DIR
     HINTS ${ICU_FIND_PATH_HINTS}
     ${ICU_FIND_OPTS}
 )
-find_library(ICU_LIBRARY_I18N NAMES icui18n
+
+if(BUILD_STATIC)
+    set(ICU_I18N_LIB_NAME libicui18n.a)
+    set(ICU_UC_LIB_NAME libicuuc.a)
+    set(ICU_DATA_LIB_NAME libicudata.a)
+else()
+    set(ICU_I18N_LIB_NAME icui18n)
+    set(ICU_UC_LIB_NAME icuuc)
+    set(ICU_DATA_LIB_NAME icudata)
+endif()
+
+find_library(ICU_LIBRARY_I18N NAMES ${ICU_I18N_LIB_NAME}
     HINTS ${ICU_FIND_LIBRARY_HINTS}
     ${ICU_FIND_OPTS}
 )
-find_library(ICU_LIBRARY_UC NAMES icuuc
+find_library(ICU_LIBRARY_UC NAMES ${ICU_UC_LIB_NAME}
+    HINTS ${ICU_FIND_LIBRARY_HINTS}
+    ${ICU_FIND_OPTS}
+)
+
+find_library(ICU_LIBRARY_DATA NAMES ${ICU_DATA_LIB_NAME}
     HINTS ${ICU_FIND_LIBRARY_HINTS}
     ${ICU_FIND_OPTS}
 )
@@ -34,7 +50,7 @@ include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(ICU
     REQUIRED_VARS ICU_INCLUDE_DIR ICU_LIBRARY_I18N ICU_LIBRARY_UC)
 set(ICU_INCLUDE_DIRS ${ICU_INCLUDE_DIR})
-set(ICU_LIBRARIES ${ICU_LIBRARY_I18N} ${ICU_LIBRARY_UC})
+set(ICU_LIBRARIES ${ICU_LIBRARY_I18N} ${ICU_LIBRARY_UC} ${ICU_LIBRARY_DATA})
 mark_as_advanced(ICU_INCLUDE_DIR ICU_INCLUDE_DIRS
         ICU_LIBRARY_I18N ICU_LIBRARY_UC ICU_LIBRARIES)
 
diff --git a/cmake/FindLibYAML.cmake b/cmake/FindLibYAML.cmake
index 8abe5f9f0e..ade06e2923 100644
--- a/cmake/FindLibYAML.cmake
+++ b/cmake/FindLibYAML.cmake
@@ -2,8 +2,14 @@ find_path(LIBYAML_INCLUDE_DIR
   NAMES yaml.h
 )
 
+if(BUILD_STATIC)
+    set(YAML_LIB_NAME libyaml.a)
+else()
+    set(YAML_LIB_NAME yaml)
+endif()
+
 find_library(LIBYAML_LIBRARY
-  NAMES yaml
+    NAMES ${YAML_LIB_NAME}
 )
 
 set(LIBYAML_INCLUDE_DIRS "${LIBYAML_INCLUDE_DIR}")
diff --git a/cmake/FindOpenSSL.cmake b/cmake/FindOpenSSL.cmake
new file mode 100644
index 0000000000..8cd22cc8d7
--- /dev/null
+++ b/cmake/FindOpenSSL.cmake
@@ -0,0 +1,291 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindOpenSSL
+# -----------
+#
+# Find the OpenSSL encryption library.
+#
+# Optional COMPONENTS
+# ^^^^^^^^^^^^^^^^^^^
+#
+# This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``.  Both
+# components have associated imported targets, as described below.
+#
+# Imported Targets
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following :prop_tgt:`IMPORTED` targets:
+#
+# ``OpenSSL::SSL``
+#   The OpenSSL ``ssl`` library, if found.
+# ``OpenSSL::Crypto``
+#   The OpenSSL ``crypto`` library, if found.
+#
+# Result Variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module will set the following variables in your project:
+#
+# ``OPENSSL_FOUND``
+#   System has the OpenSSL library. If no components are requested it only
+#   requires the crypto library.
+# ``OPENSSL_INCLUDE_DIR``
+#   The OpenSSL include directory.
+# ``OPENSSL_CRYPTO_LIBRARY``
+#   The OpenSSL crypto library.
+# ``OPENSSL_SSL_LIBRARY``
+#   The OpenSSL SSL library.
+# ``OPENSSL_LIBRARIES``
+#   All OpenSSL libraries.
+# ``OPENSSL_VERSION``
+#   This is set to ``$major.$minor.$revision$patch`` (e.g. ``0.9.8s``).
+#
+# Hints
+# ^^^^^
+#
+# Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation.
+# Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
+# Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib.
+
+if (UNIX)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(_OPENSSL QUIET openssl)
+endif ()
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if(OPENSSL_USE_STATIC_LIBS)
+  set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+  set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
+endif()
+
+set(_OPENSSL_ROOT_HINTS
+  ${OPENSSL_ROOT_DIR}
+  ENV OPENSSL_ROOT_DIR
+  )
+
+set(_OPENSSL_ROOT_HINTS_AND_PATHS
+    HINTS ${_OPENSSL_ROOT_HINTS}
+    PATHS ${_OPENSSL_ROOT_PATHS}
+    )
+
+find_path(OPENSSL_INCLUDE_DIR
+  NAMES
+    openssl/ssl.h
+  ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+  HINTS
+    ${_OPENSSL_INCLUDEDIR}
+  PATH_SUFFIXES
+    include
+)
+
+find_library(OPENSSL_SSL_LIBRARY
+  NAMES
+    ssl
+    ssleay32
+    ssleay32MD
+  NAMES_PER_DIR
+  ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+  HINTS
+    ${_OPENSSL_LIBDIR}
+  PATH_SUFFIXES
+    lib
+)
+
+find_library(OPENSSL_CRYPTO_LIBRARY
+  NAMES
+    crypto
+  NAMES_PER_DIR
+  ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+  HINTS
+    ${_OPENSSL_LIBDIR}
+  PATH_SUFFIXES
+    lib
+)
+
+mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY)
+
+# compat defines
+set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY})
+set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
+
+function(from_hex HEX DEC)
+  string(TOUPPER "${HEX}" HEX)
+  set(_res 0)
+  string(LENGTH "${HEX}" _strlen)
+
+  while (_strlen GREATER 0)
+    math(EXPR _res "${_res} * 16")
+    string(SUBSTRING "${HEX}" 0 1 NIBBLE)
+    string(SUBSTRING "${HEX}" 1 -1 HEX)
+    if (NIBBLE STREQUAL "A")
+      math(EXPR _res "${_res} + 10")
+    elseif (NIBBLE STREQUAL "B")
+      math(EXPR _res "${_res} + 11")
+    elseif (NIBBLE STREQUAL "C")
+      math(EXPR _res "${_res} + 12")
+    elseif (NIBBLE STREQUAL "D")
+      math(EXPR _res "${_res} + 13")
+    elseif (NIBBLE STREQUAL "E")
+      math(EXPR _res "${_res} + 14")
+    elseif (NIBBLE STREQUAL "F")
+      math(EXPR _res "${_res} + 15")
+    else()
+      math(EXPR _res "${_res} + ${NIBBLE}")
+    endif()
+
+    string(LENGTH "${HEX}" _strlen)
+  endwhile()
+
+  set(${DEC} ${_res} PARENT_SCOPE)
+endfunction()
+
+if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
+  file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
+       REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
+
+  if(openssl_version_str)
+    # The version number is encoded as 0xMNNFFPPS: major minor fix patch status
+    # The status gives if this is a developer or prerelease and is ignored here.
+    # Major, minor, and fix directly translate into the version numbers shown in
+    # the string. The patch field translates to the single character suffix that
+    # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so
+    # on.
+
+    string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$"
+           "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}")
+    list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
+    list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR)
+    from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR)
+    list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX)
+    from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX)
+    list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH)
+
+    if (NOT OPENSSL_VERSION_PATCH STREQUAL "00")
+      from_hex("${OPENSSL_VERSION_PATCH}" _tmp)
+      # 96 is the ASCII code of 'a' minus 1
+      math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96")
+      unset(_tmp)
+      # Once anyone knows how OpenSSL would call the patch versions beyond 'z'
+      # this should be updated to handle that, too. This has not happened yet
+      # so it is simply ignored here for now.
+      string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING)
+    endif ()
+
+    set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
+  endif ()
+endif ()
+
+set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} )
+
+foreach(_comp IN LISTS OpenSSL_FIND_COMPONENTS)
+  if(_comp STREQUAL "Crypto")
+    if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND
+        (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
+        EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
+        EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+    )
+      set(OpenSSL_${_comp}_FOUND TRUE)
+    else()
+      set(OpenSSL_${_comp}_FOUND FALSE)
+    endif()
+  elseif(_comp STREQUAL "SSL")
+    if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND
+        (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
+        EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
+        EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+    )
+      set(OpenSSL_${_comp}_FOUND TRUE)
+    else()
+      set(OpenSSL_${_comp}_FOUND FALSE)
+    endif()
+  else()
+    message(WARNING "${_comp} is not a valid OpenSSL component")
+    set(OpenSSL_${_comp}_FOUND FALSE)
+  endif()
+endforeach()
+unset(_comp)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenSSL
+  REQUIRED_VARS
+    OPENSSL_CRYPTO_LIBRARY
+    OPENSSL_INCLUDE_DIR
+  VERSION_VAR
+    OPENSSL_VERSION
+  HANDLE_COMPONENTS
+  FAIL_MESSAGE
+    "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
+)
+
+mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
+
+if(OPENSSL_FOUND)
+  if(NOT TARGET OpenSSL::Crypto AND
+      (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
+        EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
+        EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+      )
+    add_library(OpenSSL::Crypto UNKNOWN IMPORTED)
+    set_target_properties(OpenSSL::Crypto PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+    if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}")
+      set_target_properties(OpenSSL::Crypto PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+        IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}")
+    endif()
+    if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+      set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+        IMPORTED_CONFIGURATIONS RELEASE)
+      set_target_properties(OpenSSL::Crypto PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+        IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}")
+    endif()
+    if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}")
+      set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+        IMPORTED_CONFIGURATIONS DEBUG)
+      set_target_properties(OpenSSL::Crypto PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+        IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}")
+    endif()
+  endif()
+
+  if(NOT TARGET OpenSSL::SSL AND
+      (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
+        EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
+        EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+      )
+    add_library(OpenSSL::SSL UNKNOWN IMPORTED)
+    set_target_properties(OpenSSL::SSL PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+    if(EXISTS "${OPENSSL_SSL_LIBRARY}")
+      set_target_properties(OpenSSL::SSL PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+        IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}")
+    endif()
+    if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+      set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+        IMPORTED_CONFIGURATIONS RELEASE)
+      set_target_properties(OpenSSL::SSL PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+        IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}")
+    endif()
+    if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}")
+      set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+        IMPORTED_CONFIGURATIONS DEBUG)
+      set_target_properties(OpenSSL::SSL PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+        IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}")
+    endif()
+    if(TARGET OpenSSL::Crypto)
+      set_target_properties(OpenSSL::SSL PROPERTIES
+        INTERFACE_LINK_LIBRARIES OpenSSL::Crypto)
+    endif()
+  endif()
+endif()
+
+# Restore the original find library ordering
+if(OPENSSL_USE_STATIC_LIBS)
+  set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake
index 681a6f5de5..c48bdcb3e9 100644
--- a/cmake/FindReadline.cmake
+++ b/cmake/FindReadline.cmake
@@ -6,22 +6,37 @@
 # READLINE_LIBRARIES
 #
 
+if(BUILD_STATIC)
+    find_library(CURSES_CURSES_LIBRARY NAMES libcurses.a)
+    find_library(CURSES_NCURSES_LIBRARY NAMES libncurses.a)
+    find_library(CURSES_FORM_LIBRARY NAMES libform.a)
+    find_library(CURSES_INFO_LIBRARY NAMES libtinfo.a)
+    if (NOT CURSES_INFO_LIBRARY)
+        set(CURSES_INFO_LIBRARY "")
+    endif()
+endif()
 find_package(Curses)
 if(NOT CURSES_FOUND)
     find_package(Termcap)
 endif()
 
+if(BUILD_STATIC)
+    set(READLINE_LIB_NAME libreadline.a)
+else()
+    set(READLINE_LIB_NAME readline)
+endif()
+
 if (DEFINED READLINE_ROOT)
   set(_FIND_OPTS NO_CMAKE NO_CMAKE_SYSTEM_PATH)
   find_library(READLINE_LIBRARY
-    NAMES readline
+    NAMES ${READLINE_LIB_NAME}
     HINTS ${READLINE_ROOT}/lib
     ${_FIND_OPTS})
   find_path(READLINE_INCLUDE_DIR
     NAMES readline/readline.h
     HINTS ${READLINE_ROOT}/include ${_FIND_OPTS})
 else()
-  find_library(READLINE_LIBRARY NAMES readline)
+  find_library(READLINE_LIBRARY NAMES ${READLINE_LIB_NAME})
   find_path(READLINE_INCLUDE_DIR readline/readline.h)
 endif()
 
@@ -32,7 +47,15 @@ set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR})
 set(READLINE_LIBRARIES ${READLINE_LIBRARY})
 
 if(READLINE_FOUND)
+  if(CURSES_FOUND)
+    set(READLINE_LIBRARIES ${READLINE_LIBRARIES} ${CURSES_LIBRARIES} ${CURSES_INFO_LIBRARY})
+    set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
+  elseif(TERMCAP_FOUND)
+    set(READLINE_LIBRARIES ${READLINE_LIBRARIES} ${TERMCAP_LIBRARIES} ${CURSES_INFO_LIBRARY})
+    set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIRS} ${TERMCAP_INCLUDE_DIRS})
+  endif()
   if(EXISTS ${READLINE_INCLUDE_DIR}/readline/rlconf.h)
+      set(CMAKE_REQUIRED_LIBRARIES ${READLINE_LIBRARIES})
       check_library_exists(${READLINE_LIBRARY} rl_catch_sigwinch ""
           HAVE_GNU_READLINE)
       if(HAVE_GNU_READLINE)
@@ -40,13 +63,6 @@ if(READLINE_FOUND)
               "${HAVE_GNU_READLINE}")
       endif()
   endif()
-  if(CURSES_FOUND)
-    set(READLINE_LIBRARIES ${READLINE_LIBRARIES} ${CURSES_LIBRARIES})
-    set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
-  elseif(TERMCAP_FOUND)
-    set(READLINE_LIBRARIES ${READLINE_LIBRARIES} ${TERMCAP_LIBRARIES})
-    set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIRS} ${TERMCAP_INCLUDE_DIRS})
-  endif()
 endif(READLINE_FOUND)
 
 mark_as_advanced(READLINE_INCLUDE_DIRS READLINE_LIBRARIES)
diff --git a/cmake/FindTermcap.cmake b/cmake/FindTermcap.cmake
index efe0c48cfb..fa88fe7b2e 100644
--- a/cmake/FindTermcap.cmake
+++ b/cmake/FindTermcap.cmake
@@ -4,7 +4,13 @@
 # TERMCAP_LIBRARY
 # TERMCAP_INCLUDE_DIR
 
-FIND_LIBRARY(TERMCAP_LIBRARY NAMES termcap)
+if(BUILD_STATIC)
+    set(TERMCAP_STATIC libtermcap.a)
+else()
+    set(TERMCAP_STATIC termcap)
+endif()
+
+FIND_LIBRARY(TERMCAP_LIBRARY NAMES ${TERMCAP_STATIC})
 FIND_PATH(TERMCAP_INCLUDE_DIR NAMES termcap.h)
 
 include(FindPackageHandleStandardArgs)
diff --git a/cmake/FindZSTD.cmake b/cmake/FindZSTD.cmake
index 738de535da..b4421fbe66 100644
--- a/cmake/FindZSTD.cmake
+++ b/cmake/FindZSTD.cmake
@@ -2,8 +2,13 @@ find_path(ZSTD_INCLUDE_DIR
   NAMES zstd.h
 )
 
+if(BUILD_STATIC)
+    set(ZSTD_LIB_NAME libzstd.a)
+else()
+    set(ZSTD_LIB_NAME zstd)
+endif()
 find_library(ZSTD_LIBRARY
-  NAMES zstd
+    NAMES ${ZSTD_LIB_NAME}
 )
 
 set(ZSTD_INCLUDE_DIRS "${ZSTD_INCLUDE_DIR}")
diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake
index 05d33ab482..d990df6b41 100644
--- a/cmake/compiler.cmake
+++ b/cmake/compiler.cmake
@@ -116,7 +116,12 @@ set (CMAKE_CXX_FLAGS_RELWITHDEBINFO
 unset(CC_DEBUG_OPT)
 
 check_include_file(libunwind.h HAVE_LIBUNWIND_H)
-find_library(UNWIND_LIBRARY PATH_SUFFIXES system NAMES unwind)
+if(BUILD_STATIC)
+    set(UNWIND_LIB_NAME libunwind.a)
+else()
+    set(UNWIND_LIB_NAME unwind)
+endif()
+find_library(UNWIND_LIBRARY PATH_SUFFIXES system NAMES ${UNWIND_LIB_NAME})
 
 set(ENABLE_BACKTRACE_DEFAULT OFF)
 if (UNWIND_LIBRARY AND HAVE_LIBUNWIND_H)
@@ -137,20 +142,36 @@ if (ENABLE_BACKTRACE)
     else()
         if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR
             CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
-            find_library(UNWIND_PLATFORM_LIBRARY PATH_SUFFIXES system
-                         NAMES "unwind-${CMAKE_SYSTEM_PROCESSOR}")
+            if(BUILD_STATIC)
+                set(UNWIND_PLATFORM_LIB_NAME "libunwind-${CMAKE_SYSTEM_PROCESSOR}.a")
+            else()
+                set(UNWIND_PLATFORM_LIB_NAME "unwind-${CMAKE_SYSTEM_PROCESSOR}")
+            endif()
         elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "i686")
-            find_library(UNWIND_PLATFORM_LIBRARY PATH_SUFFIXES system
-                         NAMES "unwind-x86")
+            if(BUILD_STATIC)
+                set(UNWIND_PLATFORM_LIB_NAME "libunwind-x86.a")
+            else()
+                set(UNWIND_PLATFORM_LIB_NAME "unwind-x86")
+            endif()
         elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*")
-            find_library(UNWIND_PLATFORM_LIBRARY PATH_SUFFIXES system
-                         NAMES "unwind-arm")
+            if(BUILD_STATIC)
+                set(UNWIND_PLATFORM_LIB_NAME "libunwind-arm.a")
+            else()
+                set(UNWIND_PLATFORM_LIB_NAME "unwind-arm")
+            endif()
         endif()
-        set (UNWIND_LIBRARIES ${UNWIND_LIBRARY} ${UNWIND_PLATFORM_LIBRARY})
+        find_library(UNWIND_PLATFORM_LIBRARY PATH_SUFFIXES system
+            NAMES ${UNWIND_PLATFORM_LIB_NAME})
+        set(UNWIND_LIBRARIES ${UNWIND_PLATFORM_LIBRARY} ${UNWIND_LIBRARY})
     endif()
     find_package_message(UNWIND_LIBRARIES "Found unwind" "${UNWIND_LIBRARIES}")
 endif()
 
+if(BUILD_STATIC)
+    # Static linking for c++ routines
+    add_compile_flags("C;CXX" "-static-libstdc++")
+endif()
+
 #
 # Set flags for all include files: those maintained by us and
 # coming from third parties.
@@ -259,11 +280,6 @@ macro(enable_tnt_compile_flags)
     endif()
 endmacro(enable_tnt_compile_flags)
 
-if (HAVE_OPENMP)
-    add_compile_flags("C;CXX" "-fopenmp")
-endif()
-
-
 if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNUCC)
     set(HAVE_BUILTIN_CTZ 1)
     set(HAVE_BUILTIN_CTZLL 1)
diff --git a/extra/mkexports b/extra/mkexports
index 20b3454d44..145e5b8ce1 100755
--- a/extra/mkexports
+++ b/extra/mkexports
@@ -2,6 +2,7 @@
 # $1 - in  file
 # $2 - out file
 # $3 - os
+# $4 - export templates
 if [ "x$3x" = xDarwinx ]; then
     # _func1
     # _func2
@@ -11,5 +12,16 @@ else
     #   func1;
     #   func2;
     # };
-    ( echo "{" && sed -e '/^\s*$/d;s/$/;/;' $1 && echo "};" ) > $2
+    echo "$4"
+    ( echo "{" && {
+      # combine static defined list of functions
+      cat $1 ;
+      # with list of exported functions of bundled libraries
+      for so in $4 ; do {
+        # exported names from shared object
+        nm -D $so ||
+        # or follow patch from shared object script
+        nm -D `cat $so | grep GROUP | awk '{print $3}'` ;
+      } | awk '{print $3}' ; done ;
+    } | sed '/^\s*$/d;s/$/;/;' && echo "};" ) > $2
 fi
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3b55ecd41f..ebda09832c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -67,6 +67,8 @@ add_custom_target(ragel
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
     COMMAND ragel -G2 src/uri.rl -o src/uri.c)
 
+set (generic_libraries pthread dl)
+
 set (core_sources
      diag.c
      say.c
@@ -108,18 +110,18 @@ endif ()
 
 add_library(core STATIC ${core_sources})
 target_link_libraries(core
-    salad small pthread
+    salad small
     ${LIBEV_LIBRARIES}
     ${LIBEIO_LIBRARIES}
     ${LIBCORO_LIBRARIES}
     ${MSGPUCK_LIBRARIES}
-)
+    ${generic_libraries})
 
 add_library(stat STATIC rmean.c latency.c histogram.c)
 target_link_libraries(stat core)
 
 if (ENABLE_BACKTRACE AND NOT TARGET_OS_DARWIN)
-	target_link_libraries(core gcc_s ${UNWIND_LIBRARIES})
+    target_link_libraries(core gcc_s ${UNWIND_LIBRARIES})
 endif()
 
 if (CC_HAS_WNO_IMPLICIT_FALLTHROUGH)
@@ -224,9 +226,9 @@ set (common_libraries
     ${reexport_libraries}
     ${LIBYAML_LIBRARIES}
     ${READLINE_LIBRARIES}
-    ${OPENSSL_LIBRARIES}
     ${CURL_LIBRARIES}
     ${ICONV_LIBRARIES}
+    ${OPENSSL_LIBRARIES}
 )
 
 if (TARGET_OS_LINUX OR TARGET_OS_DEBIAN_FREEBSD)
@@ -252,6 +254,31 @@ add_subdirectory(box)
 set(TARANTOOL_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE)
 set(TARANTOOL_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE)
 
+set(EXPORT_LIST)
+if(BUILD_STATIC)
+    # for each static library we should find a corresponding shared library to
+    # parse and reexport library api functions
+    foreach(libstatic
+            ${READLINE_LIBRARIES}
+            ${CURL_LIBRARIES}
+            ${OPENSSL_LIBRARIES}
+            ${ICU_LIBRARIES})
+        if (${libstatic} MATCHES "lib[^/]+.a")
+            string(REGEX MATCH "lib[^/]+.a" libname ${libstatic})
+            string(REGEX REPLACE "\\.a$" "" libname ${libname})
+            string(REGEX REPLACE "^lib" "" libname ${libname})
+            find_library(SYMBOLS_LIB NAMES ${libname})
+            # add found library to export list
+            list(APPEND EXPORT_LIST ${SYMBOLS_LIB})
+            # set variable to allow rescan (CMake depended)
+            set(SYMBOLS_LIB "SYMBOLS_LIB-NOTFOUND")
+        else()
+            message(WARNING "${libstatic} should be a static")
+        endif()
+    endforeach(libstatic)
+    string(REPLACE ";" " " EXPORT_LIST "${EXPORT_LIST}")
+endif()
+
 # Exports syntax is toolchain-dependent, preprocessing is necessary
 set(exports_file ${CMAKE_BINARY_DIR}/extra/exports.${CMAKE_SYSTEM_NAME})
 add_custom_target(preprocess_exports
@@ -261,12 +288,14 @@ add_custom_command(
     DEPENDS ${CMAKE_SOURCE_DIR}/extra/exports
     COMMAND ${CMAKE_SOURCE_DIR}/extra/mkexports
             ${CMAKE_SOURCE_DIR}/extra/exports
-            ${exports_file} ${CMAKE_SYSTEM_NAME})
+            ${exports_file} ${CMAKE_SYSTEM_NAME}
+            ${EXPORT_LIST}
+)
 
 add_executable(
-	tarantool main.cc
-	${LIBUTIL_FREEBSD_SRC}/flopen.c
-	${LIBUTIL_FREEBSD_SRC}/pidfile.c)
+    tarantool main.cc
+    ${LIBUTIL_FREEBSD_SRC}/flopen.c
+    ${LIBUTIL_FREEBSD_SRC}/pidfile.c)
 
 add_dependencies(tarantool build_bundled_libs preprocess_exports)
 
@@ -294,7 +323,8 @@ else ()
     target_link_libraries(tarantool
                           -Wl,--whole-archive box ${reexport_libraries}
                           salad -Wl,--no-whole-archive
-                          ${common_libraries})
+                          ${common_libraries}
+                          ${generic_libraries})
     set_target_properties(tarantool PROPERTIES
         LINK_FLAGS "-Wl,--dynamic-list,${exports_file}")
     # get rid of -rdynamic
diff --git a/third_party/crc32.c b/third_party/crc32.c
index a271d07ece..16b8c40400 100644
--- a/third_party/crc32.c
+++ b/third_party/crc32.c
@@ -45,7 +45,7 @@
 #include <unistd.h>
 #include <stdint.h>
 
-uint32_t crc32_table[] = {
+static uint32_t crc32_table[] = {
 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
@@ -92,7 +92,7 @@ uint32_t crc32_table[] = {
 };
 
 uint32_t
-crc32(const void *buf, size_t size)
+tnt_crc32(const void *buf, size_t size)
 {
 	const uint8_t *p = buf;
 	uint32_t crc;
@@ -735,7 +735,7 @@ multitable_crc32c(uint32_t crc32c,
 }
 
 uint32_t
-crc32c(uint32_t crc32c,
+tnt_crc32c(uint32_t crc32c,
     const char *buffer,
     unsigned int length)
 {
diff --git a/third_party/crc32.h b/third_party/crc32.h
index 55c7072f33..8dc61d05da 100644
--- a/third_party/crc32.h
+++ b/third_party/crc32.h
@@ -3,7 +3,9 @@
 
 #include <stdint.h>
 
-uint32_t crc32(const void *buf, size_t size);
-uint32_t crc32c(uint32_t crc32c, const char *buffer, unsigned int length);
+#define crc32 tnt_crc32
+uint32_t tnt_crc32(const void *buf, size_t size);
+#define crc32c tnt_crc32c
+uint32_t tnt_crc32c(uint32_t crc32c, const char *buffer, unsigned int length);
 
 #endif
-- 
GitLab