ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

libcurl跨平台编译实战:CMake构建curl.zip全流程

libcurl跨平台编译实战:CMake构建curl.zip全流程 简介这一资源专为需要实现跨平台网络通信的客户端开发者准备核心是libcurl库的编译与应用覆盖Linux、macOS、iOS、Android和Windows等主流系统可有效化解不同环境下源码配置、工具链选择与库文件生成不一致的痛点。压缩包体积非常轻量仅3.82MB共包含三个文件一份Markdown写成的编译说明一份curl 7.74.0的完整源代码压缩包以及一个面向iOS平台的交叉编译脚本。当前已有408人下载学习说明其内容具备一定实用性和参考价值。通过详细阅读说明文档可以厘清configure脚本、CMake工具以及Android NDK等不同编译方式的参数含义和注意事项借助随包提供的构建脚本开发者能在iOS环境中直接生成所需架构的库文件免去手动配置的繁琐过程。而基于源代码还可深入理解HTTP、FTP、SMTP等协议交互的实现原理并根据项目需要灵活裁剪功能最终在自有应用中快速实现请求发送、文件上传下载和安全连接等能力缩短网络模块的开发周期。1. 一个 zip 包背后是 libcurl 跨平台编译里最容易被低估的一环你有没有遇到过这种场景要给内网 Windows 服务器装一个自带 curl 的离线环境或者要把 libcurl 静态编进自己的 C 工具里却发现网上搜到的 curl.exe 不是依赖这个 DLL 就是缺那个证书又或者你在 Linux 上调好的命令行一迁到 Windows 就报curl: (35) unexpected eof。这篇笔记要解决的就是“libcurl 跨平台编译 curl.zip”这条完整链路从源码开始用 CMake 在 Windows 上编出 curl.exe 和 libcurl 库再交叉编译到 Android/Linux最后把产物整理成能直接分发的 zip 包。适合需要自己掌控 curl 版本、TLS 后端和依赖项的交付维护者也适合想把 libcurl 嵌进自有程序但被动态库链接折腾过的人。标题里的 curl.zip 不是终点真正值钱的是编译参数的选择逻辑和踩坑经验。2. 编译前先定选型TLS 后端、特性集和产出物决定后面所有命令2.1 动态还是静态先想清楚交付对象libcurl 的编译结果有两种常见形态一种是动态库Windows 上是 libcurl.dll curl.exe另一种是静态库libcurl.lib / libcurl.acurl.exe 里直接包含。选择哪个取决于你最终要把产物发给谁。如果是给普通用户用的免安装命令行工具我一般选静态库。curl.exe 单独一个文件就能跑拷进 U 盘就能用不会出现“缺少 libcurl-x64.dll”这种低级售后问题。代价是编译时间变长而且如果用了 OpenSSL还得把 OpenSSL 也静态编进去体积会从 1MB 左右涨到 4-6MB。如果是给开发团队做二次开发动态库更方便——应用和 curl 各升各的版本只要保证 ABI 兼容。这里有一个比较反直觉的点静态编译 libcurl 时CMake 默认会把 curl.exe 也同时生成但这并不代表 curl.exe 和 libcurl 用的是同一套配置。你必须在同一个 CMake 工程里同时指定BUILD_CURL_EXE和BUILD_SHARED_LIBS的状态才能真正控制产出物。我见过好几次“明明关了 shared出来的还是 DLL”的情况多半是没清理 CMakeCache。2.2 TLS/SSL 后端OpenSSL、Schannel 还是 mbedTLSTLS 是 libcurl 编译里最影响兼容性的选择。Windows 上有三条主流路线SchannelWindows 原生 TLS使用系统证书库不额外带证书文件对 Win7 之后的系统友好。但如果你的 curl 要跑在 Windows 7 上Schannel 默认的 TLS 版本协商可能会和某些只支持 TLS 1.0 的老服务器冲突。热词里那个curl: (35) unexpected eof很多就是 Schannel 在 TLS 版本协商失败时给出的误导读法。Schannel 的优点是“零证书管理”缺点是调试信息少出问题很难看内部状态。OpenSSL跨平台一致性好curl -V能看到 OpenSSL 版本和 SSL 后端细节抓包和定位握手问题相对容易。但它需要你维护 CA 证书文件ca-bundle.crt而且静态编译 OpenSSL 时容易遇到unresolved external symbol这类链接问题。现代 OpenSSL 1.1.1 和 3.x 在 Windows 上的编译逻辑差异不小最好直接按官方 INSTALL 文档来。mbedTLS体积最小适合嵌入式但功能裁剪多对 HTTP/2 的适配也麻烦。我的建议是如果你只面向 Windows 内部环境用 Schannel 能少一半的证书配置工作量如果你要跨平台统一行为或者要在 Linux/Android 上复用同一套代码选 OpenSSL。热词里那个“核实 libcurl 是否真无 c-ares”的讨论其实也是在帮你确认默认配置下 libcurl 用系统 getaddrinfo一旦你换成 c-aresDNS 解析的行为就完全变了TLS 后端不变也可能会让握手时序发生变化所以选型时要一起定。2.3 域名解析c-ares 与系统解析器的边界libcurl 源码树里默认不带 c-ares 的源码只有--enable-ares这样的配置项。所谓“真无 c-ares”是指要使用 c-ares 必须先单独下载 c-ares 源码并编译再把它的头文件和库路径交给 libcurl 的构建系统。如果你在 CMake 里直接写-DCARES_INCLUDE_DIR指向不存在的位置构建会静静跳过 c-ares 支持curl -V里不会出现c-ares字样而你却以为已经启用了。这个坑我踩过不止一次。什么时候需要 c-ares当你的应用需要异步 DNS 解析、需要在 DNS 查询期间不阻塞线程或者需要自定义 DNS 服务器--dns-servers时才有必要。普通的curl命令行下载系统解析器Windows 的 getaddrinfo / Linux 的 getaddrinfo完全够用引入 c-ares 反而增加编译依赖和体积。所以我的判断是没有异步 DNS 需求的场景直接不要碰 c-ares省掉一个变量。2.4 功能裁剪HTTP/2、SSH、IDN 等值得留多少CMake 配置 libcurl 时默认会启用很多协议HTTP、FTP、FILE、TELNET、DICT、LDAP 等。如果你只是想要 HTTP/HTTPS 下载这些协议全都是可裁剪的。一个经验值是把CURL_DISABLE_LDAP、CURL_DISABLE_TELNET、CURL_DISABLE_DICT打开整个包的体积能降 15% 左右编译时间也缩短。HTTP/2 需要 nghttp2 库。如果只为兼容现代 Web 服务器我建议打开如果追求最小依赖且目标环境都是内网 HTTP/1.1可以关掉。SSHSFTP需要 libssh2这个库在 Windows 上编译比较折腾只是偶尔用一次的话建议不要编进 libcurl直接留空即可。IDN国际化域名依赖 libidn2除非你的用户会访问中文域名否则没必要开。关键是把这些开关固化到一个 CMake 配置里不要每次开新终端都重新敲。我一般会把常用参数写进一个curl_config.cmake片段或者干脆用.bat脚本封装这样换机器重编时能复用同一份配置避免“上次明明能编这次就翻车”的玄学。3. 用 CMake 在 Windows 上编出 curl.exe 和 libcurl从源码到 curl.zip3.1 准备工具链与源码Windows 上推荐用 CMake Visual Studio 工具链来做也可以用 MinGW-w64但 MSVC 产物的兼容性最好。我这里以 MSVC 为例。先装好 Visual Studio 2022 并确保“使用 C 的桌面开发”组件里有 CMake 工具和 MSVC 编译器。然后准备三样源码curl 源码、OpenSSL 源码如果用 OpenSSL、zlib 源码可选。为了少走弯路我建议直接到 curl 的 GitHub Releases 页面下载正式发布的源码 tar.gz不要 clone 最新主分支因为主分支可能会有未回退的构建改动。假设目录结构是这样的D:\curl-build\ curl-src\ # curl 源码根目录 openssl-src\ # openssl 源码根目录 zlib-src\ # zlib 源码根目录 build-curl\ # CMake 构建目录 out\ # 最终产物目录3.2 静态库方案一条 CMake 命令出 curl.exe 和 libcurl.lib进入curl-src根目录创建一个工具链说明文件或者直接在命令行里传入参数。最省事的做法是直接在构建目录下运行 cmake。下面是一条我常用的静态编译命令cd D:\curl-build\build-curl cmake ..\curl-src ^ -G Visual Studio 17 2022 -A x64 ^ -DCMAKE_INSTALL_PREFIXD:\curl-build\out ^ -DBUILD_SHARED_LIBSOFF ^ -DBUILD_CURL_EXEON ^ -DCURL_USE_SCHANNELON ^ -DCURL_ENABLE_SSLON ^ -DUSE_ZLIBON ^ -DZLIB_INCLUDE_DIRD:\curl-build\zlib-src ^ -DZLIB_LIBRARYD:\curl-build\zlib-src\build\zlibstatic.lib ^ -DCURL_DISABLE_LDAPON ^ -DCURL_DISABLE_TELNETON ^ -DCURL_DISABLE_DICTON ^ -DCURL_DISABLE_FTPOFF ^ -DCURL_DISABLE_FILEOFF ^ -DCMAKE_BUILD_TYPERelease这条命令的逻辑是在build-curl目录配置一个 Visual Studio 2022 的 64 位工程安装前缀指向out不生成 DLL但要生成 curl.exe。SSL 后端用 Schannel所以不需要 OpenSSL 源码压缩协议用 zlib但直接指定 zlib 的静态库路径。参数说明-DBUILD_SHARED_LIBSOFF关闭共享库这是静态编译的核心开关。它同时影响 libcurl 和 zlib 等的构建方式。-DCURL_USE_SCHANNELON告诉 libcurl 用 Windows 自带的 Schannel。如果在这里改成-DCURL_USE_OPENSSLON则必须同时给OPENSSL_ROOT_DIR、OPENSSL_INCLUDE_DIR等参数否则 CMake 会报找不到 OpenSSL。-DZLIB_LIBRARY和-DZLIB_INCLUDE_DIR由于 zlib 在这种手动指定路径的方式下CMake 不会帮你找头文件所以必须显式给出。如果你不想管 zlib可以把USE_ZLIB设为 OFFcurl 仍能正常工作只是不支持 gzip 压缩的 HTTP 响应。不过现在大部分 HTTPS API 都会返回 gzip建议还是编上。CURL_DISABLE_*一组协议裁剪开关按需取舍。执行完 cmake 配置后继续执行构建和安装cmake --build . --config Release --target install静态编译产物会出现在D:\curl-build\out下重点文件是bin\curl.exe和lib\libcurl.lib。因为用了 Schannel产物里没有单独的 CA 文件curl 会读取系统证书库。逻辑上有一个细节要注意--target install只安装配置给install的目标。如果用-DBUILD_CURL_EXEOFF那install时只会装库和头文件不会装 curl.exe。所以上面命令里我保留了BUILD_CURL_EXEON这样直接拿到命令行工具。3.3 动态库方案DLL 怎么和 curl.exe 分开打包如果你的目标是交付一个可复用的动态库命令改用cmake ..\curl-src -G Visual Studio 17 2022 -A x64 ^ -DCMAKE_INSTALL_PREFIXD:\curl-build\out ^ -DBUILD_SHARED_LIBSON ^ -DBUILD_CURL_EXEON ^ -DCURL_USE_SCHANNELON ^ -DCURL_ENABLE_SSLON ^ -DUSE_ZLIBON ^ -DZLIB_INCLUDE_DIR... ^ -DZLIB_LIBRARY... ^ -DCMAKE_BUILD_TYPERelease动态编译后bin目录下会同时出现curl.exe和libcurl.dll。此时如果你只拿curl.exe出来跑会因为找不到libcurl.dll而报错。你需要把libcurl.dll和curl.exe放在同一目录或者把 DLL 路径写进 PATH。这里有一个坑MSVC 编译的动态库在 Release 配置下可能依赖vcruntime140.dll等运行库。如果你的目标机器是裸奔的 Win7得先确认这些运行库是否存在否则 curl.exe 直接起不来。解决方案有两种一是用/MD且带上微软可再发行组件安装包二是改用/MT静态链接运行时但这样 CMake 配置要加-DCMAKE_MSVC_RUNTIME_LIBRARYMultiThreaded否则默认还是动态运行库。3.4 整理 curl.zip 的文件清单与目录结构编译完成后的产物比较散真正交付前我会整理成如下结构curl-8.13.0-win64-schannel-static\ curl.exe curl-ca-bundle.crt # 如果用了 OpenSSL这里必须有证书 说明.txt如果是动态库方案curl-8.13.0-win64-schannel-dynamic\ curl.exe libcurl.dll vcruntime140.dll # 缺运行库时才需要一般不建议手工分发的工具带这个 说明.txt整理时我一般把curl -V的输出写到说明.txt里作为版本凭证。打包用 PowerShell 的Compress-Archive即可cd D:\curl-build\out Compress-Archive -Path .\curl-8.13.0-win64-schannel-static\* -DestinationPath D:\curl-build\curl.zip这样产出的 zip 就是“libcurl 跨平台编译 curl.zip”交付物本身。如果你后续还要扩展 Linux 版本zip 里加一个子目录区分平台即可。4. 把同一套源码交叉编译到 Android 和 LinuxNDK 与 sysroot 实操4.1 用 Android NDK 交叉编译 libcurl 的最小 CMake 配置Android 上编 libcurl本质是用 NDK 提供的交叉工具链替换主机编译器。CMake 在 NDK 里通常自带工具链文件路径类似$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake。一个最小配置长这样export ANDROID_NDK_HOME/opt/android-ndk-r25c export ANDROID_ABIarm64-v8a export ANDROID_PLATFORMandroid-21 cmake .. \ -DCMAKE_TOOLCHAIN_FILE$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \ -DANDROID_ABI$ANDROID_ABI \ -DANDROID_PLATFORM$ANDROID_PLATFORM \ -DBUILD_SHARED_LIBSOFF \ -DBUILD_CURL_EXEOFF \ -DCURL_USE_OPENSSLON \ -DOPENSSL_ROOT_DIR/path/to/openssl-android \ -DOPENSSL_INCLUDE_DIR/path/to/openssl-android/include \ -DOPENSSL_CRYPTO_LIBRARY/path/to/openssl-android/lib/libcrypto.a \ -DOPENSSL_SSL_LIBRARY/path/to/openssl-android/lib/libssl.a \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX/path/to/out-android参数说明ANDROID_ABIarm64-v8a指定目标架构如果需要 armeabi-v7a把这里的值换成armeabi-v7a并额外加-DANDROID_ARM_NEONON可选。ANDROID_PLATFORMandroid-21指定最低 API 级别。这里不要贪高因为越高意味着目标设备越新android-21能覆盖绝大多数 Android 7 以上设备。BUILD_CURL_EXEOFF通常 Android 上只需要 libcurl.a 给 App 用不需要 curl 命令行工具。如果你真要在 Android 上跑 curl 命令需要把BUILD_CURL_EXE设为 ON并且把可执行文件放进/data/local/tmp再运行但不建议这么做——Android 的 SELinux 策略会让命令行工具的使用极其受限。OpenSSL 必须单独用 NDK 交叉编译好目录结构要和 host 上的 OpenSSL 一致。你在 Android 上没法直接使用主机上编的 OpenSSL因为主机是 x86_64目标是 arm64二进制格式不兼容。编译命令后面加一行cmake --build . --config Release --target install即可把产物装到指定前缀。注意 Android 交叉编译时不需要也不会生成 Windows 上的 DLL产出物是libcurl.a和一堆头文件。4.2 Linux 下静态编译一个自带 CA 的 curl 可执行文件Linux 上的交叉编译不像 Android 那样有标准的工具链文件但做“跨平台编译 curl.zip”这个标题时Linux 侧最常见的情况其实是“在一个 Linux 版本上编出能在另一个 Linux 版本上运行的 curl”。比如你的服务器是 CentOS 7但开发机是 Ubuntu 22.04直接编出来的 curl 会因为 glibc 版本过高而无法在 CentOS 7 上跑。我的常用做法是用 Docker 容器跑编译环境选一个尽可能老的 base 镜像例如centos:7或debian:bullseye在里面装好 gcc、make、cmake 和 openssl 开发包然后编译一个静态链接的 curldocker run -it --rm \ -v /host/path/curl-src:/curl-src \ -v /host/path/build-linux:/build-linux \ centos:7 bash容器内执行cd /build-linux cmake /curl-src \ -DCMAKE_BUILD_TYPERelease \ -DBUILD_SHARED_LIBSOFF \ -DBUILD_CURL_EXEON \ -DCURL_USE_OPENSSLON \ -DOPENSSL_ROOT_DIR/usr \ -DCURL_DISABLE_LDAPON \ -DCURL_DISABLE_TELNETON \ -DPKG_CONFIG_USE_CMAKE_PREFIX_PATHON \ -DCMAKE_INSTALL_PREFIX/build-linux/out make -j$(nproc) make install这样编出来的 curl 主要链接了系统自带的 OpenSSL 和 zlib。如果你想要全静态连 OpenSSL 也静态需要在容器里先把 OpenSSL 编成.a文件然后给 CMake 传-DOPENSSL_USE_STATIC_LIBSTRUELinux 命令行 curl 的 CA 证书路径在编译时会被默认设置成系统路径如/etc/pki/tls/certs/ca-bundle.crt。如果你要把 curl.exe或 ELF 可执行文件拷到别的容器里最好用curl -V确认一下ca-bundle的编译路径然后在目标机器上把证书文件放到对应位置。这是我吃过亏的地方编的时候一切正常拷到另一个镜像里一跑就报 CA 证书找不到curl 直接拒绝所有 https 请求。4.3 交叉编译环境变量与工具链文件怎么写才不迷路交叉编译最怕的是环境变量泄漏。比如你在同一个 shell 里先配了 Android 环境再配 Linux 环境CC、CXX、AR这些变量还保留着上一次的路径CMake 就会用到错的编译器。我的习惯是每个平台单独开一个干净终端或者用一个小脚本隔离变量。一个通用的工具链文件大致长这样set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(TOOLCHAIN_PREFIX aarch64-linux-gnu-) set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g) set(CMAKE_FIND_ROOT_PATH /opt/arm64-sysroot) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)然后编译时用cmake .. -DCMAKE_TOOLCHAIN_FILE../toolchain-arm64.cmake这里三个MODE参数值得解释PROGRAM NEVER表示在宿主机找工具程序编译器、链接器LIBRARY和INCLUDE ONLY表示只在CMAKE_FIND_ROOT_PATH指定的 sysroot 里找依赖库和头文件。如果你不设CMAKE_FIND_ROOT_PATHCMake 可能把宿主机/usr/lib里的 x86 库链接进去链接 时会报一堆奇怪的cannot find -lssl或者更隐蔽的 ABI 不匹配错误。这个错误在运行时表现为段错误排错成本极高。要交叉编译成功先要拿到目标平台的 sysroot。通常可以下载对应芯片厂商提供的 sysroot或者在设备上直接挂载根文件系统拷贝过来。合理使用工具链文件可以大大减少“编译过了运行崩了”的尴尬。5. 编译与运行时避坑从 link 错误到 unexpected eof 的排查手册5.1 链接时找不到 libcurl.lib / 报 unresolved external symbol现象CMake 配置成功编译到链接阶段时报LNK2019: unresolved external symbol curl_easy_init referenced in function main或者干脆找不到libcurl.lib。原因一是安装路径没写对链接器搜索不到libcurl.lib二是你开了静态库但调用方仍按 DLL 的方式链接导致符号修饰不一致三是 CMake 的CURL::libcurl目标没被正确导出需要手动检查libcurl.lib文件是否真的生成。解决先确认生成文件的位置。静态编译后libcurl.lib应该在安装前缀的lib目录下。如果你用的是 Visual Studio 集成开发环境要在项目属性 → 链接器 → 常规 → 附加库目录里加上这个路径。如果已经确认路径没问题则检查是不是链接了错误位数的库——x64 程序不能链接 x86 的 lib。还有一个比较隐蔽的原因CMake 在生成libcurl.lib时如果开启了CARES它会额外依赖cares.lib而你自己没有把 c-ares 的库加进链接输入导致链接失败。之前提到“核实 libcurl 是否真无 c-ares”其实在链接阶段就能暴露出来——你编了 c-ares但调用工程忘了链接它报错会让你误以为 libcurl 本身有问题。5.2 编出来的 curl 访问 https 报 curl: (35) unexpected eof现象用自编译的 curl 访问某个 https 站点返回curl: (35) error:0a000126:ssl routines::unexpected eof while reading但用系统自带的 curl 或者浏览器访问正常。原因这个错误从 OpenSSL 3 开始频繁出现。字面意思是 TLS 握手过程中服务器突然断开连接。常见原因有几个。一是服务器 TLS 版本太低比如只支持 TLS 1.0而你的 OpenSSL 3 默认不再支持 TLS 1.0/1.1。二是服务器要求 SNI而你的请求没有正确设置 Host 头或 SNI 扩展导致服务器直接 abort。三是客户端与服务器之间有一个中间设备如旧的负载均衡器不兼容 OpenSSL 3 的某些扩展。四是服务器端实际关闭了连接但客户端没收到 close_notify这是协议异常不过常见于服务器配置问题。解决先用curl -v看握手过程确认 ClientHello 里的 TLS 版本。如果是 TLS 版本问题给 curl 显式加--tlsv1.2 --tls-max 1.2或者编译时把 OpenSSL 的安全级别调低一点。如果你用的是 Schannel这个错误的表现往往不是 unexpected eof而是schannel: server closed abruptly。热词里那个curl 56 schannel: server closed abruptly就是同类问题常见于某些只支持 TLS 1.0 的老服务器。解决方式是设置--tlsv1.0或--tls-max 1.0但也要权衡安全风险。还有一个常见隐含问题你用静态编译的 curl 时OpenSSL 配置的 CA 路径可能不对导致服务器发出异常关闭后 curl 无法正确校验。可以先加-k临时跳过证书验证确认握手是否成功如果加了-k正常那就是证书链问题。5.3 c-ares 死活编不进去先确认它是不是真的被编进了 libcurl现象在 CMake 里设置了-DUSE_ARESON编译过程也没有报错但curl -V输出的 Features 列表里没有c-ares解析行为仍是同步的。原因CMake 查找 c-ares 时依赖find_package(CARES)如果它找不到cares-config.cmake或libcares.pc就会静默回退到系统解析器而且不给警告。很多人以为设了USE_ARESON就代表启用实际上这个参数只是“尝试”启用。真正的判定要看 CMake 输出的日志里有没有CARES_FOUND为真。libcurl 源码树里确实没有 c-ares 的实现代码这是设计如此——你需要先单独编好 c-ares并把它的 include 和 lib 路径传给 libcurl。解决先在本地编译 c-arescmake .. -DCMAKE_INSTALL_PREFIX/opt/cares make make install然后回到 libcurl 构建显式指定-DCARES_INCLUDE_DIR/opt/cares/include \ -DCARES_LIBRARY/opt/cares/lib/libcares.a \ -DUSE_ARESON编完后用curl -V查看 Features。如果有c-ares字样才是真的编进去了。同样如果你用 vcpkg 安装c-ares那 CMake 的find_package可能会优先找到 vcpkg 的安装路径就变成自动的了但前提是你要在 CMake 里加-DCMAKE_TOOLCHAIN_FILE/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake。5.4 老系统比如 Windows 7上 TLS 握手失败Schannel 与 OpenSSL 的表现差异现象同一个 curl.exe在 Win10 上访问 https 一切正常拷到 Windows 7 上就报证书错误或者unexpected eof。原因Windows 7 自带的 Schannel 默认不启用 TLS 1.2 中的某些加密套件而且系统证书库的根证书更新也没有 Win10 勤快。如果你编 curl 时用的是 Schannel那么 TLS 行为就被系统限制死了。如果编的是 OpenSSL则问题通常出在静态编译时 OpenSSL 引用的/etc/pki或 Windows 上的 CA 路径不存在导致证书校验失败。解决如果你必须支持 Windows 7两条路。一是继续用 Schannel但要求目标机器安装相应的 KB 更新比如 KB3140245 启用 TLS 1.2二是在编译时改用 OpenSSL并随 zip 包附带一个ca-bundle.crt用--cacert ca-bundle.crt指定证书文件。第二种方案更可控因为你可以自己决定信任哪些根证书并及时更新。实际交付的时候我会把 OpenSSL 的certs目录打包成curl-ca-bundle.crt并在说明文档里写明“如果遇到证书不受信任请使用 --cacert 参数”。5.5 编译产物体积大一倍调试符号和 ZLIB 的影响现象编出来的 curl.exe 有 8MB而官方 Release 只有不到 2MB。或者 curl.exe 在没有任何额外参数时访问本地文件的速度奇慢。原因一是 CMake 的CMAKE_BUILD_TYPEDebug或没有显式指定 Release会导致编译选项为/Od并带上完整调试符号二是 OpenSSL 静态库如果也是 Debug 编译会把大量的符号表编进最终产物三是 ZLIB 没有启用导致 curl 无法解压 gzip 响应既增加网络传输时间也影响压缩日志的解析四是可能意外启用了CURL_DEBUG宏把内部调试日志编进去了。解决编译时刻意加-DCMAKE_BUILD_TYPERelease并且在 OpenSSL 编译时也保持一致的 Release 配置。如果还想再压缩可以用strip工具Windows 上是strip.exe随 MinGW 或 LLVM 提供删除不需要的符号表信息strip curl.exe对于 OpenSSL 静态库建议用/OPT:REF链接优化去掉未引用的函数。在做 zip 包之前先检查一下curl -V输出的Release-Debug反映。如果字符串里带debug说明配置没走对。ZLIB 方面如果你用-DUSE_ZLIBOFFcurl发送带Accept-Encoding: gzip的请求后body 会是乱码因为 libcurl 不解压。这不算 bug但会让使用者误以为下载的文件损坏。所以我的默认建议是压缩功能务必打开哪怕只是静态 zlib。6. 最后的验证与打包技巧让 curl.zip 拿出去就能用编译结束不等于可以交付。我自己的习惯是先把 zip 里的 curl.exe 解压到一个临时目录然后在命令行里执行三组验证。第一组验证版本和特性curl -V看输出里的 Features 是否包含你想要的SSL、Schannel或OpenSSL以及是否意外多出c-ares。第二组验证实际请求curl.exe -s https://www.baidu.com -o nul -w http_code:%{http_code}\n在 Windows 命令行里nul相当于丢弃输出。观察返回的 http_code 是否为 200以及是否报 SSL 错误。第三组验证证书链curl.exe -I https://example.com如果提示证书过期或不受信任检查是不是 CA 证书没找对。带 OpenSSL 静态编译的 curl 一般需要--cacert或者把证书放在编译时指定的路径。打包时的一个小技巧是把curl -V的完整输出写进说明.txt这样版本信息不会丢。文件结构上我一般把不同平台放入不同的目录curl.zip win64\ curl.exe libcurl.dll # 动态方案 README.txt linux-x64\ curl android-arm64\ libcurl.a include\这样同一个 zip 就能覆盖“libcurl 跨平台编译”的全部交付场景。不过要注意zip 包里的可执行文件在 Windows 下要防杀毒软件误报尤其是动态编译且带运行库的情况。我遇到过把 vcruntime140.dll 一起打包时某款安全软件直接隔离 curl.exe 的案例。后来改成把运行库安装程序单独放外链而不是塞进 zip 里问题就消失了。收个尾我每次编译完 curl 都会用curl.exe -w %{time_total} -o /dev/null -s https://www.iana.org/help/example-domains做一次延迟测试感受不同 TLS 后端带来的握手耗时差异。这也让我慢慢养成一个习惯——写构建脚本时把 TLS 后端、CA 路径、协议裁剪几个关键项作为输入参数暴露出来而不是藏在 CMakeCache 里。日后回溯“这个 curl.zip 是拿什么配置编出来的”看一眼脚本就全明白了。这套思路不仅对 libcurl 适用对任何需要跨平台分发的网络工具都成立。希望这篇笔记能帮你少走几步弯路。本文还有配套的精品资源点击获取
返回列表