使用 vcpkg 为OpenHarmony(鸿蒙PC)构建 OpenSSH 命令行工具
文章摘要(148字): 本文介绍在鸿蒙PC(OHOS arm64)通过vcpkg构建OpenSSH的实践方案。OpenSSH提供SSH协议套件(ssh/scp/sftp等),vcpkg简化了交叉编译流程,自动处理openssl/zlib依赖。重点解决OHOS适配的8个技术难点:包括系统标识补丁、绝对路径配置、shadow禁用等。安装后生成的可执行文件位于tools/openssh/bin目录,支持
本文面向需要构建可运行在OpenHarmony或 鸿蒙PC(arm64-ohos 等 triplet) 上的openssh命令行工具的开发者。通过使用
vcpkg的方式构建。同时说明 OpenSSH 是什么、为何用 vcpkg构建、如何构建、产物在哪、以及本 port 在适配过程中处理过的典型问题。
vcpkg (针对 C++ 库的包管理):虽然它最初是c/c++的包管理器,但它的 triplet 机制(如当前的 arm64-ohos)本质上也是一种轻量级的交叉编译配置框架。
Qt 团队为鸿蒙做了 vcpkg 扩展,这套 fork 的改动刻意保持 小而聚焦,分支地址如下。
适配鸿蒙的vcpkg分支地址:https://git.qt.io/jobor/vcpkg.git
关于vcpkg更详细的安装及使用,参见博文:
《使用 vcpkg 为鸿蒙(HarmonyOS / OHOS)下载与安装三方库实践指南》
1. OpenSSH 是什么
OpenSSH 是 OpenBSD 项目移植到多平台的 SSH 协议套件,提供安全远程登录、文件传输与密钥管理等功能。日常所说的「SSH 客户端」通常包括:
| 组件 | 作用 |
|---|---|
ssh |
远程 shell、端口转发、跳板 |
scp / sftp |
基于 SSH 的文件复制与交互式文件传输 |
ssh-keygen |
生成与管理主机密钥、用户密钥 |
ssh-agent / ssh-add |
代理私钥,减少重复输入口令 |
ssh-keyscan |
批量采集主机公钥指纹 |
sshd |
SSH 服务端(守护进程) |
sftp-server |
SFTP 子系统(常由 sshd 按需拉起) |
Portable OpenSSH(openssh-portable)是面向 Linux、BSD 及各类类 Unix 环境的源码发行版,使用 GNU Autotools(configure + make),与 Windows 上常见的 MSVC 工程形态不同。
openSSH的github仓:https://github.com/openssh/openssh-portable
openSSH主页地址:https://www.openssh.org/
2. 为什么在 OHOS 上用 vcpkg 构建 OpenSSH
因为简单。vcpkg上本来就支持上千个开源库,那么OpenSSH依赖的openssl和zlib库本来就有了。只需要新增加支持下OpenSSH的命令行即可。且移植符合通用的vcpkg的规范,熟悉cmake语法的移植起来也很简单了。
鸿蒙设备或 SDK 环境中,常见需求包括:
- 在 开发机(多为 x86_64 Linux) 上 交叉编译 arm64 目标;
- 与 OpenSSL、zlib 等依赖版本 与工程其它库对齐;
- 用 同一套 vcpkg triplet / 工具链元数据 管理依赖与产物路径。
vcpkg 通过 port(vcpkg.json + portfile.cmake)描述下载、配置、安装步骤;对 Autotools 项目通常走 vcpkg_configure_make / vcpkg_install_make,并与 ports/vcpkg-make 中的默认路径约定(例如把可执行文件安装到 tools/<port>/bin)集成。
3. 本仓库 openssh port 概要
仓库地址: https://gitcode.com/qq8864/vcpkg
| 项目 | 说明 |
|---|---|
| 上游版本 | OpenSSH 9.9p2(portable tarball) |
| 清单版本字段 | 使用 version-string(9.9p2 含 p,非 semver) |
| 主要依赖 | openssl、zlib;可选 feature fido2(libfido2) |
平台表达式 supports |
支持 Linux/macOS/MinGW 等;并显式支持 ohos(` |
| 构建系统 | Autotools(无 CMake 顶层工程) |
鸿蒙相关适配要点(均在 portfile.cmake 与补丁中体现):
-
config.sub不认识linux-ohos
通过补丁ohos-config-sub.patch在config.sub中增加对ohos/linux-ohos*的识别(与 tripletaarch64-unknown-linux-ohos一类配置一致)。 -
交叉工具链需要显式
--target
在VCPKG_TARGET_IS_OHOS时通过vcpkg_cmake_get_vars读取VCPKG_DETECTED_CMAKE_C_COMPILER_TARGET等,并追加到VCPKG_C_FLAGS/VCPKG_CXX_FLAGS,与 openssl、libpng 等 port 在 OHOS 上的思路一致。 -
--sysconfdir须为绝对路径
OpenSSH 的configure不接受相对--sysconfdir,使用${CURRENT_PACKAGES_DIR}/etc/ssh。 -
Shadow /
getspnam
OHOS 类环境可能出现 有shadow头文件但无可用getspnam的情况,对 OHOS 使用--without-shadow(定义DISABLE_SHADOW)。 -
loginrec.c中utmpx笔误
上游在#else分支误写&ut应为&utx,补丁fix-loginrec-utmpx-typo.patch。 -
安装阶段
strip/check-config
交叉编译时宿主strip无法处理目标 ELF;默认make install会跑check-config(执行sshd -t),不适合交叉环境。采用install-nokeys跳过check-config/host-key,并在VCPKG_CROSSCOMPILING时加--disable-strip。 -
vcpkg_copy_tools路径
Autotools 默认把二进制装到tools/openssh/bin与tools/openssh/sbin(经 DESTDIR 整理后),与vcpkg_copy_tools默认查找的packages/.../bin不一致;port 中按实际目录vcpkg_copy_tool_dependencies,必要时用SEARCH_DIR从扁平bin/迁出。 -
仅工具、无头文件
在portfile.cmake开头 设置VCPKG_POLICY_EMPTY_INCLUDE_FOLDER,避免 post-build 对空include误报。
4. 环境准备
4.1 必备条件
- 已克隆并引导好的 vcpkg(能执行
./vcpkg install)。 - 针对 OHOS 的 CMake toolchain / triplet(例如
arm64-ohos),且openssl、zlib等依赖能在同一 triplet 下成功安装。 - 若使用 OHOS SDK 的 Clang,通常需设置
OHOS_SDK_ROOT等(与 triplet、文档一致;具体以你方工程为准)。
4.2 依赖端口(由 vcpkg.json 声明)
openssl、zlib:始终需要。vcpkg-cmake-get-vars(host: true,platform: "ohos"):仅在配置 OHOS 目标时参与,用于读取编译器--target等变量。
4.3 移植步骤
默认的vcpkg仓库中只有libssh或libssh2等相关的库,并没有openssh。因为openssh是一组命令行工具(ssh、scp、sftp等),而vcpkg主要是用来构建库和提供c/c++的包管理。但是它也可以用来构建二进制可执行程序。
1.clone下来vcpkg的仓库后,在ports文件夹下新建openssh的目录。

2.开始编写移植openssh相关的文件:
vcpkg.json
{
"name": "openssh",
"version-string": "9.9p2",
"description": "OpenSSH suite: ssh(1), scp(1), sftp(1), ssh-keygen(1), ssh-agent(1), sshd(8), and related tools (portable release).",
"homepage": "https://www.openssh.com/",
"license": null,
"supports": "(!uwp & !android & !ios & !emscripten & (!windows | mingw)) | ohos",
"dependencies": [
"openssl",
"zlib",
{
"name": "vcpkg-cmake-get-vars",
"host": true,
"platform": "ohos"
}
],
"features": {
"fido2": {
"description": "Link against libfido2 for built-in U2F/FIDO security key support in ssh/sftp tools.",
"dependencies": [
"libfido2"
]
}
}
}
portfile.cmake文件
# Tools-only port; no public headers to install.
set(VCPKG_POLICY_EMPTY_INCLUDE_FOLDER enabled)
vcpkg_download_distfile(
ARCHIVE
URLS
"https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${VERSION}.tar.gz"
"https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${VERSION}.tar.gz"
FILENAME "openssh-${VERSION}.tar.gz"
SHA512 4c6d839aa3189cd5254c745f2bd51cd3f468b02f8e427b8d7a16b9ad017888a41178d2746dc51fb2d3fec5be00e54b9ab7c32c472ca7dec57a1dea4fc9840278
)
vcpkg_extract_source_archive(
SOURCE_PATH
ARCHIVE "${ARCHIVE}"
PATCHES
ohos-config-sub.patch
fix-loginrec-utmpx-typo.patch
)
if(VCPKG_HOST_IS_WINDOWS)
vcpkg_find_acquire_program(PERL)
get_filename_component(PERL_EXE_PATH "${PERL}" DIRECTORY)
vcpkg_add_to_path("${PERL_EXE_PATH}")
endif()
vcpkg_find_acquire_program(PKGCONFIG)
get_filename_component(PKGCONFIG_DIR "${PKGCONFIG}" DIRECTORY)
vcpkg_add_to_path("${PKGCONFIG_DIR}")
# OHOS: OpenHarmony toolchains often require an explicit Clang --target so
# configure-time compile/link probes resolve sysroot headers and libs
# correctly (same approach as ports/openssl/unix and ports/libpng).
if(VCPKG_TARGET_IS_OHOS)
vcpkg_cmake_get_vars(cmake_vars_file)
include("${cmake_vars_file}")
string(APPEND VCPKG_C_FLAGS " --target=${VCPKG_DETECTED_CMAKE_C_COMPILER_TARGET}")
string(APPEND VCPKG_CXX_FLAGS " --target=${VCPKG_DETECTED_CMAKE_CXX_COMPILER_TARGET}")
# OpenSSL 3.0 deprecations in upstream portable sources (noise only).
string(APPEND VCPKG_C_FLAGS " -Wno-deprecated-declarations")
endif()
# OpenSSH's configure rejects a relative --sysconfdir; it must be absolute.
vcpkg_list(SET configure_opts
"--with-ssl-dir=${CURRENT_INSTALLED_DIR}"
"--with-zlib=${CURRENT_INSTALLED_DIR}"
"--without-openssl-header-check"
"--sysconfdir=${CURRENT_PACKAGES_DIR}/etc/ssh"
)
# OpenHarmony sysroot may expose shadow-style headers without a usable getspnam;
# --without-shadow defines DISABLE_SHADOW (see configure.ac).
if(VCPKG_TARGET_IS_OHOS)
vcpkg_list(APPEND configure_opts "--without-shadow")
endif()
if("fido2" IN_LIST FEATURES)
vcpkg_list(APPEND configure_opts "--with-security-key-builtin=yes")
endif()
# Cross builds: GNU install -s invokes the host strip(1), which cannot handle
# target ELFs (e.g. arm64-ohos built on x86_64 Linux).
if(VCPKG_CROSSCOMPILING)
vcpkg_list(APPEND configure_opts "--disable-strip")
endif()
set(extra_make_opts "")
if(VCPKG_TARGET_IS_WINDOWS)
list(APPEND extra_make_opts
DETERMINE_BUILD_TRIPLET
USE_WRAPPERS
)
endif()
vcpkg_configure_make(
SOURCE_PATH "${SOURCE_PATH}"
${extra_make_opts}
OPTIONS
${configure_opts}
)
# install-nokeys: install-files + install-sysconf, but not host-key / check-config.
# check-config runs $(DESTDIR)$(sbindir)/sshd -t under DESTDIR staging; that is
# wrong for cross-compiles (host cannot execute the target sshd, and paths may
# concatenate badly when bindir/sbindir are absolute).
vcpkg_install_make(INSTALL_TARGET install-nokeys)
# vcpkg_configure_make defaults bindir/sbindir to ${prefix}/tools/<port>/{bin,sbin}
# (see ports/vcpkg-make/vcpkg_make_common.cmake). After DESTDIR flatten, binaries
# are under tools/<port>/..., not packages/<port>/bin — vcpkg_copy_tools must use SEARCH_DIR.
set(_openssh_bindir "${CURRENT_PACKAGES_DIR}/tools/${PORT}/bin")
set(_openssh_sbindir "${CURRENT_PACKAGES_DIR}/tools/${PORT}/sbin")
if(NOT EXISTS "${_openssh_bindir}/ssh${VCPKG_TARGET_EXECUTABLE_SUFFIX}")
set(_openssh_bindir "${CURRENT_PACKAGES_DIR}/bin")
set(_openssh_sbindir "${CURRENT_PACKAGES_DIR}/sbin")
endif()
set(openssh_bin_tools
ssh
scp
sftp
ssh-add
ssh-agent
ssh-keygen
ssh-keyscan
ssh-pkcs11-helper
ssh-sk-helper
)
set(openssh_sbin_tools
sshd
sshd-session
)
set(_openssh_dest_bin "${CURRENT_PACKAGES_DIR}/tools/${PORT}/bin")
set(_openssh_dest_sbin "${CURRENT_PACKAGES_DIR}/tools/${PORT}/sbin")
if("${_openssh_bindir}" STREQUAL "${_openssh_dest_bin}" AND "${_openssh_sbindir}" STREQUAL "${_openssh_dest_sbin}")
# vcpkg autotools defaults already install into tools/<port>/{bin,sbin}.
vcpkg_copy_tool_dependencies("${_openssh_dest_bin}")
vcpkg_copy_tool_dependencies("${_openssh_dest_sbin}")
else()
vcpkg_copy_tools(
TOOL_NAMES ${openssh_bin_tools}
SEARCH_DIR "${_openssh_bindir}"
DESTINATION "${_openssh_dest_bin}"
AUTO_CLEAN
)
vcpkg_copy_tools(
TOOL_NAMES ${openssh_sbin_tools}
SEARCH_DIR "${_openssh_sbindir}"
DESTINATION "${_openssh_dest_sbin}"
AUTO_CLEAN
)
vcpkg_copy_tool_dependencies("${_openssh_dest_bin}")
vcpkg_copy_tool_dependencies("${_openssh_dest_sbin}")
endif()
# ssh-keysign and sftp-server install to ${prefix}/libexec; already under the
# package root after DESTDIR flatten — only pull in shared-library deps.
if(EXISTS "${CURRENT_PACKAGES_DIR}/libexec")
vcpkg_copy_tool_dependencies("${CURRENT_PACKAGES_DIR}/libexec")
endif()
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/debug/share"
"${CURRENT_PACKAGES_DIR}/share/man"
"${CURRENT_PACKAGES_DIR}/debug/share/man"
"${CURRENT_PACKAGES_DIR}/lib"
"${CURRENT_PACKAGES_DIR}/debug/lib"
"${CURRENT_PACKAGES_DIR}/include"
"${CURRENT_PACKAGES_DIR}/debug/include"
)
vcpkg_copy_pdbs()
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENCE")
5. 构建步骤
在 vcpkg 根目录执行(示例 triplet 为 arm64-ohos):
./vcpkg install openssh:arm64-ohos
可选功能(若 triplet 上 libfido2 可用):
./vcpkg install 'openssh[fido2]:arm64-ohos'
首次或排错时可加 --clean-after-build 清理中间树。
成功时日志末尾会出现类似:
All requested installations completed successfully
如果要删除重新构建,可以:
export OHOS_SDK_ROOT=/root/ohos-sdk/linux/
rm -rf /root/vcpkg/buildtrees/openssh
./vcpkg remove openssh:arm64-ohos
./vcpkg install openssh:arm64-ohos
6. 安装产物路径说明
安装完成后,在 installed/<triplet>/ 下可重点关注:
| 路径 | 内容 |
|---|---|
tools/openssh/bin/ |
ssh、scp、sftp、ssh-keygen、ssh-agent、ssh-add、ssh-keyscan、ssh-pkcs11-helper、ssh-sk-helper 等 |
tools/openssh/sbin/ |
sshd、sshd-session |
libexec/(triplet 根下) |
ssh-keysign、sftp-server(Autotools 默认 libexecdir) |
etc/ssh/(若保留) |
ssh_config、sshd_config、moduli 等模板(由 install-nokeys 中的 install-sysconf 安装) |
说明:install-nokeys 不会在 DESTDIR 安装阶段执行 ssh-keygen -A 生成主机密钥;部署到设备时需按运维规范自行生成 /etc/ssh/ssh_host_* 等。
7. 与「完全成功」相关的校验信息
- 安装成功:以 vcpkg 输出
All requested installations completed successfully为准。 - SPDX 提示:若
vcpkg.json未写 SPDXlicense,vcpkg 可能提示查看各包的copyright;OpenSSH 使用上游LICENCE文件,已通过vcpkg_install_copyright安装到share/openssh/copyright。 - 空
include警告:工具型 port 无公共头文件属正常;应使用VCPKG_POLICY_EMPTY_INCLUDE_FOLDER(变量名须正确),否则 post-build 仍会提示include为空。

8. 常见问题(FAQ)
8.1 config.sub 报错 OS 'ohos' not recognized
已通过 ohos-config-sub.patch 扩展 config.sub;请确认 vcpkg_extract_source_archive 的 PATCHES 中包含该补丁且为最新 port。
8.2 getspnam / xcrypt.c 编译失败
在 OHOS 上使用 --without-shadow;若你自行去掉该选项,需保证 sysroot 中 shadow API 完整且与探测一致。
8.3 strip 无法识别 ELF / install-files 失败
交叉编译时启用 --disable-strip,并避免使用默认 make install 中的 check-config(本 port 使用 install-nokeys)。
8.4 vcpkg_copy_tools 找不到 ssh
Autotools 在 vcpkg 下默认安装到 tools/openssh/bin,不是 bin/;port 已按实际路径处理 vcpkg_copy_tool_dependencies 与可选 vcpkg_copy_tools。
8.5 为何不用 MSVC 的 x64-windows?
上游 portable 以 Autotools + POSIX 为主;x64-windows(MSVC) 通常不在本 port 的 supports 范围内;在 Windows 上可考虑 MinGW triplet 或系统自带的 OpenSSH 分发渠道。
9. 真机验证
在鸿蒙PC的容器环境中验证方法:
低成本搭建鸿蒙PC运行环境:基于 Docker 的 x86_64 服务器

因为在我的测试阶段,库(so文件)和程序(bin)都在同一个文件夹下,为了使二进制可执行程序能够顺利找到库,需要使用一下指令配置下临时环境:
export LD_LIBRARY_PATH=$(pwd)
当运行 ssh 这种程序时,它需要加载 libcrypto.so(OpenSSL)和 libz.so(zlib)库。如果系统里有就直接去系统里找了。默认只会去系统的固定的“公家仓库”(如 /lib 或 /usr/lib)找。 正式发布产品时,通常不需要这么麻烦。如果鸿蒙PC环境已经有了OpenSSL的库,是可以直接运行的。
或者使用 RPATH(嵌入式最常用),在编译阶段,直接把库的路径“刻”进程序里。做法:在编译参数里加上 -Wl,-rpath,' O R I G I N / . . / l i b ′ 。程序运行时会自己找身边的库。 ORIGIN/../lib'。程序运行时会自己找身边的库。 ORIGIN/../lib′。程序运行时会自己找身边的库。ORIGIN 就代表程序自己所在的目录,不管你把程序装到哪,它都能定位到附近的库。
或者把 .so 文件放入系统标准目录,直接拷贝到板子的 /usr/lib 或 /lib 下。这是最省事的,系统启动时会自动扫描这些地方,程序拿起来就能跑。
使用SSH命令远程登录一下后台的服务器试试:
测试成功!
10. 小结
- OpenSSH 是工业界事实标准的 SSH 套件;portable 版本适合 类 Unix / OHOS 的 Autotools 构建链。
- 使用 vcpkg 可在 统一 triplet 下安装
openssh,并与openssl、zlib等依赖版本对齐。
最后,欢迎加入开源鸿蒙开发者社区交流:https://harmonypc.csdn.net/
更多推荐




所有评论(0)