cdk/cmake/DepFindSSL.cmake (339 lines of code) (raw):

# Copyright (c) 2009, 2024, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, as # published by the Free Software Foundation. # # This program is designed to work with certain software (including # but not limited to OpenSSL) that is licensed under separate terms, as # designated in a particular file or component or in included license # documentation. The authors of MySQL hereby grant you an additional # permission to link the program and your derivative works with the # separately licensed software that they have either included with # the program or referenced in the documentation. # # Without limiting anything contained in the foregoing, this file, # which is part of Connector/C++, is also subject to the # Universal FOSS Exception, version 1.0, a copy of which can be found at # https://oss.oracle.com/licenses/universal-foss-exception. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License, version 2.0, for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ############################################################################## # # Targets: # OpenSSL::SSL - main library (includes crypto library) # OpenSSL::Crypto - crypto library # # Output variables: # OPENSSL_INCLUDE_DIR # OPENSSL_LIB_DIR # OPENSSL_VERSION # OPENSSL_VERSION_MAJOR # OPENSSL_LIBRARIES # if(TARGET OpenSSL::SSL) return() endif() include(config_header) # add_config() include(CheckSymbolExists) add_config_option(WITH_SSL STRING DEFAULT system "Either 'system' to use system-wide OpenSSL library," " or custom OpenSSL location." ) function(main) message(STATUS "Looking for SSL library.") if(NOT WITH_SSL MATCHES "^(system|yes)$") if(EXISTS ${WITH_SSL}/include/openssl/ssl.h) set(OPENSSL_ROOT_DIR "${WITH_SSL}") endif() if(NOT DEFINED OpenSSL_DIR) set(OpenSSL_DIR "${WITH_SSL}") endif() endif() find_openssl() if(NOT TARGET OpenSSL::SSL) message(SEND_ERROR "Cannot find appropriate system libraries for SSL. " "Make sure you've specified a supported SSL version. " "Consult the documentation for WITH_SSL alternatives" ) return() endif() set(OPENSSL_LIB_DIR "${OPENSSL_LIB_DIR}" CACHE INTERNAL "") message(STATUS "Using OpenSSL version: ${OPENSSL_VERSION}") set(OPENSSL_VERSION_GLOBAL ${OPENSSL_VERSION} CACHE INTERNAL "OpenSSL Version") #message(STATUS "OPENSSL_INCLUDE_DIR: ${OPENSSL_INCLUDE_DIR}") #message(STATUS "OPENSSL_LIBRARIES: ${OPENSSL_LIBRARIES}") set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") CHECK_SYMBOL_EXISTS(SHA512_DIGEST_LENGTH "openssl/sha.h" HAVE_SHA512_DIGEST_LENGTH) if(NOT HAVE_SHA512_DIGEST_LENGTH) message(SEND_ERROR "Could not find SHA512_DIGEST_LENGTH symbol in sha.h header of OpenSSL library") endif() check_x509_functions() if(BUNDLE_DEPENDENCIES) bundle_ssl_libs() endif() endfunction(main) function(check_x509_functions) SET(CMAKE_REQUIRED_LIBRARIES OpenSSL::SSL) CHECK_SYMBOL_EXISTS(X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS "openssl/x509v3.h" HAVE_X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS) CHECK_SYMBOL_EXISTS(SSL_get0_param "openssl/ssl.h" HAVE_SSL_GET0_PARAM) CHECK_SYMBOL_EXISTS(X509_VERIFY_PARAM_set_hostflags "openssl/x509v3.h" HAVE_X509_VERIFY_PARAM_SET_HOSTFLAGS) CHECK_SYMBOL_EXISTS(X509_VERIFY_PARAM_set1_host "openssl/x509v3.h" HAVE_X509_VERIFY_PARAM_SET1_HOST) IF(HAVE_SSL_GET0_PARAM AND HAVE_X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS AND HAVE_X509_VERIFY_PARAM_SET_HOSTFLAGS AND HAVE_X509_VERIFY_PARAM_SET1_HOST) SET(HAVE_REQUIRED_X509_FUNCTIONS ON CACHE INTERNAL "Indicates the presence of required X509 functionality") message("-- found required X509 extensions") ADD_CONFIG(HAVE_REQUIRED_X509_FUNCTIONS) ENDIF() endfunction(check_x509_functions) # # Find libraries, create import targets and set output variables. # function(find_openssl) # Note: FindOpenSSL seems to be broken on earlier versions of cmake. if(CMAKE_VERSION VERSION_GREATER "3.8" OR USE_CMAKE_FIND_OPENSSL) # message(STATUS "Using cmake OpenSSL module") find_package(OpenSSL) set(OPENSSL_LIBRARY "${OPENSSL_SSL_LIBRARY}") else() # Use our simplified replacement for broken FindOpenSSL find_openssl_fix() endif() # Set OPENSSL_LIB_DIR from the library path if it was not yet defined. if(NOT OPENSSL_LIB_DIR) # OPENSSL_LIBRARY can be a list containing optimized and debug variants: # # optimized;/path/to/optimized/lib;debug;/path/to/debug/lib # # In that case we extract path from the optimized library. list(FIND OPENSSL_LIBRARY "optimized" pos) if(pos LESS 0) # If "optimized" entry was not found we assume that OPENSSL_LIBRARY is a single path set(lib_path "${OPENSSL_LIBRARY}") else() # Otherwise read the path after the "optimized" entry math(EXPR pos "${pos}+1") list(GET OPENSSL_LIBRARY ${pos} lib_path) endif() get_filename_component(OPENSSL_LIB_DIR "${lib_path}" PATH CACHE) endif() # Set output variables set(OPENSSL_FOUND "${OPENSSL_FOUND}" PARENT_SCOPE) set(OPENSSL_VERSION "${OPENSSL_VERSION}" PARENT_SCOPE) set(OPENSSL_VERSION_MAJOR "${OPENSSL_VERSION_MAJOR}" PARENT_SCOPE) set(OPENSSL_INCLUDE_DIR "${OPENSSL_INCLUDE_DIR}" PARENT_SCOPE) set(OPENSSL_LIB_DIR "${OPENSSL_LIB_DIR}" PARENT_SCOPE) set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES}" PARENT_SCOPE) endfunction(find_openssl) macro(find_openssl_fix) set(add_applink true) unset(hints) if(OPENSSL_ROOT_DIR) set(hints HINTS ${OPENSSL_ROOT_DIR} NO_DEFAULT_PATH) endif() find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h PATH_SUFFIXES include ${hints} ) if(NOT OPENSSL_INCLUDE_DIR) return() endif() message("-- found OpenSSL headers at: ${OPENSSL_INCLUDE_DIR}") # Verify version number. Version information looks like: # #define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1a 20 Nov 2018" FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSL_VERSION_NUMBER REGEX "#[ ]*define[\t ]+OPENSSL_VERSION_TEXT" ) #message("== OPENSSL_VERSION_NUMBER: ${OPENSSL_VERSION_NUMBER}") # define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1d-freebsd 10 Sep 2019" STRING(REGEX REPLACE "^.*OPENSSL_VERSION_TEXT[\t ]+\"OpenSSL[\t ]([0-9]+)\\.([0-9]+)\\.([0-9]+)([a-z]|)[\t \\-].*$" "\\1;\\2;\\3;\\4" version_list "${OPENSSL_VERSION_NUMBER}" ) #message("-- OPENSSL_VERSION: ${version_list}") list(GET version_list 0 OPENSSL_VERSION_MAJOR) math(EXPR OPENSSL_VERSION_MAJOR ${OPENSSL_VERSION_MAJOR}) list(GET version_list 1 OPENSSL_VERSION_MINOR) math(EXPR OPENSSL_VERSION_MINOR ${OPENSSL_VERSION_MINOR}) list(GET version_list 2 OPENSSL_VERSION_FIX) math(EXPR OPENSSL_VERSION_FIX ${OPENSSL_VERSION_FIX}) list(GET version_list 3 OPENSSL_VERSION_PATCH) set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH}" ) find_library(OPENSSL_LIBRARY NAMES ssl ssleay32 ssleay32MD libssl PATH_SUFFIXES lib ${hints} ) find_library(CRYPTO_LIBRARY NAMES crypto libeay32 libeay32MD libcrypto PATH_SUFFIXES lib ${hints} ) if(NOT OPENSSL_LIBRARY OR NOT CRYPTO_LIBRARY) return() endif() message("-- OpenSSL library: ${OPENSSL_LIBRARY}") message("-- OpenSSL crypto library: ${CRYPTO_LIBRARY}") # Note: apparently UNKNOWN library type does not work # https://stackoverflow.com/questions/39346679/cmake-imported-unknown-global-target add_library(OpenSSL::SSL SHARED IMPORTED GLOBAL) set_target_properties(OpenSSL::SSL PROPERTIES IMPORTED_LOCATION "${OPENSSL_LIBRARY}" IMPORTED_IMPLIB "${OPENSSL_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}" ) add_library(OpenSSL::Crypto SHARED IMPORTED GLOBAL) set_target_properties(OpenSSL::Crypto PROPERTIES IMPORTED_LOCATION "${CRYPTO_LIBRARY}" IMPORTED_IMPLIB "${CRYPTO_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}" ) set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_LINK_LIBRARIES OpenSSL::Crypto ) #TODO: Is it needed also when OpenSSL is found via cmake module? if(WIN32 AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/applink.c") #message("-- Handling applink.c") add_library(openssl-applink STATIC "${OPENSSL_INCLUDE_DIR}/openssl/applink.c") target_link_libraries(OpenSSL::SSL INTERFACE openssl-applink) set_target_properties(openssl-applink PROPERTIES FOLDER "Misc") # Remove warnings from openssl applink.c if(CXX_FRONTEND_MSVC) target_compile_options(openssl-applink PRIVATE /wd4152 /wd4996) endif() endif() set(OPENSSL_FOUND true) endmacro(find_openssl_fix) # # Add instructions for installing OpenSSL libraries together # with the connector. # function(bundle_ssl_libs) if(NOT OPENSSL_LIB_DIR) return() endif() if(NOT WIN32) # Note: On U**ix systems the files we link to are symlinks to # the actual shared libs, so we read these symlinks here and # bundle their targets as well. foreach(lib ${OPENSSL_LIBRARIES}) if(NOT EXISTS "${lib}") continue() endif() get_filename_component(path "${lib}" REALPATH) list(APPEND glob1 "${lib}" "${path}") endforeach() else() # Very simplistic approach - assuming that OPENSSL_LIB_DIR points # at OpenSSL installation grab all shared libraries that can be # found there. file(GLOB glob1 "${OPENSSL_LIB_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}*" ) file(GLOB glob2 "${OPENSSL_LIB_DIR}/../bin/*${CMAKE_SHARED_LIBRARY_SUFFIX}*" ) endif() foreach(lib ${glob1} ${glob2}) # Copy SSL libs to binary dir as below we will modify them (change the path to # libcrypto dependency). file(COPY ${lib} DESTINATION ${CMAKE_BINARY_DIR}/SSL) message("-- bundling OpenSSL library: ${lib}") get_filename_component(lib_filename ${lib} NAME) if(WIN32 OR APPLE) install(FILES ${CMAKE_BINARY_DIR}/SSL/${lib_filename} DESTINATION "${INSTALL_LIB_DIR}" COMPONENT OpenSSLDll ) else() install(FILES ${CMAKE_BINARY_DIR}/SSL/${lib_filename} DESTINATION "${INSTALL_LIB_DIR}/private" COMPONENT OpenSSLDll ) endif() endforeach() # For Windows we also need static import libraries if(WIN32) file(GLOB glob "${OPENSSL_LIB_DIR}/*.lib" ) foreach(lib ${glob}) message("-- bundling OpenSSL library: ${lib}") install(FILES ${lib} DESTINATION "${INSTALL_LIB_DIR_STATIC}" COMPONENT OpenSSLDev ) endforeach() endif() if(APPLE) # Edit the main OpenSSL library to not include full path to the crypto # dependency. Instead use path relative to the location of the main library. # Dependency information is changed from something # like this: # # $ otool -L SSL/libssl.dylib # SSL/libssl.dylib: # /opt/homebrew/Cellar/openssl@3/3.2.1/lib/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0) # # to something like this: # # $ otool -L SSL/libssl.dylib # SSL/libssl.dylib: # @loader_path/libcrypto.3.dylib (compatibility version 3.0.0, current version 3.0.0) # Read original dependencies using otool (only for the main library) set(lib_ssl ${OPENSSL_LIBRARIES}) list(FILTER lib_ssl INCLUDE REGEX "libssl\.dylib$") execute_process( COMMAND otool -L ${lib_ssl} OUTPUT_VARIABLE OTOOL_OPENSSL_DEPS ) # Parse output of otool to extract full paths and library names # with versions. string(REPLACE "\n" ";" DEPS_LIST ${OTOOL_OPENSSL_DEPS}) foreach(line ${DEPS_LIST}) foreach(lib ssl crypto) if(line MATCHES "(/.*lib${lib}.*${CMAKE_SHARED_LIBRARY_SUFFIX}).*compatibility version") if(CMAKE_MATCH_1) set(lib_${lib}_path "${CMAKE_MATCH_1}") get_filename_component(lib_${lib}_name "${lib_${lib}_path}" NAME) endif() endif() endforeach(lib) endforeach(line) if(NOT lib_ssl_path OR NOT lib_crypto_path) message("Warning: Failed to edit OpenSSL library dependencies") return() endif() # Use install_name_tool to replace full path with @loader_path: # $ install_name_tool -change old new file execute_process( COMMAND chmod +w ${lib_ssl_name} ${lib_crypto_name} COMMAND install_name_tool -change "${lib_crypto_path}" "@loader_path/${lib_crypto_name}" "${lib_ssl_name}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/SSL" ) endif(APPLE) endfunction(bundle_ssl_libs) main() return() ##########################################################################