cmake:Windows编译支持HTTPS的curl库及find_package查找CURL时需要注意的问题

Posted 10km

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cmake:Windows编译支持HTTPS的curl库及find_package查找CURL时需要注意的问题相关的知识,希望对你有一定的参考价值。

curl是一个成熟的HTTP client库,现在windows平台下可以使用cmake在命令行完成编译。

build curl

以下脚本实现Windows CMD下使用cmake及VS2015编译curl

cd curl
mkdir build
cd build
#############################################
# 生成Visual Studio 2015工程文件
cmake .. -G "Visual Studio 14 2015 Win64" ^
	-DCMAKE_INSTALL_PREFIX=J:\\curl-vc140-x64 ^
	-DBUILD_SHARED_LIBS=OFF ^
	-DCURL_USE_OPENSSL=ON ^
	-DCMAKE_PREFIX_PATH=J:\\skcapmini\\dependencies\\dist\\openssl-1.1.0c\\vc140\\x64\\release\\dynamic;J:\\skcapmini\\dependencies
\\dist\\zlib-1.2.9\\vc140\\x64 
# CMAKE_INSTALL_PREFIX 指定安装位置
# BUILD_SHARED_LIBS=OFF 生成curl静态库,如果生成动态库,可以不加此选项
# CURL_USE_OPENSSL=ON 指定使用OPENSSL,如果不需要支持HTTPS,可以不加此选项
# CMAKE_PREFIX_PATH 指定OpenSSL,ZLIB库的安装位置不需要支持HTTPS,可以不加此选项
#############################################
# 编译CURL并安装到CMAKE_INSTALL_PREFIX指定的位置
# 编译Debug版
cmake --build . --target install --config Debug -j 8
# 编译Release版
cmake --build . --target install --config Release -j 8
# - j 8 指定8线程并行编译,以提高编译速度

find_package

上一步已经编译了curl,现在就可以在自己项目的中引用curl库了
一般我们会在cmake脚本中通过find_package查找curl库,

find_package(CURL)

一般来说这样也没问题,但如果你是像博主一样使用自己编译的curl静态库。那么应该以如下方式调用find_package

	# 优先使用CONFIG模式查找
	find_package(CURL CONFIG)
	if(NOT CURL_FOUND)
		# 没找到再用MODULE模式查找
		find_package(CURL)
	endif()

因为cmake本身提供了Module方式查找CURL的脚本,调用find_package时如果不指定CONFIG模式,默认是以MODULE方式调用cmake内置的FindCURL.cmake来查找CURL。
不论是MODULE还是CONFIG模式都能正常找到CURL,你在项目中引用用CURL::libcurl target,能正常编译项目,但如果是要生成动态库或EXE等需要连接的动作时就会报错找不到openssl,zlib,socket通讯相关的函数。因为MODULE模式查找CURL时并没有把CURL静态库所依赖的openssl,zlib等库也加到CURL::libcurl target,所以导致连接失败。
正因为如此,要如上优先使用CONFIG模式查找CURL,没找到再用MODULE模式查找,这样就能确保找到CURL::libcurl target可以在项目正常连接。

CURLTarget.cmake

也许你会想问为什么CONFIG模式能正确找到静态编译的CURL的依赖库?
那么请看看你在第一步编译好的CURL生成的cmake脚本:
curl-vc140-x64\\lib\\cmake\\CURL\\CURLTargets.cmake 1
如下是CURLTargets.cmake 中的代码片段

# Create imported target CURL::libcurl
add_library(CURL::libcurl STATIC IMPORTED)

set_target_properties(CURL::libcurl PROPERTIES
  INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"
  INTERFACE_INCLUDE_DIRECTORIES "$_IMPORT_PREFIX/include"
  INTERFACE_LINK_LIBRARIES "wldap32;winmm;ws2_32;OpenSSL::SSL;OpenSSL::Crypto;ZLIB::ZLIB;advapi32;crypt32"
)

可以看到在CURLTargets.cmake创建了名为CURL::libcurl 的 import target ,并设置了CURL::libcurlINTERFACE_LINK_LIBRARIES 属性为"wldap32;winmm;ws2_32;OpenSSL::SSL;OpenSSL::Crypto;ZLIB::ZLIB;advapi32;crypt32",
这就是定义了CURL::libcurl的所有依赖库。

并且还通过INTERFACE_COMPILE_DEFINITIONS 属性定义了宏CURL_STATICLIB以告诉引用CURL::libcurl的项目使用的是CURL静态库。

那么为什么MODULE模式不能正确找到静态编译的CURL的依赖库?

而cmake内置MODULE方式查找CURL的脚本(cmake-3.17.1-win64-x64/share/cmake-3.17/Modules/FindCURL.cmake)2是按搜索CURL动态库的方式来实现的,在创建CURL::libcurl 时并没有设置INTERFACE_LINK_LIBRARIES ,INTERFACE_COMPILE_DEFINITIONS 属性
只是按常规设置了INTERFACE_INCLUDE_DIRECTORIES(include文件夹位置),IMPORTED_LOCATION_RELEASE(库文件位置)属性
对于CURL动态库,这种方式没有问题,但对于编译的CURL静态库,由于CURL::libcurl imported target不能提供完整的依赖库信息,就会导致在项目编译没问题,但连接的时候会报错找不到符号。


  1. curl-vc140-x64是你指定的安装位置 ↩︎

  2. cmake-3.17.1-win64-x64是你的cmake安装位置 ↩︎

以上是关于cmake:Windows编译支持HTTPS的curl库及find_package查找CURL时需要注意的问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 cmake (windows) 构建时不显示 Qt 资源

如何使用 CMake 分别编译 *.cpp 和 *.cu?

cuda 多计算能力支持

vscode 中增加文件后缀类型的支持: 设置cpp支持.cu等后缀

编译 cuda_ndarray.cu 失败:libcublas.so.7.5:无法打开共享对象文件

编译 CUDA 时出错