首页 / 资讯中心 / 文章详情

Win10下VS2019编译curl 7.84.0静态库集成指南

Win10下VS2019编译curl 7.84.0静态库集成指南 ★ FEATURED ARTICLE
简介本资源是在Win10环境下使用CMake 3.22与VS2019编译完成的curl 64位库版本为7.84.0支持SSL面向需要在Windows平台进行C/C网络开发、调用HTTP接口或研究curl源码的开发者。包内已整理为lib与include的标准目录结构便于直接集成到Visual Studio工程中同时附带curl.exe可执行文件方便在命令行中直接测试各类HTTP请求。资源共19个文件以11个h头文件、2个am构建脚本、1个lib静态库、1个dll动态库、1个exp导出文件及1个exe可执行文件为主另有README说明与gitignore配置压缩包约354KB体积轻巧。目前已有776人学习下载适合希望省去自行编译环节、快速获得可用curl库的开发者参考使用。1. 拿到一个 7.84.0 的 curl 静态库先搞清楚它能干什么在 Win10 上做 C 开发绕不开网络请求。WinHTTP 太底层自己封装 socket 又容易在 HTTPS 证书校验上翻车于是很多人会去找一个编译好的 curl 64 位库直接链进工程。标题里这个「win10 下用 vs2019 编译好的 curl 64 位库 版本 7.84.0」本质就是一份已经用 Visual Studio 2019 工具链编出来的 libcurl 静态库或导入库配套头文件拿来就能在 x64 工程里#include curl/curl.h然后调curl_easy_perform。它解决的是「不想自己折腾 OpenSSL、zlib、nghttp2 一堆依赖也不想在 MSVC 下跟 CMake 选项搏斗」这个具体诉求。适合谁适合做 Windows 桌面工具、工业上位机、内网数据采集程序且工程本身就是 VS2019 x64 的开发者。如果你用的是 MinGW 或者 VS2022链接阶段大概率会碰到运行库不匹配的问题这点后面会细说。2. 为什么选 7.84.0 这个版本以及静态库和动态库怎么挑2.1 7.84.0 在 curl 版本线里的位置curl 7.84.0 发布于 2022 年年中属于 7.x 后期版本。它比 7.79 之前的老版本多了对 HTTP/2 更完整的支持也修了一批 CVE。选这个版本通常有两个现实原因一是某些老项目锁死了 VS2019而 VS2019 的 MSVC 工具链对更新版 curl 的 CMake 配置支持不一定顺二是 7.84.0 的 API 已经足够稳定curl_easy_setopt的常用选项都齐了没必要追最新版。需要提醒的是7.84.0 不是 LTS如果你做的是长期维护的产品要评估后续升级成本。2.2 静态库libcurl.lib和动态库libcurl.dll import lib的取舍对比项静态库动态库部署只发 exe无额外文件必须带 dll漏了直接启动失败体积exe 变大exe 小dll 可复用依赖冲突容易和工程里其他库的 OpenSSL/zlib 符号打架隔离性好升级重新编译链接换 dll 即可调试符号在 exe 里相对好查需要对应 pdb我一般做内网工具优先静态库省得客户现场少拷一个 dll 就来问「为什么打不开」。但静态库有个血泪经验如果你的工程同时链了别的用 OpenSSL 的库符号重复定义几乎必然出现这时候要么统一依赖要么改用动态库。2.3 确认库的位数和运行库模式拿到库先别急着写代码用dumpbin确认三件事位数、运行库、导出符号。# 在 VS2019 的 x64 Native Tools Command Prompt 里执行 dumpbin /headers libcurl.lib | findstr machine # 期望看到 machine (x64) dumpbin /directives libcurl.lib | findstr DEFAULTLIB # 看它依赖的是 MSVCRT/MD还是 LIBCMT/MT逻辑说明/headers看机器架构必须是 x64如果是 x86 链接时会报LNK1112: 模块计算机类型冲突。/directives看默认库如果库是/MT编的而你的工程是/MD会出现一堆LNK2005重复定义或者运行库堆不匹配导致的随机崩溃。参数上工程属性里「C/C → 代码生成 → 运行库」必须和库保持一致这是最常见的翻车点。3. 在 VS2019 工程里把 curl 64 位库接进去的完整步骤3.1 目录结构和头文件放置假设你拿到的包解压后是这样curl-7.84.0-vs2019-x64/ ├── include/curl/ (curl.h, easy.h, multi.h 等) ├── lib/ (libcurl.lib 或 libcurl_a.lib) └── bin/ (如果有 dll 放这里)把include和lib放到工程目录下比如third_party/curl/。不要直接引用桌面上的路径换台机器就断。3.2 工程属性配置的四个关键位置1. C/C → 常规 → 附加包含目录$(ProjectDir)third_party\curl\include 2. 链接器 → 常规 → 附加库目录$(ProjectDir)third_party\curl\lib 3. 链接器 → 输入 → 附加依赖项libcurl.lib;ws2_32.lib;wldap32.lib;crypt32.lib;normaliz.lib 4. C/C → 预处理器 → 预处理器定义CURL_STATICLIB逻辑说明CURL_STATICLIB这个宏必须加否则 curl.h 会把函数声明成__declspec(dllimport)链接静态库时报LNK2019找不到符号。附加依赖项里那几个系统库是 curl 在 Windows 下的硬依赖ws2_32是 socketwldap32是 LDAPcrypt32是证书normaliz是 IDN 处理。少一个就是一堆无法解析的外部符号。3.3 一个最小可运行的 HTTPS GET 示例#include curl/curl.h #include string #include iostream // 写回调把收到的数据追加到 string static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { size_t total size * nmemb; static_caststd::string*(userp)-append(static_castchar*(contents), total); return total; } int main() { curl_global_init(CURL_GLOBAL_DEFAULT); // 进程启动时调一次 CURL* curl curl_easy_init(); if (!curl) return -1; std::string response; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/api/health); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, response); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 总超时 10 秒 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L); // 连接超时 5 秒 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 跟随 302 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // 保持证书校验 CURLcode res curl_easy_perform(curl); if (res ! CURLE_OK) { std::cerr curl failed: curl_easy_strerror(res) std::endl; } else { long code 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, code); std::cout HTTP code body size response.size() std::endl; } curl_easy_cleanup(curl); curl_global_cleanup(); return 0; }逻辑说明curl_global_init必须在任何其他 curl 调用之前执行且整个进程只调一次多线程下要在主线程初始化。CURLOPT_WRITEFUNCTION的回调签名固定返回实际处理的字节数返回不等于total会导致 curl 中止传输。CURLOPT_TIMEOUT是整次请求的总时间CURLOPT_CONNECTTIMEOUT只算连接阶段两个都要设否则遇到慢服务器会卡死。CURLOPT_SSL_VERIFYPEER保持 1关掉它等于裸奔生产环境不要动。3.4 用 curl -v 对照排查请求是否发对了curl -v https://example.com/api/health -o NUL逻辑说明-v打印握手、请求头、响应头全过程-o NUL在 Windows 下丢弃 body。当你程序里请求失败但不知道是 DNS、TLS 还是服务端返回错误时先用命令行 curl 跑一遍同样的 URL对比输出。如果命令行能通、程序不通问题基本在证书路径或代理设置如果命令行也不通那就是网络或服务端的事别在代码里瞎改。4. 链接和运行阶段最容易踩的坑4.1 LNK2019 无法解析的外部符号 __imp_curl_easy_init现象编译通过链接报一堆__imp_前缀的符号找不到。 原因没有定义CURL_STATICLIB头文件按动态库方式声明了函数。 解决在预处理器定义里加上CURL_STATICLIB重新生成。4.2 程序启动即崩溃堆损坏或 0xC0000005现象编译链接都过一运行到 curl 调用就崩。 原因库和工程的运行库模式不一致比如库是/MT而工程是/MD跨堆释放内存直接炸。 解决用dumpbin /directives确认库的模式把工程「代码生成 → 运行库」改成一致。VS2019 默认新建工程是/MDdDebug和/MDRelease如果库是/MT编的Debug 和 Release 都要改。4.3 HTTPS 请求返回 CURLE_SSL_CACERT 或证书错误现象HTTP 能通HTTPS 报 60 号错误。 原因静态库没有内置 CA 证书路径或者系统证书链不被 curl 默认使用。 解决下载cacert.pem用CURLOPT_CAINFO指定绝对路径或者改用CURLOPT_SSL_OPTIONS配合 Windows 证书存储但这需要 curl 编译时开了 Schannel 后端。先确认你拿到的库是 OpenSSL 后端还是 Schannel 后端用curl_version_info打印一下。4.4 多线程下随机崩溃或数据错乱现象单线程正常多线程并发请求偶发崩溃。 原因curl_global_init被多个线程重复调用或者多个线程共用同一个CURL*句柄。 解决curl_global_init在程序启动时主线程调一次每个线程用自己的CURL*curl_easy_init和curl_easy_cleanup成对出现在同一线程内。curl 的 easy 句柄不是线程安全的。4.5 请求卡住不返回超时设置无效现象设置了CURLOPT_TIMEOUT但程序还是卡很久。 原因DNS 解析阶段不受CURLOPT_TIMEOUT完全约束或者用了CURLOPT_NOSIGNAL没开导致信号干扰。 解决加上CURLOPT_CONNECTTIMEOUT限制连接阶段Windows 下建议同时设CURLOPT_NOSIGNAL为 1L避免多线程场景下 curl 使用信号机制引发问题。5. 把 curl 封装成工程里能长期用的网络层5.1 封装一个 RAII 的 CurlSession 类class CurlSession { public: CurlSession() { handle_ curl_easy_init(); } ~CurlSession() { if (handle_) curl_easy_cleanup(handle_); } CurlSession(const CurlSession) delete; CurlSession operator(const CurlSession) delete; CURL* get() const { return handle_; } bool PostJson(const std::string url, const std::string json, std::string out) { if (!handle_) return false; struct curl_slist* headers nullptr; headers curl_slist_append(headers, Content-Type: application/json); curl_easy_setopt(handle_, CURLOPT_URL, url.c_str()); curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(handle_, CURLOPT_POSTFIELDS, json.c_str()); curl_easy_setopt(handle_, CURLOPT_POSTFIELDSIZE, (long)json.size()); curl_easy_setopt(handle_, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(handle_, CURLOPT_WRITEDATA, out); curl_easy_setopt(handle_, CURLOPT_TIMEOUT, 15L); CURLcode res curl_easy_perform(handle_); curl_slist_free_all(headers); return res CURLE_OK; } private: CURL* handle_ nullptr; };逻辑说明RAII 保证句柄一定释放禁用拷贝避免句柄被意外复制。curl_slist_append返回新链表头必须用返回值直接传原指针是常见错误。CURLOPT_POSTFIELDSIZE要显式设置否则 curl 用strlen算长度body 里有\0就截断。每次请求后curl_slist_free_all释放头链表否则内存泄漏。5.2 用 curl_version_info 做启动自检curl_version_info_data* info curl_version_info(CURLVERSION_NOW); std::cout curl info-version ssl (info-ssl_version ? info-ssl_version : none) libz (info-libz_version ? info-libz_version : none) std::endl;逻辑说明启动时打印一次版本和 SSL 后端能快速确认链接进去的到底是不是你以为的那个库。如果ssl_version是 none说明这个库编译时没带 SSLHTTPS 请求会直接失败。这一步在客户现场排查时特别有用省得猜。5.3 验证清单上线前跑一遍检查项方法通过标准位数dumpbin /headersx64运行库dumpbin /directives与工程一致SSL 后端curl_version_info非 noneHTTPS 请求请求已知站点HTTP 200超时请求不可达 IP按设定时间返回多线程10 线程并发 100 次无崩溃无泄漏证书校验请求自签名站点返回证书错误这套清单我每次集成新库都会跑一遍尤其是运行库和 SSL 后端这两项翻车概率最高。静态库集成没有玄学就是把位数、运行库、宏定义、依赖库四件事对齐对齐了就能跑。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站