VS2017编译64位libssh2库:OpenSSL与CMake避坑指南
发布时间:2026/10/15 18:11:25 锦皓数字建站

简介面向Windows 64位开发需求的libssh2预编译资源包解决了在VS2017环境中自行配置CMake、OpenSSL依赖并手动编译的繁琐问题。包内已生成可直接链接的64位libssh2静态库配套完整的头文件集合及OpenSSL相关声明并附上两个64位运行依赖dll与一个验证调用方式的示例程序。整体共115个文件以109个头文件为主辅以3个lib库文件、2个dll和1个cpp文件压缩包仅2.14MB轻量且便于分发给团队成员适合在VS2017 x64工程中快速接入SSH2的会话建立、SFTP文件传输、远程命令执行与端口转发等能力。已有1513人浏览学习兼具上手即用和源码排查参考价值对需要集成libssh2但不希望从零研究编译链路的C/C开发者尤其友好。1. 自己编译 libssh2 Windows 64 位库可能比想象中更折腾当 SSH/SFTP 功能突然要落地到某个 VS2017 的 x64 服务端项目时我首先做的并不是打开源码而是想找一个现成的 libssh2 动态库直接 DLL 导入。结果很快被现实敲醒能找到的预编译产物要么是 32 位要么是用旧版 VS 生成、运行时和当前工程对不上要么干脆来源不明、没人对安全性负责。既然现成的不能直接用那就只能自己动手用 VS2017 编译一条 64 位 libssh2 库出来。这篇笔记把完整过程和几个关键坑记录下来OpenSSL 依赖怎么选、CMake 参数怎么配、编完怎么验证以及最常见的“链接失败”到底在闹什么。适合手头有 Windows 服务、工具程序需要走 SSH/SFTP又不想被第三方预编译包绑架的开发者。2. 准备与依赖选对工具链和 OpenSSL后面才不用返工2.1 编译环境组合VS2017 CMake 是当前最稳的路径libssh2 的源码里自带一份 CMakeLists.txt这是官方明确支持的构建方式。相比之下用 NMake 或者直接打开源码里的 .vcxproj 手工改配置在 VS2017 上并不省事因为 libssh2 的 CMake 脚本会处理不少平台相关的宏定义比如LIBSSH2_WIN32、LIBSSH2_OPENSSL、LIBSSH2_HAVE_ZLIB这些手动维护很容易漏。我习惯的做法是在“开发者命令提示符 for VS2017”里跑 CMake而不是用普通的控制台窗口这样可以确保编译器环境变量、头文件搜索路径都是 VS2017 那一套不会混进其它版本的 MSVC 工具链。CMake 版本建议至少 3.9因为只有 3.9 以上才支持-A x64这种生成器平台参数而 VS2017 自带的 CMake 往往版本偏旧最好单独装一个新版 CMake。如果机器上同时装了 VS2015、VS2017、VS2019一定要在 CMake 里显式指定生成器为Visual Studio 15 2017否则 CMake 默认会用系统里最新版本的那套生成器产物可能带上 VS2019 的 v142 工具集和你的 VS2017 工程无法匹配。2.2 OpenSSL 依赖准备先决定静态还是动态libssh2 的加密、签名、密钥交换等核心能力都来自 OpenSSL所以编译前必须先准备好 OpenSSL 库文件。OpenSSL 自己也要经过编译或安装包部署这里有几个选择用 vcpkg 安装、用网上的预编译安装包、或者自己编译 OpenSSL。对于大多数项目我会选择预编译安装包或者 vcpkg因为自己编 OpenSSL 的时间成本远高于编 libssh2。下载安装 OpenSSL 时一个最容易忽略的细节是安装界面里询问“Copy OpenSSL DLLs to ...”这时候要选“The OpenSSL binaries directory”或者一个你熟悉的自定义目录不要选“Windows system directory”否则后续定位库文件会出现路径混乱。安装完成后确认目录结构里包含 include、lib 两个子目录如果是 64 位版本理论上安装路径会类似C:\OpenSSL-Win64。注意这个目录名里写的是 Win64不一定代表库就是 64 位的有的第三方安装包也把 64 位装到这个名字下但本质上判断标准是看 lib 目录里的 .lib 文件名以及实际编译时架构。更可靠的检查方式是打开“Visual Studio 2017 的 x64 本机工具命令提示符”直接运行dumpbin /headers C:\OpenSSL-Win64\lib\libssl.lib能看到机器头里写的是x64才算稳。另外决定好是要静态链接 OpenSSL 还是动态链接。如果 libssh2 以静态库方式产出OpenSSL 也尽量用静态库.lib形式这样最终的主程序只需要链接 libssh2.lib 和 openssl 的 lib不需要额外分发 DLL。如果用动态 OpenSSL那么不仅编译期要有 import library运行期还得带上 libcrypto-1_1-x64.dll 和 libssl-1_1-x64.dll部署时容易忘。这个选择直接影响 CMake 参数我在后面章节会给出两组写法。2.3 不想引入 OpenSSLWinCNG 后端是备胎如果在你的场景里只是连内网服务器做 SFTP 传输对算法要求固定、也不在乎跨平台的密码学特性那可以考虑用 Windows 自带的 CNGCryptography API: Next Generation 作为加密后端。libssh2 在 CMake 里允许指定CRYPTO_BACKEND候选包括OpenSSL、WinCNG、mbedTLS、Libgcrypt。选WinCNG的话编译出来的 libssh2 库不依赖 OpenSSL 的 DLL 和 lib而是直接调用 Windows 系统的 bcrypt.dll这对部署来说最省事少了两三个 DLL 要跟着拷贝。但代价是 WinCNG 后端支持的算法范围不如 OpenSSL 广如果远端服务器用的是比较小众的 KEX 算法或密码套件可能握手阶段就会失败。我的建议是仅在目标服务器可控、算法明确的前提下走 WinCNG否则老老实实用 OpenSSL 后端。3. 从源码到 64 位 libssh2 库CMake 配置与编译实战3.1 获取源码与目录准备先从 libssh2 官方仓库的 release 页下载最新稳定版源码包解压后目录结构里应该至少看到src/、include/、CMakeLists.txt、docs/。注意如果你下载的是 git 仓库的 master 分支且没有执行过 submodule 更新可能缺少 mbedTLS 之类的第三方子模块编译时会报目录不存在。所以要用 release tar.gz 包而不要用 git clone 后直接编译。解压后我习惯在源码根目录建一个独立的build文件夹所有 CMake 中间产物都放在里面源码目录保持干净。这一步在 Windows 上尤其重要——VS2017 的中间目录和最后生成的 .sln 都在 build 里后续想重新配置时直接删掉 build 文件夹即可不需要对源码做任何清理。3.2 CMake 配置命令静态库 OpenSSL 静态版下面是我实测可行的一组命令目标是产出 64 位静态库并且 OpenSSL 也按静态链接处理cd libssh2-1.11.0 mkdir build cd build cmake .. -G Visual Studio 15 2017 -A x64 ^ -DCMAKE_INSTALL_PREFIXD:/thirdparty/libssh2-x64 ^ -DBUILD_SHARED_LIBSOFF ^ -DBUILD_EXAMPLESOFF ^ -DBUILD_TESTINGOFF ^ -DOPENSSL_ROOT_DIRC:/OpenSSL-Win64 ^ -DOPENSSL_USE_STATIC_LIBSTRUE这段命令里-G Visual Studio 15 2017指定生成器-A x64指定 64 位目标平台。BUILD_SHARED_LIBSOFF表示生成静态库最终会得到.lib而不是.dll。BUILD_EXAMPLES和BUILD_TESTING关掉避免编译一些用不到的 demo 和测试文件缩短编译时间。OPENSSL_ROOT_DIR告诉 CMake 去哪里找 OpenSSL 的安装根目录OPENSSL_USE_STATIC_LIBS是让 CMake 优先选用静态版的 OpenSSL 库文件。如果你用的是动态 OpenSSL这一项改成FALSE同时要把编译选项里的运行库切换成/MD否则 VC 运行时会冲突。CMake 在配置阶段如果报Could NOT find OpenSSL绝大多数情况是OPENSSL_ROOT_DIR指错位置或者 OpenSSL 的版本目录结构和预期的 include/openssl/ssl.h 对不上。3.3 编译与安装产物去哪了配置成功后执行编译和安装两步cmake --build . --config Release cmake --install . --config Release第一条命令会调起 MSBuild 编译整个解决方案。如果是初次编译大概一分多钟就能完成libssh2 本身代码量不大。第二条命令把头文件、静态库、CMake 配置文件安装到D:/thirdparty/libssh2-x64。完成后检查这个目录D:/thirdparty/libssh2-x64/ include/ libssh2.h libssh2_publickey.h libssh2_sftp.h lib/ libssh2.lib lib/cmake/libssh2/ libssh2Config.cmake如果你的BUILD_SHARED_LIBS设成了ON那么lib/目录里会同时出现libssh2.dll和libssh2.lib其中.lib是导入库实际逻辑在.dll里。而静态库模式下只有一个libssh2.lib这个文件里已经包含了所有 libssh2 的代码逻辑但没有把 OpenSSL 的函数塞进来所以最终主程序链接时仍然需要指向 OpenSSL 的 lib 文件。安装目录里的libssh2Config.cmake很重要以后你在其他 CMake 工程里可以直接find_package(libssh2)不用手动指定头文件和库路径。3.4 常用 CMake 缓存变量查漏有时候配置阶段表面上没有报错但编出来的库行为不太对比如 SFTP 功能编译进去了但压缩传输无效。这是因为没有启用 zlib。libssh2 支持对 SSH 通道数据做 zlib 压缩默认不开。需要额外指定-DZLIB_LIBRARYD:/thirdparty/zlib/lib/zlibstatic.lib ^ -DZLIB_INCLUDE_DIRD:/thirdparty/zlib/include这个选项不是必须的。如果你不关心传输压缩完全可以跳过影响面很小。我一般会上来先把BUILD_SHARED_LIBSOFF和CRYPTO_BACKENDOpenSSL作为固定前提再根据项目需要决定要不要 zlib。修改 CMake 配置后不需要删除 build 目录直接重新跑一遍cmake ..加上新参数CMake 会增量更新缓存变量。4. 避坑从配置到链接五个高频问题的现象、原因与解法4.1 现象CMake 配置阶段提示 “Could NOT find OpenSSL”这是最常见的开局问题。明明 OpenSSL 装好了CMake 就是找不到。原因通常是OPENSSL_ROOT_DIR没有指到正确位置或者 OpenSSL 安装包里的 include 目录层级不是 CMake 预期的形态。CMake 的 FindOpenSSL 模块默认会去OPENSSL_ROOT_DIR/include下找openssl/ssl.h如果安装包目录里只有include/ssl.h而没有include/openssl/ssl.h就识别不成功。解决方法是直接显式给出头文件和库文件路径绕过搜索逻辑-DOPENSSL_INCLUDE_DIRC:/OpenSSL-Win64/include ^ -DOPENSSL_SSL_LIBRARYC:/OpenSSL-Win64/lib/libssl.lib ^ -DOPENSSL_CRYPTO_LIBRARYC:/OpenSSL-Win64/lib/libcrypto.lib这些变量一旦显式指定FindOpenSSL 就不再依赖自动探测理论上最不容易出错。三个路径要确保指向同一次安装的产品不要混用两个版本的 OpenSSL。4.2 现象生成解决方案时提示 “同时指定了 /GR 和 /GR-”这个报错多见于 libssh2 源码目录下残留了旧版编译中间文件或者 build 目录不是全新创建的。VS2017 打开.sln时会读取每个 vcxproj 里的Runtimelibrary设置如果同一个项目里既有MultiThreadedDebug又有MultiThreadedDLL的配置残留MSBuild 就会炸。解决方式是删除 build 目录从头再来。我写过一次教训为了省时间在原有 build 目录里反复切 Debug/Release、静态/动态最后 MSBuild 命令能跑但生成出来的库冲突白白排查了两小时。从那以后只要 CMake 配置的开关发生大变化我二话不说先把 build 整个删掉。4.3 现象链接报 LNK2038 或者 LNK2005集中在_BEGIN_SINGLE_THREAD_USE等 CRT 符号上这个报错十有八九是运行时库不匹配造成的。libssh2 编译时用的/MT或/MD跟你主程序编译时用的不一致。LNK2038的提示信息里会直接写明“检测到 RuntimeLibrary 不匹配”这是 MSVC 在链接时做的安全检查。解决办法是让 libssh2 和主程序统一用同一种运行时开关如果主程序用的/MD那么编译 libssh2 时 CMake 也要走动态运行时。但 CMake 没有直接提供“运行时模式”的开关正确做法是在 CMake 配置阶段手动指定全局编译选项-DCMAKE_C_FLAGS_RELEASE/MD -DCMAKE_CXX_FLAGS_RELEASE/MD当然前提是 OpenSSL 那边也必须是/MD编译出来的。市场上很多预编译 OpenSSL 安装包同时提供libssl64MT.lib和libssl64MD.lib两个版本选错就会一路炸到链接。看清文件名里的 MT/MD 后缀再下手。4.4 现象编译成功但libssh2_init(0)返回 -1这个属于运行时错误编译和链接都过了却在程序启动时失败。原因通常是 libssh2 库没被正确加载或者在动态库模式下找不到libssh2.dll。还有一种隐蔽情况你链接的是静态 libssh2但 OpenSSL 用的是动态 DLL而程序启动时 OpenSSL 的 DLL 不在 PATH 环境变量里。解决方法是先把 OpenSSL 的 DLL 复制到 exe 所在目录或者直接在代码里用SetDllDirectory指定 DLL 路径。我见过有人把这个当成 libssh2 初始化失败排查半天实际上根本是 OpenSSL DLL 没找到。用 Dependecy Walker 或 Process Explorer 看一眼加载的 DLL 列表五分钟就能定位。4.5 现象64 位工程链接上了 32 位 OpenSSL 库这个最隐蔽因为 CMake 不一定报错。如果OPENSSL_CRYPTO_LIBRARY指向的 lib 文件是 32 位版本链接器在生成 64 位程序时会报LNK1112: module machine type x86 conflicts with target machine type x64。原因就是下载的 OpenSSL 安装包虽然是给 x64 系统装的但里面同时包含了 32 位和 64 位两套库你手动指定的路径恰好指向了lib/VC/static/32这样的子目录。解决方法是严格检查路径里的x64关键字并用dumpbin /headers确认机器类型。这一步检查最好放到刚拿到 OpenSSL 安装包就做不要等到链接出错再回头找。5. 验证与集成写一个最小的 SSH 连接程序把库真正用起来5.1 在 VS2017 工程里配置库依赖打开你的主工程进入“项目属性 - VC 目录”在“包含目录”里加上D:/thirdparty/libssh2-x64/include和C:/OpenSSL-Win64/include在“库目录”里加上D:/thirdparty/libssh2-x64/lib和C:/OpenSSL-Win64/lib。然后在“链接器 - 输入 - 附加依赖项”里填写libssh2.lib、libssl.lib、libcrypto.lib。静态链接时顺序通常不影响但如果是动态 OpenSSL建议先写 libssh2.lib再写 libssl.lib 和 libcrypto.lib避免某些符号解析顺序问题。另外如果主工程用了预编译头记得在包含 libssh2.h 前把与 OpenSSL 相关的警告级别调整一下否则第三方头文件可能带来一堆 C4996 警告。5.2 用最小程序验证库是否可用写一个非常小的控制台程序完成 SSH 会话初始化和版本号获取#include stdio.h #include libssh2.h int main() { int rc libssh2_init(0); if (rc ! 0) { printf(libssh2_init failed: %d\n, rc); return 1; } const char *ver libssh2_version(0); printf(libssh2 version: %s\n, ver ? ver : unknown); libssh2_exit(); return 0; }这段代码的核心就三件事初始化全局状态、取版本号、退出时释放全局资源。libssh2_init(0)的参数传 0 表示默认初始化不做额外的内存分配策略调整。如果这里返回非 0说明库本身加载失败或内部初始化异常重点排查 DLL 路径如果连版本号都打印不出来说明头文件和库版本不一致的概率极大。只有这个最小程序跑通再去接 SFTP 读写、公钥认证这些复杂功能不然问题叠在一起很难定位。5.3 一个值得养成的习惯编译信息留存从那以后我每编译一个第三方库都会在安装目录里放一个build_info.txt记录 CMake 版本、编译命令、OpenSSL 路径、静态/动态开关。刚开始觉得多此一举直到三个月后另一个项目需要重新编译同样版本的 libssh2一问三不知、只能靠反查 CMakeCache.txt 猜参数才意识到这些信息有多值钱。这个小习惯帮我省下大量重复排查时间希望你也能用得上。如果你的场景和我类似——VS2017、x64、不想碰第三方预编译包——可以直接按本文的流程走一遍配置时注意我标红的那几个变量即可。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。