
bcal (Byte CALculator) 是一个 REPL(Read-Eval-Print Loop)命令行工具,用于存储表达式计算、SI/IEC 单位转换、字节地址计算、进制转换和 LBA/CHS 计算。对于经常处理位、字节、地址和二进制前缀的开发者来说非常有用。
bc 或 calc 进行通用数值计算git clone https://github.com/jarun/bcal.git
cd bcal
make strip install下载到本地

usage: bcal [-c N] [-f loc] [-s bytes] [expr]
[N [unit]] [-b [expr]] [-m] [-d] [-h]
Storage expression calculator.
positional arguments:
expr expression in decimal/hex operands
N [unit] capacity in B/KiB/MiB/GiB/TiB/kB/MB/GB/TB
default unit is B (byte), case is ignored
N can be decimal or '0x' prefixed hex value
optional arguments:
-c N show +ve integer N in binary, decimal, hex
-f loc convert CHS to LBA or LBA to CHS
-s bytes sector size [default 512]
-b [expr] enter bc mode or evaluate expression in bc
-m show minimal output (e.g. decimal bytes)
-d enable debug information and logs
-h show this help$ bcal "(5kb+2mb)/3"
$ bcal "5 tb / 12"
$ bcal "(2giB * 2) / (2kib >> 2)"$ bcal 20140115 b
$ bcal 0x1335053 B
$ bcal 0xaabbcc kb
$ bcal 0xdef Gib$ bcal -f l500
$ bcal -f c10-10-10$ bcal -c 20140115
$ bcal -c 0b1001100110101000001010011
$ bcal -c 0x1335053$ bcal
bcal> 15 gib + 15 kib
bcal> r / 5
bcal> ?code/bcal/
├── build_ohos.sh # HarmonyOS 构建脚本
├── hnp.json # HNP 包配置文件
├── Makefile # 构建文件
├── src/
│ ├── bcal.c # 主程序源码
│ └── readline_stub.h # readline 替代实现
├── inc/ # 头文件目录
└── README.md # 项目说明创建 hnp.json 文件:
{
"type":"hnp-config",
"name":"bcal",
"version":"2.4.0",
"install":{}
}创建 build_ohos.sh 脚本,参考其他项目的构建脚本结构:
#!/bin/bash
# bcal HarmonyOS 构建脚本
export BCAL_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/bcal.org/bcal_2.4.0
sys_prefix=${PREFIX}
export PREFIX=${BCAL_INSTALL_HNP_PATH}
echo "${PREFIX}"
# 创建安装目录
mkdir -p ${BCAL_INSTALL_HNP_PATH}
# 构建和安装
make clean
make VERBOSE=1
make install
# 复制 HNP 配置文件
cp hnp.json ${BCAL_INSTALL_HNP_PATH}/
# 打包
pushd ${BCAL_INSTALL_HNP_PATH}/../
${HNP_TOOL} pack -i ${BCAL_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_bcal_2.4.0.tar.gz bcal_2.4.0/
popd
export PREFIX=${sys_prefix}#!/bin/bash
# ============================================================================
# build_ohos.sh - bcal 工具 HarmonyOS 构建脚本
# ============================================================================
# 设置 HNP 安装路径
export BCAL_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/bcal.org/bcal_2.4.0
# 保存并临时修改 PREFIX
sys_prefix=${PREFIX}
export PREFIX=${BCAL_INSTALL_HNP_PATH}
echo "${PREFIX}"
# 创建安装目录(确保目录存在)
mkdir -p ${BCAL_INSTALL_HNP_PATH}
# 清理之前的构建产物
make clean
# 编译时禁用 readline(使用 stub 实现)
# HarmonyOS SDK 中没有 readline 库,需要使用自定义的 stub 实现
make VERBOSE=1 CPPFLAGS="-UHAVE_READLINE" LDLIBS_READLINE="" || {
echo "Error: make failed"
exit 1
}
# 安装
make install || {
echo "Error: make install failed"
exit 1
}
# 复制 HNP 配置文件
cp hnp.json ${BCAL_INSTALL_HNP_PATH}/ || {
echo "Error: failed to copy hnp.json"
exit 1
}
# 打包
if [ -d "${BCAL_INSTALL_HNP_PATH}" ]; then
pushd ${BCAL_INSTALL_HNP_PATH}/../ > /dev/null
${HNP_TOOL} pack -i ${BCAL_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/ || {
echo "Error: HNP pack failed"
popd > /dev/null
export PREFIX=${sys_prefix}
exit 1
}
tar -zvcf ${ARCHIVE_PATH}/ohos_bcal_2.4.0.tar.gz bcal_2.4.0/ || {
echo "Error: tar failed"
popd > /dev/null
export PREFIX=${sys_prefix}
exit 1
}
popd > /dev/null
else
echo "Error: Installation directory does not exist: ${BCAL_INSTALL_HNP_PATH}"
export PREFIX=${sys_prefix}
exit 1
fi
# 恢复 PREFIX
export PREFIX=${sys_prefix}clang-15: error: '-fuse-ld=' taking a path is deprecated; use '--ld-path=' instead [-Werror,-Wfuse-ld-path]clang-15 编译器不再支持 -fuse-ld=/path/to/ld 的语法,需要使用新的 --ld-path=/path/to/ld 语法。
在 build.sh 中修改 CFLAGS 和 LDFLAGS:
修改前:
export CFLAGS="-fPIC -D__MUSL__=1 -D__OHOS__ -fstack-protector-strong --target=${TARGET_PLATFORM} -fuse-ld=${LD} --sysroot=${SYSROOT}"
export LDFLAGS="${LDFLAGS} -fuse-ld=${LD} --target=${TARGET_PLATFORM} --sysroot=${SYSROOT}"修改后:
export CFLAGS="-fPIC -D__MUSL__=1 -D__OHOS__ -fstack-protector-strong --target=${TARGET_PLATFORM} --ld-path=${LD} --sysroot=${SYSROOT}"
export LDFLAGS="${LDFLAGS} --ld-path=${LD} --target=${TARGET_PLATFORM} --sysroot=${SYSROOT}"src/bcal.c:31:10: fatal error: 'readline/history.h' file not found
#include <readline/history.h>
^~~~~~~~~~~~~~~~~~~~HarmonyOS SDK 的 sysroot 中没有 readline 库。bcal 默认依赖 readline 用于交互式输入,但该功能在 HarmonyOS 环境中不可用。
创建 readline 的 stub 实现,使代码可以在没有 readline 的情况下编译:
1. 创建 src/readline_stub.h:
#ifndef READLINE_STUB_H
#define READLINE_STUB_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Simple readline stub implementation for systems without readline
static inline char *readline(const char *prompt) {
if (prompt) {
fputs(prompt, stdout);
fflush(stdout);
}
char *line = NULL;
size_t len = 0;
ssize_t read = getline(&line, &len, stdin);
if (read == -1) {
free(line);
return NULL;
}
// Remove trailing newline
if (read > 0 && line[read - 1] == '\n') {
line[read - 1] = '\0';
}
return line;
}
static inline void add_history(const char *line) {
// Stub: do nothing
(void)line;
}
static inline int read_history(const char *filename) {
// Stub: do nothing
(void)filename;
return 0;
}
static inline int write_history(const char *filename) {
// Stub: do nothing
(void)filename;
return 0;
}
#endif // READLINE_STUB_H2. 修改 src/bcal.c 使用条件编译:
#include <getopt.h>
#if defined(HAVE_READLINE) && HAVE_READLINE == 1
#include <readline/history.h>
#include <readline/readline.h>
#else
#include "readline_stub.h"
#endif
#include "dslib.h"
#include "log.h"3. 处理 readline 特定函数调用:
#if defined(HAVE_READLINE) && HAVE_READLINE == 1
rl_bind_key('\t', rl_insert);
#else
// Tab completion not available without readline
#endif4. 在构建脚本中禁用 readline:
make VERBOSE=1 CPPFLAGS="-UHAVE_READLINE" LDLIBS_READLINE=""cp: directory /Users/jianguo/HarmonyOSPC/build/data/service/hnp/bcal.org/bcal_2.4.0 does not exist
pushd: /Users/jianguo/HarmonyOSPC/build/data/service/hnp/bcal.org/bcal_2.4.0/../: No such file or directory
popd: directory stack empty构建脚本缺少错误处理和目录检查,导致在编译失败时后续步骤无法正确执行。
添加完善的错误处理和目录检查:
# 创建安装目录(确保目录存在)
mkdir -p ${BCAL_INSTALL_HNP_PATH}
# 添加错误处理
make VERBOSE=1 CPPFLAGS="-UHAVE_READLINE" LDLIBS_READLINE="" || {
echo "Error: make failed"
exit 1
}
make install || {
echo "Error: make install failed"
exit 1
}
# 打包前检查目录是否存在
if [ -d "${BCAL_INSTALL_HNP_PATH}" ]; then
pushd ${BCAL_INSTALL_HNP_PATH}/../ > /dev/null
# ... 打包操作 ...
popd > /dev/null
else
echo "Error: Installation directory does not exist"
exit 1
fi成功构建后,会在 output/ 目录下生成以下文件:
bcal.hnp - HarmonyOS Native Package 格式包(约 45KB)ohos_bcal_2.4.0.tar.gz - tar.gz 压缩包(约 45KB)# 检查文件是否存在
ls -lh output/bcal.hnp output/ohos_bcal_2.4.0.tar.gz
# 检查 HNP 文件格式
file output/bcal.hnp
# 查看 tar.gz 内容
tar -tzf output/ohos_bcal_2.4.0.tar.gzbcal_2.4.0/
├── bin/
│ └── bcal # 可执行文件
├── hnp.json # HNP 配置文件
└── share/
├── doc/
│ └── bcal/
│ └── README.md
└── man/
└── man1/
└── bcal.1.gz # 手册页终于编译成功了
# 计算存储表达式
$ bcal "(5kb+2mb)/3"
$ bcal "5 tb / 12"
$ bcal "(2giB * 2) / (2kib >> 2)"
# 单位转换
$ bcal 20140115 b
$ bcal 0x1335053 B
$ bcal 0xaabbcc kb# LBA 转 CHS
$ bcal -f l500
$ bcal -f l0x600-18-0x7e
# CHS 转 LBA
$ bcal -f c10-10-10
$ bcal -f c0x10-0x10-0x10# 显示二进制、十进制和十六进制
$ bcal -c 20140115
$ bcal -c 0b1001100110101000001010011
$ bcal -c 0x1335053$ bcal
bcal> 15 gib + 15 kib
bcal> r / 5
bcal> b # 切换到 bc 模式
bcal> ? # 显示帮助
bcal> q # 退出# 从管道输入
$ printf '15 kib + 15 gib \n r / 5' | bcal -m
# 从文件输入
$ cat expr
15 gib + 15 kib
r / 5
$ bcal -m < expr--ld-path= 替代已弃用的 -fuse-ld= 语法bcal 工具特别适用于: