четверг, 27 марта 2025 г.

[prog.c++.vcpkg] Внезапные приключения с подключением OpenSSL к проекту посредством vcpkg

Есть проект, который собирается под Windows и под Linux. Для управления зависимостями используется vcpkg (вместе с манифестами, т.е. с файлами vcpkg-configuration.json и vcpkg.json, хотя манифесты тут вряд ли виноваты).

В зависимостях есть OpenSSL. Подключение OpenSSL в CMakeLists.txt проекта выглядит стандартным образом:

find_package(OpenSSL CONFIG REQUIRED)
...
target_link_libraries(some_executable_file OpenSSL::SSL OpenSSL::Crypto)

Так вот под Windows все это работает как часы, тогда как под Linux-ом случился нежданчик: внезапно™ выяснилось, что нет таких CMake-овских таргетов, как OpenSSL::SSL и OpenSSL::Crypto.

Вот нет и все, хотя find_package успешно отрабатывает.

Блуждания по потрохам кучи CMake-овских файлов, установленных vcpkg, привело вот к такому фрагменту в файле OpenSSLConfig.cmake, который лежит в vcpkg_installed/x64-linux/share/openssl (извиняюсь за его объем, но здесь все самое важное):

if(NOT Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG)
  # Prevent loop
  set(Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG "prevent-loop")
  # Chainload vcpkg's module-based multi-config target setup
  find_package(OpenSSL MODULE)
  set(Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG 0)
else()
  # Use official single-config target setup
# Set up the imported targets
if(_ossl_use_static_libs)

  add_library(OpenSSL::Crypto STATIC IMPORTED)
  add_library(OpenSSL::SSL STATIC IMPORTED)

  set(OPENSSL_LIBCRYPTO_STATIC "${OPENSSL_LIBRARY_DIR}/libcrypto.a")
  set(OPENSSL_LIBCRYPTO_DEPENDENCIES -ldl -pthread)
  set_target_properties(OpenSSL::Crypto PROPERTIES
    IMPORTED_LINK_INTERFACE_LANGUAGES "C"
    IMPORTED_LOCATION ${OPENSSL_LIBCRYPTO_STATIC})
  set_property(TARGET OpenSSL::Crypto
    PROPERTY INTERFACE_LINK_LIBRARIES ${OPENSSL_LIBCRYPTO_DEPENDENCIES})

  set(OPENSSL_LIBSSL_STATIC "${OPENSSL_LIBRARY_DIR}/libssl.a")
  set(OPENSSL_LIBSSL_DEPENDENCIES OpenSSL::Crypto)
  set_target_properties(OpenSSL::SSL PROPERTIES
    IMPORTED_LINK_INTERFACE_LANGUAGES "C"
    IMPORTED_LOCATION ${OPENSSL_LIBSSL_STATIC})
  set_property(TARGET OpenSSL::SSL
    PROPERTY INTERFACE_LINK_LIBRARIES ${OPENSSL_LIBSSL_DEPENDENCIES})

  # Directories and names compatible with CMake's FindOpenSSL.cmake
  set(OPENSSL_CRYPTO_LIBRARY ${OPENSSL_LIBCRYPTO_STATIC})
  set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_LIBCRYPTO_DEPENDENCIES})
  set(OPENSSL_SSL_LIBRARY ${OPENSSL_LIBSSL_STATIC})
  set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_LIBSSL_DEPENDENCIES})
  set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_LIBSSL_DEPENDENCIES} ${OPENSSL_LIBCRYPTO_DEPENDENCIES})

else()

  # Shared libraries are UNSUPPORTED in this configuration

endif()

Итак, суть в том, что если переменная Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG не установлена (а она не установлена), то делается еще один find_package(OpenSSL), после которого никаких таргетов OpenSSL::SSL/Crypto не определяется. Но вот если Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG установлена, то тогда эти таргеты для случая статической библиотеки должным образом определяются.

Поэтому-то таргетов OpenSSL::SSL/Crypto нет, и попытка их использования ведет к ошибкам в проектном CMakeLists.txt.

Почему таргеты OpenSSL::SSL/Crypto есть при работе с OpenSSL в Windows -- я ХЗ.

Тут, вероятно, какая-то магия vcpkg, поскольку проблемные строчки добавляются в специальном patch-файле в порте OpenSSL для vcpkg (цинк).

Причем не только мы наступили на эти грабли. Есть до сих пор открытый issue на github-е с описанием сути проблемы. К сожалению, я его нашел уже после того, как сам дорылся до причины.

В качестве обходного маневра в проектный CMakeLists.txt для Linux-а была добавлена строчка:

set(Z_VCPKG_OPENSSL_USE_SINGLE_CONFIG ON)

перед вызовом find_package(OpenSSL).

Комментариев нет: