New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmake: don't include non-IMPORTED zlib target in check_library_exists. #11648
Conversation
8b57b3f
to
7a09921
Compare
If I read the changes correctly, The problem to solve here is a totally reasonable one, but IMO there is no other way around it, than instructing CMake to build leaf dependencies earlier than parents, in the correct order, for the whole tree. For this, CMake should first query all projects it's meant to build for their dependencies, build the dependency tree (report or fail on circular ones) and form the order that avoids this kind of problem in the first place. A "low-cost" version of this may be to somehow trigger building these dependencies from our Does CMake offer built-in support for this problem? (or is this meant to be to job of higher level / external tooling?) |
@nmoinvaz what @vszakats is saying is that curl cannot be configured correctly unless these dependencies already exist on disk. That means the motivating use case, to vendor curl and its dependencies and build them all in one giant project in a single CMake run, will not work. Only in such a use case would the dependencies be |
It may not work in the OpenSSL case (if it does feature checks), but it should work on the zlib case since there are no feature checks. Even in OpenSSL, I'm not sure why feature checks/flags are not available as #defines. I will investigate. |
It looks like it is using The only use case I really care about is the ZLIB use case. We have been using our own zlib |
7a09921
to
158aca7
Compare
@vszakats can you explain this a bit. My understanding is that whether or not the CMake targets are imported/non-imported, that all the symbols are resolved in the linker stage. |
ZLIB is a transitive dependency for a list of curl dependencies (OpenSSL, wolfSSL, all SSHs, ngtcp2). In curl-for-win, ZLIB is the very first project to build for these reasons exactly. This is orchestrated by a custom script and a manually set build order. I'd expect CMake offering control over that if it's capable of building a bunch of projects in a single go. If we limit this to ZLIB-only, isn't it a solution to "just" make sure in the upper-level CMake logic, that ZLIB is always built before curl? |
My intention is not to change the build order of projects. CMake already handles build order dependency nicely between parent and child projects. Since ZLIB does not have any checks, it does not need to be built beforehand. By adding The goal is to prevent our zlib CMake target from being included in the call to |
check_library_exists/concat does not work well with non-imported targets. ZLIB might not be an imported target if it is included in a parent cmake project before including curl.
158aca7
to
18d7773
Compare
@bagder any chance in getting this merged? |
Hm, IMO that build script already fakes |
It's not that simple because of the way that check_library_exists is called by appending previously found library names into the current check. So you'd have to set the cache variable for every call to check_library _exists that included zlib and then do that for each platform. It would be too many variables to be practical. |
Is it possible to get this merged into the next release? |
I haven't made extensive tests, but it seems we might have a "cleaner" fix by eliminating the remaining 4 uses of Does this draft patch solve this Issue? May it create any new ones?: diff --git a/CMake/Macros.cmake b/CMake/Macros.cmake
index e12bf303f..7ad2f5c40 100644
--- a/CMake/Macros.cmake
+++ b/CMake/Macros.cmake
@@ -23,19 +23,6 @@
###########################################################################
#File defines convenience macros for available feature testing
-# This macro checks if the symbol exists in the library and if it
-# does, it prepends library to the list. It is intended to be called
-# multiple times with a sequence of possibly dependent libraries in
-# order of least-to-most-dependent. Some libraries depend on others
-# to link correctly.
-macro(check_library_exists_concat LIBRARY SYMBOL VARIABLE)
- check_library_exists("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "${CMAKE_LIBRARY_PATH}"
- ${VARIABLE})
- if(${VARIABLE})
- set(CURL_LIBS ${LIBRARY} ${CURL_LIBS})
- endif()
-endmacro()
-
# Check if header file exists and add it to the list.
# This macro is intended to be called multiple times with a sequence of
# possibly dependent header files. Some headers depend on others to be
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 863d126ac..97b07254b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -380,7 +380,10 @@ if(ENABLE_THREADED_RESOLVER)
endif()
# Check for all needed libraries
-check_library_exists_concat("socket" connect HAVE_LIBSOCKET)
+check_library_exists("socket" "connect" "" HAVE_LIBSOCKET)
+if(HAVE_LIBSOCKET)
+ set(CURL_LIBS "socket;${CURL_LIBS}")
+endif()
check_function_exists(gethostname HAVE_GETHOSTNAME)
@@ -755,8 +758,12 @@ if(NOT CURL_DISABLE_LDAP)
if(NOT USE_WIN32_LDAP)
# Check for LDAP
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
- check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
- check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER)
+ check_library_exists("${CMAKE_LDAP_LIB}" "ldap_init" "" HAVE_LIBLDAP)
+ if(HAVE_LIBLDAP)
+ check_library_exists("${CMAKE_LDAP_LIB};${CMAKE_LBER_LIB}" "ber_init" "" HAVE_LIBLBER)
+ else()
+ check_library_exists("${CMAKE_LBER_LIB}" "ber_init" "" HAVE_LIBLBER)
+ endif()
set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
@@ -795,8 +802,10 @@ if(NOT CURL_DISABLE_LDAP)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -DLDAP_DEPRECATED=1)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
+ set(CURL_LIBS "${CMAKE_LDAP_LIB};${CURL_LIBS}")
if(HAVE_LIBLBER)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
+ set(CURL_LIBS "${CMAKE_LBER_LIB};${CURL_LIBS}")
endif()
check_c_source_compiles("
@@ -843,7 +852,10 @@ endif()
# Check for idn2
option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
if(USE_LIBIDN2)
- check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
+ check_library_exists("idn2" "idn2_lookup_ul" "" HAVE_LIBIDN2)
+ if(HAVE_LIBIDN2)
+ set(CURL_LIBS "idn2;${CURL_LIBS}")
+ endif()
else()
set(HAVE_LIBIDN2 OFF)
endif() |
@vszakats removing |
I don't think we need If any of such check happens to require a previously detected lib, I believe we should add the required one explicitly to the specific check it needs it, instead of blindly adding everything detected previously like we do now. |
The idea of `check_library_exists_concat()` is that it detects an optional component and adds it to the list of libs that we also use in subsequent component checks. This caused problems when detecting components, with unnecessary dependencies that were not yet built. CMake offers the `CMAKE_REQUIRED_LIBRARIES` variable to set the libs used for component checks, which we already use in most of the cases. That left 4 uses of `check_library_exists_concat()`. Only one of these actually needed the 'concat' feature (ldap/lber). Delete this function and replace it with standard `check_library_exists()` and manual management of our `CURL_LIBS` list we use when linking build targets. And special logic to handle the ldap/lber case. (We have a similar function for headers: `check_include_file_concat`. It works, but problematic for performance reasons and because it hides the actual headers necessary in `check_symbol_exists()` calls.) Ref: curl#11537 Fixes curl#11285 Fixes curl#11648 Closes #xxxxx
The idea of `check_library_exists_concat()` is that it detects an optional component and adds it to the list of libs that we also use in subsequent component checks. This caused problems when detecting components with unnecessary dependencies that were not yet built. CMake offers the `CMAKE_REQUIRED_LIBRARIES` variable to set libs used for component checks, which we already use in most cases. That left 4 uses of `check_library_exists_concat()`. Only one of these actually needed the 'concat' feature (ldap/lber). Delete this function and replace it with standard `check_library_exists()` and manual management of our `CURL_LIBS` list we use when linking build targets. And special logic to handle the ldap/lber case. (We have a similar function for headers: `check_include_file_concat()`. It works, but problematic for performance reasons and because it hides the actual headers required in `check_symbol_exists()` calls.) Ref: #11537 #11558 Fixes #11285 Fixes #11648 Closes #12070
check_library_exists
does not work well with non-imported targets. ZLIB might not be an imported target if it is included in a parent cmake project before including curl.We use a separate variable
CURL_DEPS
to keep track of non-imported targets so they don't get caught up in thecheck_library_exists_concat()
call.Original issue: #11285.
Background info: #11285 (comment) and #11537 (comment).