less 工具 OpenHarmony PC适配实践
less 工具 OpenHarmony PC适配实践
目录
- 工具概述
- 主要用途
- 适配过程
- 遇到的问题与解决方案
- 构建脚本说明
- 总结
工具概述
less 是一个功能强大的终端分页器(terminal pager),用于在终端中查看文本文件的内容。它是 more 命令的增强版本,提供了更丰富的功能和更好的用户体验。
主要特点
- 双向滚动:支持向前和向后滚动查看文件内容
- 搜索功能:支持向前和向后搜索文本
- 标记功能:可以在文件中设置标记,快速跳转
- 语法高亮:支持代码语法高亮显示
- 多文件支持:可以同时打开多个文件
- 终端兼容性:兼容各种终端类型和终端模拟器
效果

版本信息
- 项目名称:less
- 版本:1.0.0
- 许可证:GPL 或 Less License
- 官方网站:https://www.greenwoodsoftware.com/less/
主要用途
1. 查看大型文件
less 特别适合查看大型日志文件或配置文件,因为它不会一次性加载整个文件到内存中,而是按需加载:
less /var/log/system.log
less /etc/config.conf
2. 查看命令输出
可以将命令的输出通过管道传递给 less:
ps aux | less
history | less
3. 代码查看
支持语法高亮,适合查看源代码文件:
less source.c
less Makefile
4. 交互式浏览
提供了丰富的交互命令:
- 空格键:向下翻页
- b:向上翻页
- /:向前搜索
- ?:向后搜索
- g:跳转到文件开头
- G:跳转到文件结尾
- q:退出
适配过程
1. 项目结构
less 使用传统的 autotools 构建系统(autoconf/automake),需要先运行 configure 脚本生成 Makefile。
2. 构建系统分析
- 构建工具:autotools (configure + make)
- 编程语言:C
- 依赖库:termcap/terminfo(终端控制库)
- 特殊需求:需要终端库支持,但在交叉编译时无法运行测试程序
3. 适配步骤
步骤 1:配置构建脚本
创建 build_ohos.sh 脚本,设置 OpenHarmony 交叉编译环境:
#!/bin/bash
# less 工具 OpenHarmony 构建脚本export LESS_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/less.org/less_1.0.0
export PREFIX=${LESS_INSTALL_HNP_PATH}
mkdir -p ${LESS_INSTALL_HNP_PATH}
步骤 2:运行 configure
配置构建系统,指定目标平台:
sh configure \--prefix=${PREFIX} \--host=aarch64-linux-gnu \CC="${CC}" \CFLAGS="${CFLAGS}" \LDFLAGS="${LDFLAGS}" \TERMLIBS="-ltermcap"
步骤 3:修复配置问题
由于交叉编译时 configure 无法运行测试程序,需要手动修复 defines.h 中的宏定义。
步骤 4:编译和安装
make VERBOSE=1
make install
步骤 5:打包 HNP
使用 HNP 工具打包应用:
${HNP_TOOL} pack -i ${LESS_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_less_1.0.0.tar.gz less_1.0.0/
遇到的问题与解决方案
问题 1:FILE 类型未定义
错误信息:
error: unknown type name 'FILE'
原因分析:
defines.h 中 HAVE_STDIO_H 被设置为 #undef,导致 stdio.h 没有被包含,FILE 类型未定义。
解决方案:
在 build_ohos.sh 中添加自动修复逻辑:
sed -i.bak 's/^#undef HAVE_STDIO_H$/#define HAVE_STDIO_H 1/' defines.h
问题 2:PATTERN_TYPE 类型未定义
错误信息:
error: unknown type name 'PATTERN_TYPE'
原因分析:
less 支持多种正则表达式库(GNU regex、POSIX regex、PCRE 等),但 OpenHarmony SDK 中这些库都不可用。PATTERN_TYPE 类型定义在 pattern.h 中,依赖于正则表达式库的宏定义。
解决方案:
启用 NO_REGEX 宏,使 PATTERN_TYPE 定义为 void *:
sed -i.bak 's/^#undef NO_REGEX$/#define NO_REGEX 1/' defines.h
问题 3:sprintf 未声明警告
错误信息:
warning: call to undeclared library function 'sprintf'
原因分析:
HAVE_SNPRINTF 未定义,代码回退到使用 sprintf,但 sprintf 未声明。
解决方案:
启用 HAVE_SNPRINTF,使用 snprintf 替代 sprintf:
sed -i.bak 's/^#undef HAVE_SNPRINTF$/#define HAVE_SNPRINTF 1/' defines.h
问题 4:sgtty.h 文件未找到
错误信息:
fatal error: 'sgtty.h' file not found
原因分析:
screen.c 中的包含逻辑会尝试包含 sgtty.h(旧式终端控制头文件),但 OpenHarmony SDK 不支持这个文件。
解决方案:
启用 POSIX termios.h 支持:
sed -i.bak 's/^#undef HAVE_TERMIOS_H$/#define HAVE_TERMIOS_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_TERMIOS_FUNCS$/#define HAVE_TERMIOS_FUNCS 1/' defines.h
问题 5:INT_MAX 未定义
错误信息:
error: use of undeclared identifier 'INT_MAX'
原因分析:
HAVE_LIMITS_H 未定义,limits.h 没有被包含。
解决方案:
启用 HAVE_LIMITS_H:
sed -i.bak 's/^#undef HAVE_LIMITS_H$/#define HAVE_LIMITS_H 1/' defines.h
问题 6:termcap 函数未声明
错误信息:
warning: call to undeclared function 'tgetflag'
warning: call to undeclared function 'tgetnum'
warning: call to undeclared function 'tgetstr'
原因分析:
OpenHarmony SDK 中没有 termcap.h 头文件,termcap 函数未声明。
解决方案:
创建 termcap_stub.h 和 termcap_stub.c 提供 termcap 函数的声明和 stub 实现:
termcap_stub.h:
#ifndef TERMCAP_STUB_H
#define TERMCAP_STUB_H#include <stdio.h>extern int tgetflag(const char *id);
extern int tgetnum(const char *id);
extern char *tgetstr(const char *id, char **area);
extern char *tgoto(const char *cap, int col, int row);
extern int tgetent(char *bp, const char *name);
extern int tputs(const char *str, int affcnt, int (*putc)(int));#ifndef TGETENT_OK
#define TGETENT_OK 1
#endif#endif /* TERMCAP_STUB_H */
termcap_stub.c:
#include "termcap_stub.h"
#include <stdlib.h>
#include <string.h>int tgetflag(const char *id) {(void)id;return 0;
}int tgetnum(const char *id) {(void)id;return -1;
}char *tgetstr(const char *id, char **area) {(void)id;(void)area;return NULL;
}char *tgoto(const char *cap, int col, int row) {static char buf[32];snprintf(buf, sizeof(buf), "\033[%d;%dH", row + 1, col + 1);return buf;
}int tgetent(char *bp, const char *name) {(void)bp;(void)name;return TGETENT_OK;
}int tputs(const char *str, int affcnt, int (*putc)(int)) {(void)affcnt;if (str != NULL && putc != NULL) {while (*str) {putc(*str++);}}return 0;
}
修改 screen.c,在找不到 termcap.h 时使用 stub:
#if HAVE_TERMCAP_H
#include <termcap.h>
#else
/* OpenHarmony doesn't have termcap.h, use stub */
#include "termcap_stub.h"
#endif
问题 7:termcap 函数链接错误
错误信息:
ld.lld: error: undefined symbol: tgetstr
ld.lld: error: undefined symbol: tgetent
原因分析:
termcap_stub.o 没有被添加到 Makefile 的 OBJ 变量中。
解决方案:
在 build_ohos.sh 中添加逻辑,自动将 termcap_stub.o 添加到 Makefile:
if [ -f "./termcap_stub.c" ] && ! grep -q "termcap_stub" Makefile 2>/dev/null; thenecho "Adding termcap_stub.c to Makefile..."awk '/^OBJ = /{in_obj=1} in_obj && /xbuf\.\${O}/{sub(/$/, " termcap_stub.${O}"); in_obj=0} {print}' Makefile > Makefile.tmp && mv Makefile.tmp Makefile || \sed -i.bak '/^\t.*xbuf\.\${O}/s/$/ termcap_stub.${O}/' Makefile 2>/dev/null || \sed -i '' '/^\t.*xbuf\.\${O}/s/$/ termcap_stub.${O}/' Makefile 2>/dev/null || true
fi
问题 8:open/time/strerror 函数未声明
错误信息:
warning: call to undeclared function 'open'
warning: call to undeclared function 'time'
error: static declaration of 'strerror' follows non-static declaration
原因分析:
相应的头文件宏定义未启用。
解决方案:
启用 HAVE_FCNTL_H、HAVE_TIME_H 和 HAVE_STRERROR:
sed -i.bak 's/^#undef HAVE_FCNTL_H$/#define HAVE_FCNTL_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_TIME_H$/#define HAVE_TIME_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_STRERROR$/#define HAVE_STRERROR 1/' defines.h
问题 9:lsystem 函数未定义
错误信息:
ld.lld: error: undefined symbol: lsystem
原因分析:
lsystem 函数在 lsystem.c 中被 #if HAVE_SYSTEM 条件编译保护,但 HAVE_SYSTEM 未定义。
解决方案:
启用 HAVE_SYSTEM:
sed -i.bak 's/^#undef HAVE_SYSTEM$/#define HAVE_SYSTEM 1/' defines.h
问题 10:手册页文件缺失
错误信息:
make: *** No rule to make target 'lesskey.nro', needed by 'install'. Stop.
原因分析:
make install 需要 lesskey.nro 和 lessecho.nro 手册页文件,但这些文件不存在。
解决方案:
在安装前创建占位文件:
if [ ! -f "./lesskey.nro" ]; thencp lesskey.nro.VER lesskey.nro 2>/dev/null || touch lesskey.nro
fi
if [ ! -f "./lessecho.nro" ]; thencp lessecho.nro.VER lessecho.nro 2>/dev/null || touch lessecho.nro
fi
构建脚本说明
build_ohos.sh 关键部分
1. 环境设置
export LESS_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/less.org/less_1.0.0
export PREFIX=${LESS_INSTALL_HNP_PATH}
mkdir -p ${LESS_INSTALL_HNP_PATH}
2. Configure 配置
sh configure \--prefix=${PREFIX} \--host=aarch64-linux-gnu \CC="${CC}" \CFLAGS="${CFLAGS}" \LDFLAGS="${LDFLAGS}" \TERMLIBS="-ltermcap"
3. 自动修复 defines.h
# 修复关键宏定义
sed -i.bak 's/^#undef HAVE_STDIO_H$/#define HAVE_STDIO_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_SNPRINTF$/#define HAVE_SNPRINTF 1/' defines.h
sed -i.bak 's/^#undef NO_REGEX$/#define NO_REGEX 1/' defines.h
sed -i.bak 's/^#undef HAVE_TERMIOS_H$/#define HAVE_TERMIOS_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_TERMIOS_FUNCS$/#define HAVE_TERMIOS_FUNCS 1/' defines.h
sed -i.bak 's/^#undef HAVE_LIMITS_H$/#define HAVE_LIMITS_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_FCNTL_H$/#define HAVE_FCNTL_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_TIME_H$/#define HAVE_TIME_H 1/' defines.h
sed -i.bak 's/^#undef HAVE_STRERROR$/#define HAVE_STRERROR 1/' defines.h
sed -i.bak 's/^#undef HAVE_SYSTEM$/#define HAVE_SYSTEM 1/' defines.h
4. 添加 termcap_stub 到 Makefile
if [ -f "./termcap_stub.c" ] && ! grep -q "termcap_stub" Makefile 2>/dev/null; thenawk '/^OBJ = /{in_obj=1} in_obj && /xbuf\.\${O}/{sub(/$/, " termcap_stub.${O}"); in_obj=0} {print}' Makefile > Makefile.tmp && mv Makefile.tmp Makefile
fi
5. 创建手册页占位文件
if [ ! -f "./lesskey.nro" ]; thencp lesskey.nro.VER lesskey.nro 2>/dev/null || touch lesskey.nro
fi
if [ ! -f "./lessecho.nro" ]; thencp lessecho.nro.VER lessecho.nro 2>/dev/null || touch lessecho.nro
fi
关键修复总结
修复的宏定义
| 宏定义 | 修复前 | 修复后 | 用途 |
|---|---|---|---|
HAVE_STDIO_H | #undef | #define HAVE_STDIO_H 1 | FILE 类型定义 |
HAVE_SNPRINTF | #undef | #define HAVE_SNPRINTF 1 | 使用 snprintf |
NO_REGEX | #undef | #define NO_REGEX 1 | PATTERN_TYPE 定义 |
HAVE_TERMIOS_H | #undef | #define HAVE_TERMIOS_H 1 | POSIX termios 支持 |
HAVE_TERMIOS_FUNCS | #undef | #define HAVE_TERMIOS_FUNCS 1 | termios 函数支持 |
HAVE_LIMITS_H | #undef | #define HAVE_LIMITS_H 1 | INT_MAX 定义 |
HAVE_FCNTL_H | #undef | #define HAVE_FCNTL_H 1 | open 函数声明 |
HAVE_TIME_H | #undef | #define HAVE_TIME_H 1 | time 函数声明 |
HAVE_STRERROR | #undef | #define HAVE_STRERROR 1 | 使用系统 strerror |
HAVE_SYSTEM | #undef | #define HAVE_SYSTEM 1 | lsystem 函数编译 |
创建的新文件
- termcap_stub.h - termcap 函数声明
- termcap_stub.c - termcap 函数 stub 实现
修改的文件
- screen.c - 添加 termcap_stub.h 包含逻辑
- build_ohos.sh - 添加自动修复和构建逻辑
使用示例
基本使用
# 查看文件
less filename.txt# 查看命令输出
ps aux | less# 搜索文本(在 less 中)
/pattern # 向前搜索
?pattern # 向后搜索
n # 下一个匹配
N # 上一个匹配
常用命令
| 命令 | 功能 |
|---|---|
空格键 | 向下翻页 |
b | 向上翻页 |
g | 跳转到文件开头 |
G | 跳转到文件结尾 |
/pattern | 向前搜索 |
?pattern | 向后搜索 |
q | 退出 |
h | 显示帮助 |
总结
适配难点
- 交叉编译限制:
configure脚本无法运行测试程序,需要手动修复配置 - 依赖库缺失:OpenHarmony SDK 中没有 termcap 库,需要创建 stub 实现
- 头文件缺失:多个标准头文件的宏定义需要手动启用
- 条件编译:大量使用条件编译,需要正确设置宏定义
适配成果
- ✅ 成功编译
less、lesskey、lessecho三个可执行文件 - ✅ 创建了 termcap stub 实现,解决了终端控制库依赖问题
- ✅ 修复了所有编译和链接错误
- ✅ 实现了自动化构建脚本,支持一键构建
经验总结
- 交叉编译适配:对于使用 autotools 的项目,需要仔细检查
configure生成的defines.h,手动修复无法正确检测的宏定义 - 依赖库处理:对于缺失的系统库,可以创建 stub 实现,提供最小功能支持
- 自动化构建:使用脚本自动修复配置问题,提高构建效率
- 文档记录:详细记录遇到的问题和解决方案,便于后续维护
后续优化建议
- termcap 功能增强:可以改进
termcap_stub.c的实现,提供更完整的终端控制功能 - 正则表达式支持:如果 OpenHarmony SDK 未来支持正则表达式库,可以启用相应的宏定义
- 测试验证:在实际的 OpenHarmony 设备上测试
less的功能,确保所有特性正常工作
参考资料
- less 官方网站
- less 源代码
- OpenHarmony Native 开发文档
参考资源
- sd 官方仓库
- Rust 交叉编译文档
- HarmonyOS 原生应用开发文档
- 项目代码仓
- PC代码仓
- PC社区
