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 的功能,确保所有特性正常工作

参考资料

参考资源

相关推荐
行走的陀螺仪2 小时前
vue3-封装权限按钮组件和自定义指令
前端·vue3·js·自定义指令·权限按钮
isyuah2 小时前
vite-plugin-openapi-ts CLI 使用指南
前端·vite
qq_398586543 小时前
浏览器中内嵌一个浏览器
前端·javascript·css·css3
Mapmost3 小时前
地图引擎性能优化:解决3DTiles加载痛点的六大核心策略
前端
San30.3 小时前
Ajax 数据请求:从 XMLHttpRequest 到现代前端数据交互的演进
前端·ajax·交互
西西西西胡萝卜鸡3 小时前
虚拟列表(Virtual List)组件实现与优化铁臂猿版(简易版)
前端·vue.js
宇余4 小时前
Unibest:新一代uni-app工程化最佳实践指南
前端·vue.js
性野喜悲4 小时前
ts+uniapp小程序时间日期选择框(分开选择)
前端·javascript·vue.js
P***25395 小时前
前端构建工具缓存清理,npm cache与yarn cache
前端·缓存·npm