From 3e841630ece59c04e26058a761302f38370fd0cc Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 25 Jan 2026 13:04:58 +0100 Subject: [PATCH] cmake: fix logic for openssl/zlib binutils ld workaround While working #16973, the binutils ld lib order workaround logic regressed so that it modified the wrong target, writing into the system `ZLIB::ZLIB` and `OpenSSL::Crypto` ones a `INTERFACE_LINK_LIBRARIES` property, instead of creating CURL-namespaced targets. Oddly enough, this also fixed the binutils ld lib ordering issue. It seems this property makes CMake insert each referenced library in two more positions (not at the very end though), which allows ld to resolve all symbols in the cases tested in CI. Fix by creating the indented namespaced targets, and also creating these in `curl-config.cmake` to be available when consuming libcurl. Note that the logic continues doing `get_target_property()` on the two system targets above. If these targets are defined manually and miss the `LOCATION` propery, or are defined as aliases, this command may fail. curl expects these targets be created by CMake's `FindZLIB` and `FindOpenSSL` built-in Find modules (or ones compatible). Ref: #20419 The binutils ld issue is reproduced by these CI jobs: - Linux gcc glibc (amd64, arm64) - Windows gcc zlib-classic (x64) Currently using this curl-for-win revision: https://github.com/curl/curl-for-win/commit/7d12669dafc5aadb525415abde2152a44e10f07d Examples: https://github.com/curl/curl/actions/runs/21332437230/job/61399234023?pr=20427 https://github.com/curl/curl/actions/runs/21332437230/job/61399234033?pr=20427 Comparison of lib orders, as passed by CMake to the linker: without workaround (possibly breaking binutils `ld`): ```diff -framework [...] libssl.dylib libcrypto.dylib libz.tbd -lssh2 -lidn2 libldap.tbd liblber.tbd -lbrotlidec -lbrotlicommon -lzstd -lnghttp2 -lpsl -lrtmp -lz -lssl -lcrypto ``` before this patch: ```diff -framework [...] libssl.dylib libcrypto.dylib libz.tbd +libcrypto.dylib <== inserted via `INTERFACE_LINK_LIBRARIES` +libz.tbd <== inserted via `INTERFACE_LINK_LIBRARIES` -lssh2 -lidn2 libldap.tbd liblber.tbd +libcrypto.dylib <== inserted via `INTERFACE_LINK_LIBRARIES` +ibz.tbd <== inserted via `INTERFACE_LINK_LIBRARIES` -lbrotlidec -lbrotlicommon -lzstd -lnghttp2 -lpsl -lrtmp -lz -lssl -lcrypto ``` after this patch: ```diff -framework [...] libssl.dylib libcrypto.dylib libz.tbd -lssh2 -lidn2 libldap.tbd liblber.tbd -lbrotlidec -lbrotlicommon -lzstd -lnghttp2 -lpsl -lrtmp -lz -lssl -lcrypto +libcrypto.dylib <== inserted via `CURL::OpenSSL_Crypto` +libz.tbd <== inserted via `CURL::ZLIB` ``` Bug: https://github.com/curl/curl/pull/20382#discussion_r2716660108 Reverts: https://github.com/curl/curl/commit/615c43eae8f926418c8205b6fe4ff693e8fc6b7d Follow-up to 16f073ef49f94412000218c9f6ad04e3fd7e4d01 #16973 Closes #20427 --- CMake/curl-config.in.cmake | 10 ++++++++++ CMakeLists.txt | 23 ++++++++++------------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/CMake/curl-config.in.cmake b/CMake/curl-config.in.cmake index ef2a64cc91..cd0d9bbe83 100644 --- a/CMake/curl-config.in.cmake +++ b/CMake/curl-config.in.cmake @@ -39,9 +39,19 @@ if("@USE_OPENSSL@") else() find_dependency(OpenSSL) endif() + if(TARGET OpenSSL::Crypto AND NOT TARGET CURL::OpenSSL_Crypto) + add_library(CURL::OpenSSL_Crypto INTERFACE IMPORTED) + get_target_property(_curl_libname OpenSSL::Crypto LOCATION) + set_target_properties(CURL::OpenSSL_Crypto PROPERTIES INTERFACE_LINK_LIBRARIES "${_curl_libname}") + endif() endif() if("@HAVE_LIBZ@") find_dependency(ZLIB "@ZLIB_VERSION_MAJOR@") + if(TARGET ZLIB::ZLIB AND NOT TARGET CURL::ZLIB) + add_library(CURL::ZLIB INTERFACE IMPORTED) + get_target_property(_curl_libname ZLIB::ZLIB LOCATION) + set_target_properties(CURL::ZLIB PROPERTIES INTERFACE_LINK_LIBRARIES "${_curl_libname}") + endif() endif() set(_curl_cmake_module_path_save ${CMAKE_MODULE_PATH}) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2b93389ee..8827deac2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1813,21 +1813,18 @@ endif() # before dependencies detected via curl's custom Find modules, and breaks # linkers sensitive to lib order. There must be a better solution to this. if(CMAKE_C_COMPILER_ID STREQUAL "GNU") - set(_libs "") - if(USE_OPENSSL) - list(APPEND _libs OpenSSL::Crypto) + if(USE_OPENSSL AND TARGET OpenSSL::Crypto) + add_library(CURL::OpenSSL_Crypto INTERFACE IMPORTED) + get_target_property(_curl_libname OpenSSL::Crypto LOCATION) + set_target_properties(CURL::OpenSSL_Crypto PROPERTIES INTERFACE_LINK_LIBRARIES "${_curl_libname}") + list(APPEND CURL_LIBS CURL::OpenSSL_Crypto) endif() - if(HAVE_LIBZ) - list(APPEND _libs ZLIB::ZLIB) + if(HAVE_LIBZ AND TARGET ZLIB::ZLIB) + add_library(CURL::ZLIB INTERFACE IMPORTED) + get_target_property(_curl_libname ZLIB::ZLIB LOCATION) + set_target_properties(CURL::ZLIB PROPERTIES INTERFACE_LINK_LIBRARIES "${_curl_libname}") + list(APPEND CURL_LIBS CURL::ZLIB) endif() - foreach(_lib IN LISTS _libs) - if(TARGET "${_lib}") - add_library(CURL::${_lib} INTERFACE IMPORTED) - get_target_property(_libname "${_lib}" LOCATION) - set_target_properties(${_lib} PROPERTIES INTERFACE_LINK_LIBRARIES "${_libname}") - list(APPEND CURL_LIBS ${_lib}) - endif() - endforeach() if(WIN32) add_library(CURL::win32_winsock INTERFACE IMPORTED) set_target_properties(CURL::win32_winsock PROPERTIES INTERFACE_LINK_LIBRARIES "ws2_32")