本文记录使用命令 OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh 构建 Ncurses 6.5 的完整过程,包括环境、构建链路、关键日志、常见问题与解决方案、产物验证与重建方法,便于复现与运维。
📖 Ncurses 简介
Ncurses(New Curses)是一个提供字符终端界面(TUI)控制的库,是 curses 库的免费实现。它提供了创建文本用户界面的 API,支持窗口管理、颜色、鼠标输入等功能,广泛应用于终端应用程序开发。
🎯 Ncurses 的作用与重要性
Ncurses 是构建终端应用程序的基础库,提供了:
- 窗口管理:创建和管理多个文本窗口
- 输入处理:键盘和鼠标输入处理
- 颜色支持:256 色和真彩色支持
- 终端能力:查询和设置终端属性
- 国际化支持:宽字符(wide character)支持,处理多字节字符
🔧 核心组件说明
1. 库文件
libncursesw.so- 主库(宽字符版本),提供核心 curses 功能libtinfow.so- 终端信息库(宽字符版本),管理 terminfo 数据库libpanelw.so- 面板库,提供窗口堆叠和覆盖功能libmenuw.so- 菜单库,提供菜单创建和管理libformw.so- 表单库,提供表单输入和验证libncurses++w.so- C++ 绑定库
2. 命令行工具
tic- terminfo 编译器,将 terminfo 源文件编译为二进制格式toe- terminfo 条目列表工具,列出可用的终端类型infocmp- terminfo 比较工具,比较和显示 terminfo 条目clear- 清屏工具tput- 终端能力查询工具tset/reset- 终端初始化工具captoinfo/infotocap- termcap 和 terminfo 格式转换工具ncursesw6-config- 配置工具,输出编译和链接选项
3. Terminfo 数据库
- 包含数千种终端类型的描述文件
- 存储在
share/terminfo/目录下 - 支持各种终端类型,如
xterm、xterm-256color、screen等
🚀 构建入口与环境
- 📝 执行命令 :
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh - 🔧 入口脚本 :
create-hnp.sh- 检查必需的环境变量
OHOS_ARCH和OHOS_ABI - 导出
LC_CTYPE、TOOL_HOME、OHOS_SDK_HOME - 执行
make -C build-hnp
- 检查必需的环境变量
- 📦 顶层构建 :
build-hnp/MakefilePKGS变量定义需要构建的包列表(包含ncurses)- 通过
check-pkgs机制自动检测PKGS变化并触发重新构建 - 自动合并
external-hnp目录下的外部 HNP 包 base.hnp依赖所有包的.stamp和外部 HNP 包- 总目标
all: copy,打包base.hnp并拷贝到entry/hnp/$(OHOS_ABI)
⚙️ Ncurses 包的构建配置
- 📁 包目录 :
build-hnp/ncurses/Makefile- 继承通用规则:
include ../utils/Makefrag - 源地址:
SOURCE_URL = https://mirrors.tuna.tsinghua.edu.cn/gnu/ncurses/ncurses-6.5.tar.gz - 采用双阶段构建策略:宿主构建 + 交叉构建
- 继承通用规则:
🔄 双阶段构建策略
阶段 1:宿主构建 tic(Terminfo 编译器)
目的 :在构建主机上编译 tic 工具,用于交叉构建阶段安装 terminfo 数据库。
配置参数:
bash
CC="cc" CXX="" LD="ld" AR="ar" CXXFLAGS="" CFLAGS="" LDFLAGS="" \
RANLIB=ranlib \
../configure --disable-mixed-case
关键修复:
- 显式设置
RANLIB=ranlib,避免继承交叉环境的llvm-ranlib路径污染 - 如果不设置,会出现 "File name too long" 异常,因为交叉工具链路径被错误地传递到宿主构建
构建步骤:
- 构建
include目录(头文件) - 构建
progs/tic(terminfo 编译器)
阶段 2:交叉构建库与工具
配置参数:
bash
--with-shared # 构建共享库
--with-strip-program="..." # 指定 strip 工具路径
--with-termlib # 构建独立的 terminfo 库
--with-cxx-binding # 启用 C++ 绑定
--with-widec # 启用宽字符支持
--without-ada # 禁用 Ada 绑定
--host aarch64-unknown-linux-musl # 交叉编译目标
--enable-pc-files # 生成 pkg-config 文件
--with-pkg-config-libdir=... # pkg-config 文件目录
--disable-mixed-case # 禁用大小写混合
构建步骤:
- 配置交叉编译环境
- 编译库和工具
- 使用宿主构建的
tic安装 terminfo 数据库(通过TIC_PATH指定) - 去除静态库
.a文件(只保留共享库) - 复制到
../sysroot
- 🔧 通用工具链与路径 :
build-hnp/utils/MakefragCC/CXX/LD/AR/RANLIB/...均指向 OHOS SDK 的 LLVM 工具链- 通过
PKG_CONFIG_LIBDIR指向sysroot下.pc目录,确保依赖发现 - 下载支持多镜像回退:
wget→curl,主镜像失败时自动尝试备用镜像
📋 关键日志与过程节点
- 📥 下载与解包 :
- 从清华大学镜像站下载
ncurses-6.5.tar.gz - 完成解包并创建两个构建目录:
build-tic(宿主)和build(交叉)
- 从清华大学镜像站下载
- ⚙️ 宿主构建阶段 :
- 使用系统编译器
cc构建tic工具 - 成功生成
build-tic/progs/tic可执行文件
- 使用系统编译器
- 🔨 交叉构建阶段 :
- 配置交叉编译环境,启用宽字符和 C++ 绑定
- 编译生成所有库文件:
libncursesw.so、libtinfow.so、libpanelw.so、libmenuw.so、libformw.so - 编译生成所有工具:
tic、toe、infocmp、clear、tput、tset等 - 使用宿主构建的
tic安装 terminfo 数据库(2868 个终端类型描述文件)
- 📦 安装与打包 :
- 去除静态库文件(只保留共享库)
- 复制到
../sysroot并进行 ELF strip - 合并外部 HNP 包(如果存在)
- 最终执行
zip -r base.hnp sysroot并拷贝到entry/hnp/arm64-v8a/
🐛 常见问题与解决方案
❌ RANLIB 路径污染问题
-
🔍 症状 :宿主阶段
progs构建报错:make[3]: /Applications/.../openharmony:<long PATH>.../llvm-ranlib ... File name too long -
🔎 原因 :环境中的
RANLIB指向交叉工具链且包含被污染的OHOS_SDK_HOME/PATH串,导致执行路径异常 -
✅ 解决方案:
- 在宿主阶段命令前显式设置
RANLIB=ranlib(见build-hnp/ncurses/Makefile:8-10) - 确保使用系统
ranlib,避免交叉工具链变量污染 - 修复后重新执行构建,宿主
tic构建通过,交叉阶段正常安装
- 在宿主阶段命令前显式设置
✅ 产物验证
📦 检查打包文件
bash
ls build-hnp/base.hnp # 应存在
ls entry/hnp/arm64-v8a/*.hnp # 应包含 base.hnp 与 base-public.hnp
🔍 检查库文件
bash
# 检查核心库
ls -lh build-hnp/sysroot/lib/libncursesw*
ls -lh build-hnp/sysroot/lib/libtinfow*
ls -lh build-hnp/sysroot/lib/libpanelw*
ls -lh build-hnp/sysroot/lib/libmenuw*
ls -lh build-hnp/sysroot/lib/libformw*
# 检查 pkg-config 文件
ls -lh build-hnp/sysroot/lib/pkgconfig/ncursesw.pc
ls -lh build-hnp/sysroot/lib/pkgconfig/tinfow.pc
✅ 构建验证结果:
- ✅ 所有库文件已成功安装:
libncursesw.so.6.5(212K)、libtinfow.so.6.5(251K) 等 - ✅ 符号链接已正确创建
- ✅ pkg-config 文件已生成
🔧 检查命令行工具
bash
# 列出所有 ncurses 工具
ls -lh build-hnp/sysroot/bin/ | grep -E "(tic|toe|infocmp|clear|tput|tset|reset|ncurses)"
# 检查关键工具
test -f build-hnp/sysroot/bin/tic && echo "tic: OK" || echo "tic: MISSING"
test -f build-hnp/sysroot/bin/clear && echo "clear: OK" || echo "clear: MISSING"
test -f build-hnp/sysroot/bin/tput && echo "tput: OK" || echo "tput: MISSING"
test -f build-hnp/sysroot/bin/ncursesw6-config && echo "ncursesw6-config: OK" || echo "ncursesw6-config: MISSING"
✅ 构建验证结果:
- ✅ 所有工具已成功安装:
tic(78K)、infocmp(54K)、clear(8K)、tput(19K) 等 - ✅ 符号链接已正确创建:
captoinfo -> tic、infotocap -> tic、reset -> tset
📚 检查 Terminfo 数据库
bash
# 统计 terminfo 文件数量
find build-hnp/sysroot/share/terminfo -type f | wc -l
# 列出部分终端类型
ls build-hnp/sysroot/share/terminfo/x/ | head -10
# 检查特定终端类型
test -f build-hnp/sysroot/share/terminfo/x/xterm-256color && echo "xterm-256color: OK" || echo "xterm-256color: MISSING"

✅ 构建验证结果:
- ✅ Terminfo 数据库已成功安装:2868 个终端类型描述文件
- ✅ 包含常用终端类型:
xterm、xterm-256color、screen等
📝 检查头文件
bash
# 检查头文件目录
ls -lh build-hnp/sysroot/include/ncursesw/
# 检查主要头文件
test -f build-hnp/sysroot/include/ncursesw/curses.h && echo "curses.h: OK" || echo "curses.h: MISSING"
test -f build-hnp/sysroot/include/ncursesw/panel.h && echo "panel.h: OK" || echo "panel.h: MISSING"
test -f build-hnp/sysroot/include/ncursesw/menu.h && echo "menu.h: OK" || echo "menu.h: MISSING"
test -f build-hnp/sysroot/include/ncursesw/form.h && echo "form.h: OK" || echo "form.h: MISSING"

💻 终端中执行的示例命令
🔧 命令行工具使用示例
1. clear - 清屏工具
bash
# 清空终端屏幕
clear
# 或使用快捷键 Ctrl+L(如果终端支持)
2. tput - 终端能力查询工具
bash
# 查询终端列数
tput cols
# 查询终端行数
tput lines
# 设置文本颜色(前景色)
tput setaf 2 # 绿色
tput setaf 3 # 黄色
tput setaf 4 # 蓝色
# 设置文本颜色(背景色)
tput setab 1 # 红色背景
# 重置所有属性
tput sgr0
# 移动光标到指定位置(行,列)
tput cup 10 20
# 保存光标位置
tput sc
# 恢复光标位置
tput rc
# 清除到行尾
tput el
# 清除到行首
tput el1
# 清除整个屏幕
tput clear
# 示例:彩色输出
echo "$(tput setaf 2)绿色文本$(tput sgr0)"
echo "$(tput setaf 1)$(tput setab 7)红色文字,白色背景$(tput sgr0)"

3. tset / reset - 终端初始化工具
bash
# 重置终端到默认状态
reset
# 或使用 tset
tset
# 指定终端类型
tset -Q xterm-256color
# 显示当前终端类型
tset -s
4. infocmp - Terminfo 比较工具
bash
# 显示当前终端的 terminfo 条目
infocmp
# 显示特定终端的 terminfo 条目
infocmp xterm-256color
# 比较两个终端类型
infocmp xterm xterm-256color
# 显示差异
infocmp -d xterm xterm-256color
# 显示所有能力
infocmp -L xterm-256color
# 显示简短格式
infocmp -s xterm-256color

5. toe - Terminfo 条目列表工具
bash
# 列出所有可用的终端类型
toe
# 搜索包含特定字符串的终端类型
toe | grep xterm
# 显示特定终端的详细信息
toe -a xterm+256setaf

6. tic - Terminfo 编译器
bash
# 编译 terminfo 源文件
tic terminfo.src
# 编译并安装到指定目录
tic -D /path/to/terminfo terminfo.src
# 显示编译过程
tic -v terminfo.src
# 检查 terminfo 文件
tic -c terminfo.src
7. ncursesw6-config - 配置工具
bash
# 显示编译选项(CFLAGS)
ncursesw6-config --cflags
# 显示链接选项(LIBS)
ncursesw6-config --libs
# 显示版本信息
ncursesw6-config --version
# 显示所有信息
ncursesw6-config --all
# 在编译程序时使用
gcc -o program program.c $(ncursesw6-config --cflags --libs)
📝 编程示例
示例 1:使用 Ncurses 创建简单窗口
c
// hello_ncurses.c
#include <ncursesw/ncurses.h>
int main() {
// 初始化 ncurses
initscr();
// 打印文本
printw("Hello, Ncurses!");
refresh();
// 等待按键
getch();
// 清理并退出
endwin();
return 0;
}
编译和运行:
bash
# 编译
aarch64-unknown-linux-ohos-clang hello_ncurses.c \
$(build-hnp/sysroot/bin/ncursesw6-config --cflags --libs) \
-o hello_ncurses
# 运行
./hello_ncurses
示例 2:使用颜色
c
// color_example.c
#include <ncursesw/ncurses.h>
int main() {
initscr();
start_color();
// 初始化颜色对
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLUE, COLOR_WHITE);
// 使用颜色
attron(COLOR_PAIR(1));
printw("红色文本\n");
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2));
printw("绿色文本\n");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
printw("蓝色文本,白色背景\n");
attroff(COLOR_PAIR(3));
refresh();
getch();
endwin();
return 0;
}
示例 3:创建窗口和边框
c
// window_example.c
#include <ncursesw/ncurses.h>
int main() {
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
// 创建窗口
WINDOW *win = newwin(10, 40, 5, 10);
box(win, 0, 0);
mvwprintw(win, 1, 1, "这是一个带边框的窗口");
mvwprintw(win, 2, 1, "按任意键退出");
wrefresh(win);
getch();
delwin(win);
endwin();
return 0;
}
🧪 功能验证脚本
bash
#!/bin/bash
# ncurses 工具验证脚本
NCURSES_BIN="build-hnp/sysroot/bin"
TOOLS=("tic" "toe" "infocmp" "clear" "tput" "tset" "reset" "ncursesw6-config")
echo "=== Ncurses 工具验证 ==="
for tool in "${TOOLS[@]}"; do
if [ -f "$NCURSES_BIN/$tool" ]; then
echo "✓ $tool: 存在"
# 尝试获取版本信息
"$NCURSES_BIN/$tool" --version 2>&1 | head -1 || true
else
echo "✗ $tool: 缺失"
fi
done
echo ""
echo "=== 库文件验证 ==="
for lib in libncursesw libtinfow libpanelw libmenuw libformw; do
if [ -f "build-hnp/sysroot/lib/$lib.so" ]; then
echo "✓ $lib.so: 存在"
ls -lh build-hnp/sysroot/lib/$lib.so*
else
echo "✗ $lib.so: 缺失"
fi
done
echo ""
echo "=== Terminfo 数据库验证 ==="
TERMINFO_COUNT=$(find build-hnp/sysroot/share/terminfo -type f | wc -l)
echo "Terminfo 条目数量: $TERMINFO_COUNT"
echo ""
echo "=== 测试 tput 命令 ==="
echo "终端列数: $($NCURSES_BIN/tput cols 2>/dev/null || echo "N/A")"
echo "终端行数: $($NCURSES_BIN/tput lines 2>/dev/null || echo "N/A")"
🔄 重建与扩展
-
🔧 重建单包:
bashmake -C build-hnp rebuild-ncurses # 触发子包重新编译并刷新 .stamp -
🧹 清理:
bashmake -C build-hnp clean # 清理 sysroot、所有 .stamp 和 PKGS_MARKER -
📦 扩展 :Ncurses 是许多终端应用的基础依赖,如
readline、tmux、vim、htop等都需要它 -
🔄 自动重建机制:
- 修改
PKGS后,check-pkgs会自动检测变化并触发重新构建 - 新增外部 HNP 包到
external-hnp目录后,会自动合并到base.hnp
- 修改
💡 实践建议
- 🔄 交叉+宿主双阶段 :优先在宿主构建
tic,交叉阶段通过TIC_PATH引用以安装 terminfo - 🛡️ 环境隔离 :为宿主阶段显式设置工具(如
RANLIB=ranlib),避免交叉工具链变量污染 - 📦 宽字符与 C++ 绑定 :本构建启用
--with-widec与--with-cxx-binding,满足现代 TUI 程序需求;按需裁剪可减少体积 - 🔗 依赖关系:Ncurses 是终端应用的基础库,通常需要先构建 Ncurses,再构建依赖它的应用(如 readline、tmux、vim 等)
📝 结论与建议
- ✅ 本次已在 aarch64 环境下完成 Ncurses 6.5 的交叉编译与打包,所有库、工具和 terminfo 数据库已安装到
sysroot并纳入 HNP 包。 - 💡 为保证构建稳定 :
- 固定可靠的上游镜像,避免下载阶段随机失败(已实现自动回退机制)
- 对大型包启用构建缓存(可在
Makefrag中开启USE_CCACHE) - 宿主/交叉分离与环境显式化是稳定构建的关键
- 通过
ncursesw.pc与工具链路径,后续readline/tmux/vim等均可顺利链接与运行 - 利用
check-pkgs机制自动检测包列表变化,无需手动清理
📚 以上为 Ncurses 构建的深度解读与实践记录。