简介:面向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 不想引入 OpenSSL?WinCNG 后端是备胎
如果在你的场景里,只是连内网服务器做 SFTP 传输,对算法要求固定、也不在乎跨平台的密码学特性,那可以考虑用 Windows 自带的 CNG(Cryptography 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_PREFIX="D:/thirdparty/libssh2-x64" ^ -DBUILD_SHARED_LIBS=OFF ^ -DBUILD_EXAMPLES=OFF ^ -DBUILD_TESTING=OFF ^ -DOPENSSL_ROOT_DIR="C:/OpenSSL-Win64" ^ -DOPENSSL_USE_STATIC_LIBS=TRUE这段命令里,-G "Visual Studio 15 2017"指定生成器,-A x64指定 64 位目标平台。BUILD_SHARED_LIBS=OFF表示生成静态库,最终会得到.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_LIBRARY="D:/thirdparty/zlib/lib/zlibstatic.lib" ^ -DZLIB_INCLUDE_DIR="D:/thirdparty/zlib/include"这个选项不是必须的。如果你不关心传输压缩,完全可以跳过,影响面很小。我一般会上来先把BUILD_SHARED_LIBS=OFF和CRYPTO_BACKEND=OpenSSL作为固定前提,再根据项目需要决定要不要 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_DIR="C:/OpenSSL-Win64/include" ^ -DOPENSSL_SSL_LIBRARY="C:/OpenSSL-Win64/lib/libssl.lib" ^ -DOPENSSL_CRYPTO_LIBRARY="C:/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、不想碰第三方预编译包——可以直接按本文的流程走一遍,配置时注意我标红的那几个变量即可。希望帮到你。
本文还有配套的精品资源,点击获取