动态链接OpenSSL和Curl CMake本身提供了对OpenSSL/Curl这种大户人家的库的支持,通过find_package
命令查找系统安装的OpenSSL/Curl库的路径,动态链接的方式如下即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 find_package (OpenSSL REQUIRED)if (OPENSSL_FOUND) include_directories (${OPENSSL_INCLUDE_DIRS} ) message (STATUS "OpenSSL Found!" )endif ()find_package (CURL REQUIRED)if (CURL_FOUND) include_directories (${CURL_INCLUDE_DIR} ) message (STATUS "Curl Found: ${CURL_VERSION_STRING} ${CURL_LIBRARIES} ${CURL_LINK_LIBRARIES}!" )else (CURL_FOUND) message (FATAL_ERROR "Could not find the CURL library and development files." )endif ()target_link_libraries (target_program ${CURL_LIBRARIES} )target_link_libraries (target_program OpenSSL::Crypto OpenSSL::SSL)
由于项目需求需要改成静态链接,其实没太大必要,把需要的动态库一起打包到安装软件,然后指定rpath应该就可以了。
但是甲方爸爸说了算了啊。🤷♂️
静态链接配置 Linux发行版仓库安装的OpenSSL和Curl都包含了静态和动态库,但是CMake这两个各自启用静态编译的方法不太一样。
OpenSSL添加set(OPENSSL_USE_STATIC_LIBS TRUE)
即可,make时可以看到已经找到静态库。
Curl则需要在include头文件之前添加add_definitions(-DCURL_STATICLIB)
参考:
Static linking of OpenSSL Crypto in CMake
C - Cmake compiling program with libcurl
1 2 3 4 5 set (OPENSSL_USE_STATIC_LIBS TRUE )add_definitions (-DCURL_STATICLIB)
但是事实上编译过程中发现Curl好像还是动态链接的,编译完成的使用ldd -r target_program
,发现还有libcurl.so.4
之类字样,似乎没有找到静态库。
强行指定绝对路径链接libcurl.a
的话会爆出找不到定义的错误,因为curl依赖的库也得静态链接才可以,这也说明前面的设置并没有成功静态链接。
ls
查看Curl库所在位置可以看到动态库静态库同时都存在,应该还是配置问题。中间绕了些弯弯发现了${CMAKE_FIND_LIBRARY_SUFFIXES}
选项,本意是设置find_library
命令查找库时后缀名的优先级,事实上find_package
内部实现就是前者,一开始配置错误,死活没找到静态.a
库,在Linux下默认查找顺序是.so;.a
,改成如下即可找到并链接静态Curl。
1 SET (CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES} )
参考 Default values for CMAKE_FIND_LIBRARY_PREFIXES/CMAKE_FIND_LIBRARY_SUFFIXES
使用curl-config --static-libs
可以看到所依赖的其他库有哪些。
参考 How to get rid of libcurl linking error?
源码编译Curl静态库 可以发现,Linux发行版仓库中的Curl依赖的其他乱七八糟库过多,不得已还得自己编译,不开启不需要的功能。Curl官网 下载最新7.70版本源码,执行./configure --with-ssl --disable-shared
之后可以看到配置开启的功能如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Host setup: x86_64-pc-linux-gnu Install prefix: /usr/local Compiler: gcc CFLAGS: -Werror-implicit-function-declaration -O2 -Wno-system-headers -pthread CPPFLAGS: LDFLAGS: LIBS: -lssl -lcrypto -lssl -lcrypto -lz curl version: 7.70 .0 SSL: enabled (OpenSSL) SSH: no (--with-{libssh,libssh2}) zlib: enabled brotli: no (--with-brotli) GSS-API: no (--with-gssapi) TLS-SRP: enabled resolver: POSIX threaded IPv6: enabled Unix sockets: enabled IDN: no (--with-{libidn2,winidn}) Build libcurl: Shared=no, Static=yes Built-in manual: enabled --libcurl option: enabled (--disable-libcurl-option) Verbose errors: enabled (--disable-verbose) Code coverage: disabled SSPI: no (--enable-sspi) ca cert bundle: /etc/ssl/certs/ca-certificates.crt ca cert path: no ca fallback: no LDAP: no (--enable-ldap / --with-ldap-lib / --with-lber-lib) LDAPS: no (--enable-ldaps) RTSP: enabled RTMP: no (--with-librtmp) Metalink: no (--with-libmetalink) PSL: no (libpsl not found) Alt-svc: no (--enable-alt-svc) HTTP2: disabled (--with-nghttp2) HTTP3: disabled (--with-ngtcp2, --with-quiche) ESNI: no (--enable-esni) Protocols: DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP Features: SSL IPv6 UnixSockets libz AsynchDNS NTLM NTLM_WB TLS-SRP HTTPS-proxy
然后,由于我不需要安装,只执行make
即可,生成文件路径为./lib/.libs/libcurl.a
。我也不知道为什么在隐藏目录下。
指定链接自己编译生成的libcurl.a
可以发现需要的依赖库就少很多了。
但是仍然缺少zlib
、dl
和pthread
的库支持。后两者都是基本库,添加下面一行即可。
1 target_link_libraries (target_program ${CMAKE_DL_LIBS} -lpthread)
静态链接zlib zlib是提供压缩算法的库,CMake其实也提供了zlib支持,简单如下即可。
1 2 3 4 5 6 7 find_package (ZLIB REQUIRED)if (ZLIB_FOUND) message (STATUS "Zlib Found!" ) include_directories (${ZLIB_INCLUDE_DIR} )endif ()target_link_libraries (target_program ${ZLIB_LIBRARIES} )
由于之前配置了CMAKE_FIND_LIBRARY_SUFFIXES
,默认会找到libz.a
。
本来以为OK了,结果还是出了问题:Ubuntu软件仓库里的zlib不支持重定位!静态链接时提示如下错误:
1 2 /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libz.a(inflate.o): relocation R_X86_64_PC32 against symbol `inflateReset' can not be used when making a shared object ; recompile with -fPIC /usr/bin/ld: final link failed: Bad value
没办法还是需要源码编译zlib时开启-fPIC
支持才可以,zlib官网 下载源码,源码目录下执行CFLAGS="-O3 -fPIC" ./configure && make
即可,生成libz.a
文件就在当前目录下,指定链接终于可以成功编译啦!
动态链接和静态链接生成库依赖对比 我们再使用ldd -r target_program
对比一下动态链接和静态链接的库,可以发现静态链接后依赖的库要少很多。
⬆️动态链接
⬆️静态链接
最终版CMakelists.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 include (CMakeDependentOption)option (LINK_CURL_OPENSSL_STATIC "Using static curl & openssl library" ON ) cmake_dependent_option(CUSTOM_CURL_STATIC "Using prebuilt static curl library" ON "LINK_CURL_OPENSSL_STATIC" OFF ) cmake_dependent_option(CUSTOM_ZLIB_STATIC "Using prebuilt static zlib library" ON "LINK_CURL_OPENSSL_STATIC" OFF )if (LINK_CURL_OPENSSL_STATIC) message (STATUS "Using static curl & openssl library!" ) add_definitions (-DCURL_STATICLIB) SET (CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES} ) message (STATUS "CMAKE_FIND_LIBRARY_SUFFIXES: " ${CMAKE_FIND_LIBRARY_SUFFIXES} ) set (OPENSSL_USE_STATIC_LIBS TRUE )else ()endif ()find_package (OpenSSL REQUIRED)if (OPENSSL_FOUND) include_directories (${OPENSSL_INCLUDE_DIRS} ) message (STATUS "OpenSSL Found!" )endif ()if (NOT CUSTOM_CURL_STATIC) find_package (CURL REQUIRED) if (CURL_FOUND) include_directories (${CURL_INCLUDE_DIR} ) message (STATUS "Curl Found: ${CURL_VERSION_STRING} ${CURL_LIBRARIES} ${CURL_LINK_LIBRARIES}!" ) set (curl_library ${CURL_LIBRARIES} ) else (CURL_FOUND) message (FATAL_ERROR "Could not find the CURL library and development files." ) endif ()else () message (STATUS "Using custom compiled static library: libcurl.a !" ) include_directories (${PREBUILTS_BASE_DIRECTORY} /${PLATFORM_NAME} /include /) set (curl_library ${PREBUILTS_LIB_DERECTORY} /curl/libcurl.a)endif ()if (NOT CUSTOM_ZLIB_STATIC) find_package (ZLIB REQUIRED) if (ZLIB_FOUND) message (STATUS "Zlib Found!" ) include_directories (${ZLIB_INCLUDE_DIR} ) set (zlib_library ${ZLIB_LIBRARIES} ) endif ()else () message (STATUS "Using custom compiled static library: libz.a !" ) set (zlib_library ${PREBUILTS_LIB_DERECTORY} /zlib/libz.a)endif ()target_link_libraries (target_program ${curl_library} )target_link_libraries (target_program OpenSSL::Crypto OpenSSL::SSL)if (LINK_CURL_OPENSSL_STATIC) target_link_libraries (target_program ${zlib_library} ) target_link_libraries (target_program ${CMAKE_DL_LIBS} -lpthread)endif ()
上面的CMakelists提供了3个配置参数:
LINK_CURL_OPENSSL_STATIC
:默认开启,静态链接Curl和OpenSSL。
CUSTOM_CURL_STATIC
:默认开启,使用工程目录下预编译的libcurl.a。
CUSTOM_ZLIB_STATIC
:默认开启,使用工程目录下预编译的libzlib.a。
正常cmake .. && make
,会静态链接Curl、OpenSSL、zlib,其中Curl和zlib使用预编译版本。使用cmake -DCUSTOM_CURL_STATIC=OFF -DCUSTOM_ZLIB_STATIC=OFF .. && make
来使用默认系统安装的静态版本。
使用cmake -DLINK_CURL_OPENSSL_STATIC=OFF .. && make
,则会使用动态链接Curl和OpenSSL。
--- END ---