'Building a CMake project with OpenSSL as dependency

I would like to build my project with OpenSSL from sources. I am using a modern CMake with FetchContent feature. So far, I have no trouble using FetchContent with CMake external projects, but OpenSSL does not use CMake.

My try so far:

FetchContent_Declare(
  openssl
  GIT_REPOSITORY https://github.com/openssl/openssl.git
  GIT_TAG        origin/master
  CONFIGURE_COMMAND "./Configure"
  BUILD_COMMAND "make"
  TEST_COMMAND "make test"
)
...
FetchContent_MakeAvailable(openssl)

but this does not make anything in the main project and of course compilation fails for executables requiring lib openssl.

Could you please help me to figure out if it's possible to automatically build the openssl lib for my program ? I would like to avoid usage of existing non official wrappers of openssl with cmake.

Thanks a lot in advance

Stephane



Solution 1:[1]

I think that you are mixing FetchContent and ExternalProject.

FetchContent will download (and possibly patch) your subproject, typically to use it like a "git submodule", and ExternalProject will not only download it, but also build it. From the FetchContent docs:

In addition to the above explicit options, any other unrecognized options are passed through unmodified to ExternalProject_Add() to perform the download, patch and update steps. The following options are explicitly prohibited (they are disabled by the FetchContent_Populate() command):

  • CONFIGURE_COMMAND
  • BUILD_COMMAND
  • INSTALL_COMMAND
  • TEST_COMMAND

Now, there are two things with ExternalProject_Add():

  1. It will run at build time. I like to use it as a cross-platform script to help users build the dependencies from source, but they have to run that script as a prerequisite, and then build my project by referencing to the result of this one.
  2. It will build and install the project locally, so your main project that depends on it will have to find it, e.g. by pointing CMAKE_PREFIX_PATH to the install path of the dependency.

Also, you could make it such that the configure step of your main project runs ExternalProject_add in a separate process, but I think that it quickly makes it more complex and ends up not helping users so much.

All that to say that there is no silver bullet when it comes to dependencies, and for a dependency like OpenSSL, the simplest may be to give instructions explaining how to apt install openssl or brew install openssl, and then use find_package(OpenSSL REQUIRED) in your CMakeLists.txt!

Solution 2:[2]

This one is tricky, because OpenSSL does not use CMake, it has a custom build script, and has a complex behavior with glibc. As @JonasVautherin said, you cannot use FetchContent_Declare, you must use ExternalProject_Add:

set(OPENSSL_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/openssl-src) # default path by CMake
set(OPENSSL_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/openssl)
set(OPENSSL_INCLUDE_DIR ${OPENSSL_INSTALL_DIR}/include)
set(OPENSSL_CONFIGURE_COMMAND ${OPENSSL_SOURCE_DIR}/config)
ExternalProject_Add(
  OpenSSL
  SOURCE_DIR ${OPENSSL_SOURCE_DIR}
  GIT_REPOSITORY https://github.com/openssl/openssl.git
  GIT_TAG OpenSSL_1_1_1n
  USES_TERMINAL_DOWNLOAD TRUE
  CONFIGURE_COMMAND
    ${OPENSSL_CONFIGURE_COMMAND}
    --prefix=${OPENSSL_INSTALL_DIR}
    --openssldir=${OPENSSL_INSTALL_DIR}
  BUILD_COMMAND make
  TEST_COMMAND ""
  INSTALL_COMMAND make install
  INSTALL_DIR ${OPENSSL_INSTALL_DIR}
)

After doing that, you cannot include or link it with your other targets yet. To do that, you still need to declare the library, as if it was found using find_package, i.e. as if FindOpenSSL.cmake was used:

# We cannot use find_library because ExternalProject_Add() is performed at build time.
# And to please the property INTERFACE_INCLUDE_DIRECTORIES,
# we make the include directory in advance.
file(MAKE_DIRECTORY ${OPENSSL_INCLUDE_DIR})

add_library(OpenSSL::SSL STATIC IMPORTED GLOBAL)
set_property(TARGET OpenSSL::SSL PROPERTY IMPORTED_LOCATION ${OPENSSL_INSTALL_DIR}/lib/libssl.${OPENSSL_LIBRARY_SUFFIX})
set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR})
add_dependencies(OpenSSL::SSL OpenSSL)

add_library(OpenSSL::Crypto STATIC IMPORTED GLOBAL)
set_property(TARGET OpenSSL::Crypto PROPERTY IMPORTED_LOCATION ${OPENSSL_INSTALL_DIR}/lib/libcrypto.${OPENSSL_LIBRARY_SUFFIX})
set_property(TARGET OpenSSL::Crypto PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR})
add_dependencies(OpenSSL::Crypto OpenSSL)

Now you can include the OpenSSL and link with it normally.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JonasVautherin
Solution 2 Victor Paléologue