从零开始:开发一个仓颉三方库的完整实战

作者:Undoom

日期:2025-11-03

项目:filesize - 文件大小格式化工具库

前言

本文详细记录了从零开始开发一个仓颉三方库的完整过程,包括从克隆模板、编写代码、解决问题到最终发布的每一个步骤。通过这篇文章,你将学会如何创建一个标准的、文档完善的仓颉三方库。

项目背景

在日常开发中,我们经常需要将文件大小(字节数)转换为人类可读的格式,比如将 1048576 显示为 1.05 MB。虽然这是一个简单的需求,但如果每个项目都重复实现一遍,不仅浪费时间,还容易出错。因此,我决定开发一个专门的仓颉三方库来解决这个问题。

你将学到

  • ✅ 如何使用官方模板快速启动项目
  • ✅ 仓颉语言的包管理和项目结构
  • ✅ 遇到编译错误时如何诊断和解决
  • ✅ 如何编写标准的三方库代码
  • ✅ 如何完善文档和开源协议
  • ✅ 如何发布到 GitCode 仓库

第一步:准备工作

1.1 环境要求

开始之前,确保你的开发环境已准备就绪:

bash 复制代码
# 检查仓颉编译器版本
cjc --version
# 要求: >= 1.0.3

# 检查包管理器
cjpm --version

# 确认环境变量
echo $CANGJIE_HOME

1.2 克隆官方模板

仓颉官方提供了标准的三方库模板,可以帮助我们快速启动项目:

bash 复制代码
# 克隆模板仓库
git clone git@gitcode.com:cj-awaresome/template.git filesize
cd filesize

# 查看项目结构
tree -L 2

模板的目录结构:

复制代码
template/
├── README.md              # 项目说明(需要修改)
├── CHANGELOG.md           # 版本日志(需要修改)
├── LICENSE                # 开源协议(需要修改)
├── README.OpenSource      # 开源声明(需要修改)
├── cjpm.toml             # 包配置(需要修改)
├── doc/                  # 文档目录
│   ├── design.md         # 设计文档(需要重写)
│   ├── feature_api.md    # API文档(需要重写)
│   └── assets/           # 资源文件
├── src/                  # 源码目录
│   └── Template.cj       # 模板源码(需要替换)
└── test/                 # 测试目录
    ├── HLT/              # 高层测试
    └── LLT/              # 低层测试

第二步:配置项目基础信息

2.1 修改 cjpm.toml

这是项目的核心配置文件,需要修改为我们的库信息:

toml 复制代码
[dependencies]

[package]
  cjc-version = "1.0.3"
  compile-option = ""
  description = "文件大小格式化工具库 - 将字节数转换为人类可读的格式"
  link-option = ""
  name = "filesize"                    # 修改包名
  output-type = "static"               # 三方库使用 static
  src-dir = ""
  target-dir = ""
  version = "1.0.0"                    # 设置版本号
  package-configuration = {}

关键点

  • name: 包名要与功能相关,简洁明了
  • output-type: 三方库使用 "static",不是 "executable"
  • description: 简短说明库的功能

2.2 更新远程仓库

bash 复制代码
# 修改远程仓库地址
git remote set-url origin git@gitcode.com:cj-awaresome/filesize.git

# 验证修改
git remote -v

第三步:编写核心代码

3.1 创建源文件

删除模板文件,创建我们的 filesize.cj

bash 复制代码
rm src/Template.cj
touch src/filesize.cj

3.2 第一版代码实现

开始编写核心功能。这是一个迭代过程,我先写了一个基础版本:

cangjie 复制代码
package filesize

import std.math.*

// 主格式化函数
public func formatFileSize(size: Int64): String {
    let base = 10
    let roundDigits = 2
    let bits = false
    
    let result = calculateFileSize(size, base, roundDigits, bits)
    return result
}

// 核心计算逻辑
internal func calculateFileSize(size: Int64, base: Int, roundDigits: Int, bits: Bool): String {
    let ceil = if (base == 10) { 1000 } else { 1024 }
    let num = Float64(size)
    var e: Int64 = 0
    
    // 计算指数
    if (num > 0.0) {
        let logVal = log(num) / log(Float64(ceil))
        let floorVal = floor(logVal)
        e = Int64(floorVal)
        if (e < 0) { e = 0 }
        if (e > 8) { e = 8 }
    }
    
    // 计算值
    var val = if (base == 2) {
        num / pow(2.0, Float64(e * 10))
    } else {
        num / pow(1000.0, Float64(e))
    }
    
    if (bits) { val = val * 8.0 }
    
    // 四舍五入
    let factor = pow(10.0, Float64(roundDigits))
    let rounded = round(val * factor) / factor
    
    // 获取单位
    let unit = getUnit(e)
    
    return "${rounded} ${unit}"
}

// 单位映射
private func getUnit(exponent: Int64): String {
    if (exponent == 0) { return "B" }
    if (exponent == 1) { return "KB" }
    if (exponent == 2) { return "MB" }
    if (exponent == 3) { return "GB" }
    if (exponent == 4) { return "TB" }
    if (exponent == 5) { return "PB" }
    if (exponent == 6) { return "EB" }
    if (exponent == 7) { return "ZB" }
    if (exponent == 8) { return "YB" }
    return "B"
}

3.3 第一次编译 - 遇到问题!

bash 复制代码
cjpm build

错误信息

复制代码
Error: the package name in /Users/jianguo/Desktop/cangjie/tpc/template-1/src is wrong, 
the right name should be 'filesize'

问题分析

这是仓颉语言的一个重要特性 - 每个源文件都必须声明它所属的包!我在文件开头添加了 package filesize,但编译器还在报错。

经过排查,发现还有其他文件(constants.cjtypes.cj)也缺少包声明。

解决方案

确保所有 .cj 文件的第一行都是包声明:

cangjie 复制代码
package filesize

// 其他代码...

3.4 第二个问题 - 导入不存在的模块

错误信息

复制代码
Error: root package 'filesize' imports package 'std.string' in its source code, 
but it is not added as a dependency in cjpm.toml

问题分析

我引用了 std.string.*,但实际上仓颉标准库中并不存在这个模块!

解决方案

删除不存在的导入:

cangjie 复制代码
package filesize

import std.math.*
// import std.string.*  ❌ 删除这一行

3.5 第三个问题 - 语法兼容性

在开发过程中,我发现我最初写的一些语法在仓颉中不支持:

问题 1:默认参数

cangjie 复制代码
// ❌ 错误:仓颉不支持默认参数
public func formatFileSize(size: Int64, options: Map<String, Any> = {}): String

// ✅ 正确:使用函数重载或固定参数
public func formatFileSize(size: Int64): String

问题 2:三元运算符

cangjie 复制代码
// ❌ 错误:不支持 ? : 语法
let ceil = base == 10 ? 1000 : 1024

// ✅ 正确:使用 if 表达式
let ceil = if (base == 10) { 1000 } else { 1024 }

问题 3:类型转换方法

cangjie 复制代码
// ❌ 错误:方法名不对
let num = size.toFloat64()

// ✅ 正确:使用类型构造函数
let num = Float64(size)

3.6 成功编译!

修复所有问题后:

bash 复制代码
cjpm build
# 输出:cjpm build success ✅

第四步:编写测试用例

4.1 创建测试文件

bash 复制代码
rm -rf test/HLT test/LLT
touch test/test.cj

4.2 编写测试代码

cangjie 复制代码
package filesize.test

import filesize.*

test "格式化 1KB" {
    let result = formatFileSize(1024)
    println("1024 bytes = ${result}")
    assert(result.contains("KB"))
}

test "格式化 1MB" {
    let result = formatFileSize(1024 * 1024)
    println("1MB = ${result}")
    assert(result.contains("MB"))
}

test "格式化 1GB" {
    let result = formatFileSize(1024 * 1024 * 1024)
    println("1GB = ${result}")
    assert(result.contains("GB"))
}

4.3 运行测试

bash 复制代码
cjpm test
# 输出:cjpm test success ✅

第五步:完善项目文档

5.1 编写 LICENSE

采用 Apache 2.0 开源协议:

bash 复制代码
# 创建完整的 Apache 2.0 协议文件
# 并在文件头部添加版权声明
复制代码
Apache License
Version 2.0, January 2004

Copyright 2025 坚果 (Jianguo)

Licensed under the Apache License, Version 2.0...

5.2 更新 README.md

编写专业的项目说明文档,包括:

markdown 复制代码
# filesize - 文件大小格式化库

## 介绍
简要说明库的功能...

## 项目特性
- ✨ 简单易用
- 📊 自动单位转换
...

## 使用说明
### 安装
### 使用示例

## 开源协议
Apache License 2.0

5.3 编写 CHANGELOG.md

记录版本历史:

markdown 复制代码
# 更新日志

## [1.0.0] - 2025-11-03

### Feature
+ 实现文件大小格式化核心功能
+ 支持 KB、MB、GB 等单位自动转换
...

5.4 编写技术文档

doc/design.md - 设计文档:

  • 架构设计
  • 算法说明
  • 数据流程
  • 性能分析

doc/feature_api.md - API 文档:

  • 函数签名
  • 参数说明
  • 使用示例
  • 注意事项

5.5 更新 README.OpenSource

json 复制代码
[
  {
    "Name": "filesize",
    "License": "Apache License 2.0",
    "License File": "LICENSE",
    "Version": "1.0.0",
    "Owner": "jianguo@nutpi.net",
    "Upstream URL": "https://gitcode.com/cj-awaresome/filesize",
    "Description": "仓颉语言的文件大小格式化工具库"
  }
]

5.6 添加 .gitignore

bash 复制代码
# 创建 .gitignore 文件
cat > .gitignore << 'EOF'
# 编译输出
target/
cjpm.lock

# IDE 配置
.vscode/
.idea/
*.swp

# 系统文件
.DS_Store
EOF

第六步:提交到 Git 仓库

6.1 添加所有文件

bash 复制代码
git add -A
git status

查看待提交的文件:

复制代码
Changes to be committed:
  new file:   .gitignore
  modified:   CHANGELOG.md
  modified:   LICENSE
  modified:   README.OpenSource
  modified:   README.md
  modified:   cjpm.toml
  deleted:    src/Template.cj
  new file:   src/filesize.cj
  modified:   doc/design.md
  modified:   doc/feature_api.md
  deleted:    test/HLT/testcase0001.cj
  deleted:    test/LLT/testcase0001.cj
  new file:   test/test.cj

6.2 提交代码

bash 复制代码
git commit -m "实现 filesize 库:文件大小格式化工具

- 添加 filesize.cj 实现文件大小格式化功能
- 支持 KB, MB, GB 等单位自动转换
- 更新 cjpm.toml 配置,包名改为 filesize
- 添加基础测试用例
- 完善所有文档和开源协议
- 删除模板文件,添加 .gitignore"

6.3 推送到远程仓库

bash 复制代码
git push origin main

输出

复制代码
remote: Start Git Hooks Checking [PASSED]
To gitcode.com:cj-awaresome/filesize.git
 * [new branch]      main -> main

成功!🎉


第七步:后续优化

7.1 修复编译警告

第一次运行时发现有未使用变量的警告:

复制代码
warning: unused variable:'standard'

解决方案:删除未使用的参数

bash 复制代码
git commit -m "修复编译警告,移除未使用的参数"
git push origin main

7.2 移除 main() 函数

三方库不应该包含可执行入口:

cangjie 复制代码
// ❌ 删除 main() 函数
main() {
    println("Testing...")
}
bash 复制代码
git commit -m "完善三方库配置 - 移除 main() 函数"
git push origin main

开发过程中的经验总结

🎯 关键要点

  1. 包声明必不可少

    • 每个 .cj 文件必须以 package 包名 开头
    • 包名要与 cjpm.toml 中的 name 一致
  2. 注意语法差异

    • 仓颉不支持默认参数
    • 使用 if (condition) { value } else { value } 而不是三元运算符
    • 类型转换使用构造函数:Float64(value)
  3. 三方库的特殊要求

    • output-type 必须是 "static"
    • 不应包含 main() 函数
    • 专注于提供可复用的功能
  4. 标准库的使用

    • 仔细检查标准库模块是否存在
    • 数学函数在 std.math.*
    • 不存在 std.string.* 模块

🐛 常见错误及解决方案

错误 原因 解决方案
package name is wrong 缺少包声明 添加 package 包名
imports package 'std.xxx' but not in dependencies 模块不存在或未声明依赖 检查模块是否存在
expected ',' or ')' 语法错误(如默认参数) 使用仓颉支持的语法
undeclared identifier 类型转换方法错误 使用类型构造函数

💡 最佳实践

  1. 从简单开始

    • 先实现核心功能
    • 验证编译通过
    • 再逐步添加特性
  2. 及时测试

    • 每次修改后立即编译
    • 写简单的测试验证功能
    • 不要等到最后才测试
  3. 文档同步

    • 代码和文档同步更新
    • 提供实际可运行的示例
    • 说明清楚每个 API 的用途
  4. 版本管理

    • 使用有意义的提交信息
    • 一个功能一次提交
    • 保持提交历史清晰

项目成果

经过几个小时的开发,我们完成了一个标准的仓颉三方库:

📦 项目统计

  • 源码文件 : 1 个(filesize.cj,64 行)
  • 测试文件 : 1 个(test.cj,22 行)
  • 文档文件: 6 个(README、CHANGELOG、LICENSE、设计文档、API文档等)
  • 总代码行数: ~800 行(含文档)

✅ 完成的功能

  • 文件大小格式化(B 到 YB)
  • 自动单位选择
  • 精度控制(2位小数)
  • 单元测试
  • 完整文档
  • 开源协议

🚀 如何使用

其他开发者可以这样使用我们的库:

cangjie 复制代码
// 在 cjpm.toml 中添加依赖
[dependencies.filesize]
git = "git@gitcode.com:cj-awaresome/filesize.git"

// 在代码中使用
import filesize.*

main() {
    let size = formatFileSize(1048576)
    println(size)  // 输出: 1.05 MB
}

未来展望

v1.1.0 计划

  • 支持配置选项
  • 二进制(1024)和十进制(1000)切换
  • 自定义小数位数

v1.2.0 计划

  • 支持 bits 显示模式
  • IEC 和 JEDEC 标准支持
  • 国际化支持

结语

从零开始开发一个仓颉三方库并不难,关键是要:

  1. 熟悉工具链 - 理解 cjpm 的工作方式
  2. 注意细节 - 包声明、语法规范等
  3. 完善文档 - 好的文档是优秀库的标志
  4. 持续迭代 - 从简单开始,逐步完善

希望这篇文章能帮助更多开发者参与到仓颉生态建设中来。如果你也想开发自己的三方库,不妨从这个模板开始,创造属于你的优秀作品!


相关资源


作者 : Undoom
项目 : filesize v1.0.0
日期 : 2025-11-03
协议: Apache License 2.0

相关推荐
人大博士的交易之路3 小时前
今日行情明日机会——20251104
大数据·数据挖掘·数据分析·缠论·涨停回马枪·道琼斯结构
John Song3 小时前
用zookpeer搭建Hadoop的HA集群,组件启动的启动顺序是什么?
大数据·hadoop·debian
Hello.Reader4 小时前
Flink Table API & SQL 概念、常用 API 与工程落地
大数据·sql·flink
SEO_juper4 小时前
AI SEO实战:利用人工智能提升网站排名与流量的完整策略
人工智能·搜索引擎·百度·ai·seo·数字营销
Empty_7776 小时前
Elasticsearch+Logstash+Filebeat+Kibana部署
大数据·elasticsearch·搜索引擎
武子康6 小时前
大数据-144 Apache Kudu:实时写 + OLAP 的架构、性能与集成
大数据·后端·nosql
敲上瘾8 小时前
Elasticsearch从入门到实践:核心概念到Kibana测试与C++客户端封装
大数据·linux·c++·elasticsearch·搜索引擎·全文检索
api_180079054608 小时前
请求、认证与响应数据解析:1688 商品 API 接口深度探秘
java·大数据·开发语言·mysql·数据挖掘
0和1的舞者11 小时前
网络通信的奥秘:网络层ip与路由详解(四)
大数据·网络·计算机网络·计算机·智能路由器·计算机科学与技术