CMake build prints "Static linking is broken!" #841

Closed
zethon opened this Issue May 30, 2016 · 9 comments

Projects

None yet

3 participants

@zethon
zethon commented May 30, 2016

I want to statically link libcurl into an app I'm writing. I'm using the CMake build system since I'm trying to build with clang. However, the CMake build system is very clear:

CMake Warning at CMakeLists.txt:1137 (message):
Static linking is broken!

However, when I generate and then build I see it's built a file ./lib/libcurl.a

Can this file be trusted?

@bagder bagder added the cmake label May 31, 2016
@bagder
Member
bagder commented May 31, 2016

That message was introduced in commit 8ed66f9 by @Lekensteyn . You remember the reason? Is it still valid?

@Lekensteyn
Member
Lekensteyn commented May 31, 2016 edited

This likely refers to the generated curl-config file that is unusable in a certain configuration involving static libs, the actual library could still be functional.

What if you make install the library and then try to link with curl-config --static-libs? Does that work or will you get an error?

There is also this TODO within that commit:

TODO CURL_LIBS also contains absolute paths which don't work with static -l...

@zethon
zethon commented May 31, 2016

curl-config --static-libs does work with valid-looking output and no errors.

@Lekensteyn
Member
Lekensteyn commented May 31, 2016 edited

It seems that the problem is related to the inclusion of other shared libraries:

$ curl --libcurl example.c example.com -s -o /dev/null
$ /tmp/curl-root/bin/curl-config --static-libs
/tmp/curl-root/lib/libcurl.a -lc -lidn -llber -lldap -ldl -l/usr/lib64/libssl.so -l/usr/lib64/libcrypto.so -l/usr/lib64/libz.so -l/usr/lib64/libssh2.so
$ gcc example.c `/tmp/curl-root/bin/curl-config --static-libs`
/usr/bin/ld: cannot find -l/usr/lib64/libssl.so
/usr/bin/ld: cannot find -l/usr/lib64/libcrypto.so
/usr/bin/ld: cannot find -l/usr/lib64/libz.so
/usr/bin/ld: cannot find -l/usr/lib64/libssh2.so
collect2: error: ld returned 1 exit status

The cmake scripts have to be modified to return a static library (libssl.a, etc.) instead of the shared libs. That is a bit complicated... FindXXX modules are supposed to export the static library locations. For example, only CMake 3.4 has done this for OpenSSL: https://cmake.org/cmake/help/v3.4/module/FindOpenSSL.html

The problem is that -l/usr/lib/x86_64-linux-gnu/libssl.a does not work, it really has to be -lssl (with an appropriate -L... as needed). Setting ENABLE_STATIC to no has as only side-effect that the curl-config command refuses to output something for --static-libs.

Here is a WIP patch to prefer linking to static libs, but that still results in invalid linker commands (the TODO on the end is not resolved yet):

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06f18cf..6eff378 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,15 @@ if (ENABLE_CURLDEBUG)
   set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
 endif()

+# Prefer linking to static libraries when building a static library.
+if(CURL_STATICLIB)
+  if(WIN32)
+    set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+  else()
+    set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+  endif()
+endif()
+
 # initialize CURL_LIBS
 set(CURL_LIBS "")

@@ -310,6 +319,9 @@ if(CMAKE_USE_OPENSSL)
   find_package(OpenSSL)
   if(OPENSSL_FOUND)
     list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
+    if(CURL_STATICLIB)
+      list(APPEND CURL_LIBS ${CMAKE_DL_LIBS})
+    endif()
     set(USE_OPENSSL ON)
     set(HAVE_LIBCRYPTO ON)
     set(HAVE_LIBSSL ON)
@@ -1133,9 +1145,7 @@ set(CURL_CA_BUNDLE          "")
 set(CURLVERSION             "${CURL_VERSION}")
 set(ENABLE_SHARED           "yes")
 if(CURL_STATICLIB)
-  # Broken: LIBCURL_LIBS below; .a lib is not built
-  message(WARNING "Static linking is broken!")
-  set(ENABLE_STATIC         "no")
+  set(ENABLE_STATIC         "yes")
 else()
   set(ENABLE_STATIC         "no")
 endif()
@@ -1144,7 +1154,6 @@ set(includedir              "\${prefix}/include")
 set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 set(LIBCURL_LIBS            "")
 set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
-# TODO CURL_LIBS also contains absolute paths which don't work with static -l...
 foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
   set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
 endforeach()
@bagder
Member
bagder commented Jun 1, 2016

Static linking of libcurl is however the ability to build a static libcurl. Using a static libcurl is harder and we actually can't presume that we can figure out and provide the dependency chain of possible libs.

@Lekensteyn Lekensteyn added a commit to Lekensteyn/curl that referenced this issue Jun 1, 2016
@Lekensteyn Lekensteyn cmake: fix curl-config --static-libs
Libraries for `curl-config --static-libs` are required to have the form
-ldl. Assume library paths like /usr/lib/libssl.so and map it to "ssl"
for curl-config.

This removes the confusing messag "Static linking is broken" which was
printed because curl-config --static-libs was disfunctional while the
static libcurl.a is fine.

Fixes curl#841
4192146
@zethon
zethon commented Jun 4, 2016

Sorry to be using this as a message board for trouble-shooting but you guys seem responsive! :)

I've tried building a simple C++ app with the static library and I am getting several ldap linking errors:

Undefined symbols for architecture x86_64:
"_ldap_url_parse", referenced from:
_Curl_ldap in libcurl.a(ldap.c.o)
"_ldap_set_option", referenced from:
_Curl_ldap in libcurl.a(ldap.c.o)
(and on and on)

The thing that is confusing me is that I have disabled LDAP support:

image

So, I'm not sure why libcurl.a still references LDAP or how to fix this (without having to needlessly link to the LDAP's libs).

Suggestions? Thanks!

@zethon
zethon commented Jun 4, 2016 edited

I've made a little more progress. I was able get past the Linker errors (I think I may have just needed to clear my CMake cache and start from scratch) but now I don't seem to have any HTTP support (I'm on OSX 10.11.3). A simple call to an https site returns Unsupported protocol.

I'm certainly linking to the OpenSSL (and ZLib) libraries when I build libcurl, as well as in my app.

image

However it doesn't look like it:

$> src/curl -V
curl 7.50.0-DEV (Darwin) libcurl/7.50.0-DEV zlib/1.2.5
Protocols: http
Features: IPv6 libz UnixSockets

Thoughts?

@bagder
Member
bagder commented Jun 4, 2016

For general questions, help and support, please use curl-library mailing list. For specific bugs/issues you find, file them here.

@Lekensteyn Lekensteyn added a commit to Lekensteyn/curl that referenced this issue Aug 8, 2016
@Lekensteyn Lekensteyn cmake: fix curl-config --static-libs
The `curl-config --static-libs` command should not output paths like
-l/usr/lib/libssl.so, instead print the absolute path without `-l`.

This also removes the confusing message "Static linking is broken" which
was printed because curl-config --static-libs was disfunctional even
though the static libcurl.a library works properly.

Fixes curl#841
95ad190
@bagder
Member
bagder commented Sep 11, 2016

Fixed

@bagder bagder closed this Sep 11, 2016
@Lekensteyn Lekensteyn added a commit that referenced this issue Sep 11, 2016
@Lekensteyn Lekensteyn cmake: fix curl-config --static-libs
The `curl-config --static-libs` command should not output paths like
-l/usr/lib/libssl.so, instead print the absolute path without `-l`.

This also removes the confusing message "Static linking is broken" which
was printed because curl-config --static-libs was disfunctional even
though the static libcurl.a library works properly.

Fixes #841
2f3feda
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment