到仓颉语言网站https://cangjie-lang.cn/download 下载适合自己平台的二进制包。

kylin@kylin-aaa:/data/i$ wget "https://cangjie-lang.cn/v1/files/auth/downLoad?nsId=142267&fileName=cangjie-sdk-linux-aarch64-1.0.5.tar.gz&objectKey=698acfa3bd66ae22b62330b1" -O cj105.tar.gz

2026-08-20 09:55:20 (1.05 MB/s) - 已保存 “cj105.tar.gz” [281794014/281794014])

kylin@kylin-aaa:/data/i$ tar xf cj105.tar.gz
kylin@kylin-aaa:/data/i$ source cangjie/envsetup.sh
kylin@kylin-aaa:/data/i$ cjc -v
cjc: /usr/lib/aarch64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by cjc)
cjc: /usr/lib/aarch64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.11' not found (required by cjc)

解压并设置环境变量后执行cjc,报缺少glibc++动态库错误

kylin@kylin-aaa:/data/i$ sudo docker start p13
p13
kylin@kylin-aaa:/data/i$ sudo docker exec -it p13 bash
root@kylin-aaa:/# cd /par
root@kylin-aaa:/par# source cangjie/envsetup.sh
root@kylin-gtj:/par# cjc -v
Cangjie Compiler: 1.0.5 (cjnative)
Target: aarch64-unknown-linux-gnu

启动一个包含动态库的docker容器,可以执行cjc -v了。

// hello.cj
main() {
    println("你好,仓颉")
}

编译源代码hello.cj,结果如下

root@kylin-gtj:/par# cjc hello.cj -o hello

root@kylin-gtj:/par# ./hello
你好,仓颉

还可以用cjpm命令管理一个项目。

root@kylin-gtj:/par# mkdir cj
root@kylin-gtj:/par# cd cj
root@kylin-gtj:/par/cj# cjpm init
cjpm init success

root@kylin-gtj:/par/cj# ls
cjpm.toml  src
root@kylin-gtj:/par/cj# cjpm run
hello world

cjpm run finished

再用一个递归的斐波那契数列函数来测试编译后的二进制文件性能。

//package somethinglike 这个是我的文件名
func fib(n: Int64):Int64{
    match (n){//match函数相当于是C++中的switch函数
        case 0 | 1 => n//当n=0或1时输出n本身
        case other where other > 0 =>
            fib(other - 1)+fib(other - 2)
        case _ => 0//不符合斐波那契数列定义的输入返回0,case _相当于是default
    }
}
main(){
    println(fib(-1))
    for(i in 42..=42){//从1到10,如果没有=,相当于是1<=i<10,即1到9
        print("${fib(i)} ")//也可以使用println,但是每输出一个结果就会换行
    }
}

先用默认编译,执行速度较慢。

root@kylin-gtj:/par# cjc fib.cj -o fib
root@kylin-gtj:/par# time ./fib
0
267914296 
real	0m9.151s
user	0m9.156s
sys	0m0.000s
root@kylin-gtj:/par# cjc -h
Usage:
      cjc [option] file...

  -O0                         Optimization level 0 (default)
  -O, -O1                     Optimization level 1
  -O2                         Optimization level 2
  -Os                         Optimization level s, like -O2 with extra optimizations for size
  -Oz                         Optimization level z, like -Os but reduces code size further
  -O<value>                   Set Optimization level
root@kylin-aaa:/par# cjc fib.cj -o fib -O2
root@kylin-aaa:/par# time ./fib
0
267914296 
real	0m1.563s
user	0m1.556s
sys	0m0.000s
root@kylin-aaa:/par# ls -l fib*
-rwxr-xr-x 1 root     root     991400 Aug 20 02:27 fib
-rw-rw-r-- 1 postgres postgres    590 Aug 20 02:25 fib.cj

可见类似gcc, 有-O系列优化级别。-O2比默认快了好几倍。
编译完成的二进制文件较大,几乎什么都不干都有900KB。
再来编译一个导入标准库的源代码。

//package cjcDemo

// 导入必要的标准库模块
import std.convert.*    // 数据类型转换模块
import std.console.*    // 控制台输入输出模块

// 定义一个函数,读取用户输入的整数,并返回 Int64 类型的值
func inputInt(info: String): Int64 {
    print(info)  // 输出提示信息到控制台
    let number: Int64 = Int64.parse(Console.stdIn.readln().getOrThrow())  // 读取用户输入并转换为 Int64
    return number  // 返回输入的整数
}

// 计算斐波那契数列的第 n 项,并返回该项的值及完整数列
func fibonacci(n: Int64): (Int64, Array<Int64>) {
    // 创建一个大小为 n+1 的数组,用于存储斐波那契数列的各项,初始化为 0
    let dp = Array<Int64>(n + 1, repeat: 0)
    
    // 如果 n 大于 0,则设置第一项为 1(F(1) = 1)
    if (n > 0) {
        dp[1] = 1
    }

    // 使用循环计算斐波那契数列的每一项,避免重复计算
    for (i in 2..=n) {
        dp[i] = dp[i - 1] + dp[i - 2]  // 当前项为前两项之和
    }

    // 返回第 n 项的值和完整的斐波那契数列数组
    return (dp[n], dp)
}

// 主函数,程序入口
main(): Int64 {
    // 调用 inputInt 函数,提示用户输入非负整数 n
    let n = inputInt("请输入一个非负整数 n: ")

    // 调用 fibonacci 函数,计算第 n 项及完整的斐波那契数列
    let (result, sequence) = fibonacci(n)

    // 输出第 n 项的值
    println("F(${n}) = ${result}")

    // 输出斐波那契数列的所有项
    println("斐波那契序列:")
    for (i in 0..sequence.size) {
        println("F(${i}) = ${sequence[i]}")  // 按格式输出每一项的值
    }

    return 0  // 返回 0 表示程序成功执行
}


可能是版本更新原因,console被废弃了,但还能编译通过。二进制文件膨胀到了3MB。

root@kylin-aaa:/par# cjc demo.cj -o demo -O2
warning: class 'Console' is deprecated. Use related global functions in the std.env instead.
  ==> demo.cj:10:37:
   | 
10 |     let number: Int64 = Int64.parse(Console.stdIn.readln().getOrThrow())  // 读取用户输入并转换为 Int64
   |                                     ^^^^^^^ deprecated
   | 
   # note: this warning can be suppressed by setting the compiler option `-Woff deprecated`

1 warning generated, 1 warning printed.

root@kylin-aaa:/par# ls -l ./demo
-rwxr-xr-x 1 root root 3207584 Aug 20 02:51 ./demo

root@kylin-aaa:/par# ./demo
请输入一个非负整数 n: 42
F(42) = 267914296
斐波那契序列:
F(0) = 0
F(1) = 1
..
F(42) = 267914296

还能检查数组越界,抛出异常。

root@kylin-aaa:/par# ./demo
请输入一个非负整数 n: -1
An exception has occurred:
IndexOutOfBoundsException: The length of the array is 0, but the index is -1.
	 at default.fibonacci(Int64)(/par/demo.cj:30)
	 at default.main()(/par/demo.cj:39)

希望用-Os和-Oz优化大小,并没有效果。

root@kylin-aaa:/par# 
root@kylin-aaa:/par# cjc demo.cj -o demo -Os
warning: class 'Console' is deprecated. Use related global functions in the std.env instead.
  ==> demo.cj:10:37:
   | 
10 |     let number: Int64 = Int64.parse(Console.stdIn.readln().getOrThrow())  // 读取用户输入并转换为 Int64
   |                                     ^^^^^^^ deprecated
   | 
   # note: this warning can be suppressed by setting the compiler option `-Woff deprecated`

1 warning generated, 1 warning printed.
root@kylin-aaa:/par# ls -l ./demo
-rwxr-xr-x 1 root root 3207304 Aug 20 05:43 ./demo
root@kylin-aaa:/par# cjc demo.cj -o demo -Oz
warning: class 'Console' is deprecated. Use related global functions in the std.env instead.
  ==> demo.cj:10:37:
   | 
10 |     let number: Int64 = Int64.parse(Console.stdIn.readln().getOrThrow())  // 读取用户输入并转换为 Int64
   |                                     ^^^^^^^ deprecated
   | 
   # note: this warning can be suppressed by setting the compiler option `-Woff deprecated`

1 warning generated, 1 warning printed.
root@kylin-aaa:/par# ls -l ./demo
-rwxr-xr-x 1 root root 3207304 Aug 20 05:43 ./demo
root@kylin-aaa:/par# cjc demo.cj -o demo -O1 -Woff deprecated
root@kylin-aaa:/par# ls -l ./demo
-rwxr-xr-x 1 root root 3207392 Aug 20 05:44 ./demo

用ldd命令检查,可见它除了依赖glibc的动态库,还依赖sdk中的libcangjie-runtime.so和libboundscheck.so。如果它们不在环境变量搜索路径中,就会报not found。

kylin@kylin-aaa:/data/i$ ldd demo
./demo: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./demo)
./demo: /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.27' not found (required by ./demo)
./demo: /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by ./demo)
	linux-vdso.so.1 =>  (0x0000007faf955000)
	/usr/lib/libzfh.so (0x0000007faf4b0000)
	libcangjie-runtime.so => not found
	libboundscheck.so => not found
	libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000007faf3e3000)
	libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007faf29c000)
	/lib/ld-linux-aarch64.so.1 (0x0000007faf92a000)
	libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007faf270000)
	libdl.so.2 => /lib/aarch64-linux-gnu/libdl.so.2 (0x0000007faf25d000)

奇怪的是,linux aarch64版本sdk中还包含windows x64的库文件,难道用来交叉编译?

root@kylin-gtj:/par# ls -l cangjie/lib
total 2044
-rwxr-x--- 1 postgres postgres 1007104 Feb 28  2023 libstdFFI.dll
-rwxr-x--- 1 postgres postgres   75482 Feb 28  2023 libstdFFI.dll.a
-rwxr-x--- 1 postgres postgres  995728 Feb 28  2023 libstdFFI.so
drwxr-x--- 2 postgres postgres    4096 Feb 28  2023 linux_aarch64_cjnative
drwxr-x--- 2 postgres postgres    4096 Feb 28  2023 windows_x86_64_cjnative
Logo

一站式 AI 云服务平台

更多推荐