less 工具 OpenHarmony PC适配实践

less 工具 OpenHarmony PC适配实践

目录


工具概述

less 是一个功能强大的终端分页器(terminal pager),用于在终端中查看文本文件的内容。它是 more 命令的增强版本,提供了更丰富的功能和更好的用户体验。

主要特点

  • 双向滚动:支持向前和向后滚动查看文件内容
  • 搜索功能:支持向前和向后搜索文本
  • 标记功能:可以在文件中设置标记,快速跳转
  • 语法高亮:支持代码语法高亮显示
  • 多文件支持:可以同时打开多个文件
  • 终端兼容性:兼容各种终端类型和终端模拟器

效果

版本信息


主要用途

1. 查看大型文件

less 特别适合查看大型日志文件或配置文件,因为它不会一次性加载整个文件到内存中,而是按需加载:

bash 复制代码
less /var/log/system.log
less /etc/config.conf

2. 查看命令输出

可以将命令的输出通过管道传递给 less

bash 复制代码
ps aux | less
history | less

3. 代码查看

支持语法高亮,适合查看源代码文件:

bash 复制代码
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 交叉编译环境:

bash 复制代码
#!/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

配置构建系统,指定目标平台:

bash 复制代码
sh configure \
    --prefix=${PREFIX} \
    --host=aarch64-linux-gnu \
    CC="${CC}" \
    CFLAGS="${CFLAGS}" \
    LDFLAGS="${LDFLAGS}" \
    TERMLIBS="-ltermcap"
步骤 3:修复配置问题

由于交叉编译时 configure 无法运行测试程序,需要手动修复 defines.h 中的宏定义。

步骤 4:编译和安装
bash 复制代码
make VERBOSE=1
make install
步骤 5:打包 HNP

使用 HNP 工具打包应用:

bash 复制代码
${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.hHAVE_STDIO_H 被设置为 #undef,导致 stdio.h 没有被包含,FILE 类型未定义。

解决方案

build_ohos.sh 中添加自动修复逻辑:

bash 复制代码
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 *

bash 复制代码
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

bash 复制代码
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 支持:

bash 复制代码
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

bash 复制代码
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.htermcap_stub.c 提供 termcap 函数的声明和 stub 实现:

termcap_stub.h

c 复制代码
#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

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:

c 复制代码
#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:

bash 复制代码
if [ -f "./termcap_stub.c" ] && ! grep -q "termcap_stub" Makefile 2>/dev/null; then
    echo "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_HHAVE_TIME_HHAVE_STRERROR

bash 复制代码
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

bash 复制代码
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.nrolessecho.nro 手册页文件,但这些文件不存在。

解决方案

在安装前创建占位文件:

bash 复制代码
if [ ! -f "./lesskey.nro" ]; then
    cp lesskey.nro.VER lesskey.nro 2>/dev/null || touch lesskey.nro
fi
if [ ! -f "./lessecho.nro" ]; then
    cp lessecho.nro.VER lessecho.nro 2>/dev/null || touch lessecho.nro
fi

构建脚本说明

build_ohos.sh 关键部分

1. 环境设置
bash 复制代码
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 配置
bash 复制代码
sh configure \
    --prefix=${PREFIX} \
    --host=aarch64-linux-gnu \
    CC="${CC}" \
    CFLAGS="${CFLAGS}" \
    LDFLAGS="${LDFLAGS}" \
    TERMLIBS="-ltermcap"
3. 自动修复 defines.h
bash 复制代码
# 修复关键宏定义
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
bash 复制代码
if [ -f "./termcap_stub.c" ] && ! grep -q "termcap_stub" Makefile 2>/dev/null; then
    awk '/^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. 创建手册页占位文件
bash 复制代码
if [ ! -f "./lesskey.nro" ]; then
    cp lesskey.nro.VER lesskey.nro 2>/dev/null || touch lesskey.nro
fi
if [ ! -f "./lessecho.nro" ]; then
    cp 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 函数编译

创建的新文件

  1. termcap_stub.h - termcap 函数声明
  2. termcap_stub.c - termcap 函数 stub 实现

修改的文件

  1. screen.c - 添加 termcap_stub.h 包含逻辑
  2. build_ohos.sh - 添加自动修复和构建逻辑

使用示例

基本使用

bash 复制代码
# 查看文件
less filename.txt

# 查看命令输出
ps aux | less

# 搜索文本(在 less 中)
/pattern    # 向前搜索
?pattern    # 向后搜索
n           # 下一个匹配
N           # 上一个匹配

常用命令

命令 功能
空格键 向下翻页
b 向上翻页
g 跳转到文件开头
G 跳转到文件结尾
/pattern 向前搜索
?pattern 向后搜索
q 退出
h 显示帮助

总结

适配难点

  1. 交叉编译限制configure 脚本无法运行测试程序,需要手动修复配置
  2. 依赖库缺失:OpenHarmony SDK 中没有 termcap 库,需要创建 stub 实现
  3. 头文件缺失:多个标准头文件的宏定义需要手动启用
  4. 条件编译:大量使用条件编译,需要正确设置宏定义

适配成果

  • ✅ 成功编译 lesslesskeylessecho 三个可执行文件
  • ✅ 创建了 termcap stub 实现,解决了终端控制库依赖问题
  • ✅ 修复了所有编译和链接错误
  • ✅ 实现了自动化构建脚本,支持一键构建

经验总结

  1. 交叉编译适配 :对于使用 autotools 的项目,需要仔细检查 configure 生成的 defines.h,手动修复无法正确检测的宏定义
  2. 依赖库处理:对于缺失的系统库,可以创建 stub 实现,提供最小功能支持
  3. 自动化构建:使用脚本自动修复配置问题,提高构建效率
  4. 文档记录:详细记录遇到的问题和解决方案,便于后续维护

后续优化建议

  1. termcap 功能增强 :可以改进 termcap_stub.c 的实现,提供更完整的终端控制功能
  2. 正则表达式支持:如果 OpenHarmony SDK 未来支持正则表达式库,可以启用相应的宏定义
  3. 测试验证 :在实际的 OpenHarmony 设备上测试 less 的功能,确保所有特性正常工作

参考资料

参考资源

相关推荐
代码匠心4 分钟前
AI 自动编程:一句话设计高颜值博客
前端·ai·ai编程·claude
_AaronWong1 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode1 小时前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户5433081441941 小时前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo1 小时前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
恋猫de小郭2 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
哀木2 小时前
给自己整一个 claude code,解锁编程新姿势
前端
程序员鱼皮2 小时前
GitHub 关注突破 2w,我总结了 10 个涨星涨粉技巧!
前端·后端·github
UrbanJazzerati2 小时前
Vue3 父子组件通信完全指南
前端·面试
是一碗螺丝粉2 小时前
5分钟上手LangChain.js:用DeepSeek给你的App加上AI能力
前端·人工智能·langchain