بنقرة واحدة
cangjie-ffi-build
仓颉FFI/C互操作配置构建指导。当需要了解仓颉 C 互操作项目的配置/构建/运行方法(包括动态库、静态库及不同平台),应使用此 Skill
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
仓颉FFI/C互操作配置构建指导。当需要了解仓颉 C 互操作项目的配置/构建/运行方法(包括动态库、静态库及不同平台),应使用此 Skill
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
当需要构建鸿蒙应用项目时,使用此 Skill 执行构建流程。此 Skill 包含完整的构建命令、构建流程说明、构建失败处理流程。构建脚本会自动执行依赖安装、仓颉预编译、资源生成、编译、打包等步骤。
在鸿蒙应用(Cangjie)开发中,当需要使用 stdx 拓展库(如 crypto、encoding、net、log、actors 等),或在构建/链接阶段出现 stdx 相关错误时,使用此 Skill 获取/解压 stdx 包,并指导在 entry/cjpm.toml 中正确配置 bin-dependencies.path-option。
在进行仓颉工程或鸿蒙应用开发时的第一步,应该优先读取该SKILL,用来确定后续的开发步骤。
仓颉语言内置注解。当需要了解仓颉 SDK 提供的内置注解(@sourcePackage/@sourceFile/@sourceLine/@When/@FastNative/@Frozen/@Attribute/@Deprecated)的用途、语法和最优实践时,应使用此 Skill。
仓颉语言附录参考。当需要查阅仓颉语言的关键字列表、运算符优先级与结合性、运算符重载函数签名、运行时环境变量配置、包兼容性规则、TokenKind枚举类型时,应使用此 Skill。
仓颉标准库 Array 类型详细指南。当需要了解 Array 的构造、元素访问、切片、拼接、查找、排序、拷贝、反转、映射、扁平化等操作的完整 API 和用法时,应使用此 Skill。
| name | cangjie-ffi-build |
| description | 仓颉FFI/C互操作配置构建指导。当需要了解仓颉 C 互操作项目的配置/构建/运行方法(包括动态库、静态库及不同平台),应使用此 Skill |
| 平台 | 动态库 | 静态库 |
|---|---|---|
| Linux | lib<name>.so | lib<name>.a |
| macOS | lib<name>.dylib | lib<name>.a |
| Windows | lib<name>.dll | lib<name>.lib |
注意:Windows 平台上依赖动态库,目前 cjc 和 cjpm 实现有差异:编译时,cjc 对动态库是否有
lib前缀不敏感,cjpm 则要求动态库必须有lib前缀。运行时,cjc 编出的可执行文件,依赖的动态库必须加上lib前缀,而 cjpm 构建出的可执行文件,依赖的动态库一定不能有lib前缀。请务必熟悉这个规则(实际是规格问题,未来会修复),保证能正常构建和运行。
| 选项 | 说明 |
|---|---|
-L <path> / --library-path <path> | 指定库文件搜索目录(优先级高于 LIBRARY_PATH 环境变量) |
-l <name> / --library <name> | 链接库文件,格式为 lib[name].[extension](如 -l draw 链接 libdraw.so/.a/.dll) |
# 编译 C 代码为动态库
clang -shared -fPIC -fstack-protector-all native.c -o libnative.so
# 编译 C 代码为静态库
clang -c -fstack-protector-all native.c -o native.o && ar rcs libnative.a native.o
# 编译仓颉代码并链接
cjc -L . -l native main.cj -o main
# 运行(动态库须确保在搜索路径上)
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main
# 编译 C 代码为动态库
clang -shared -fPIC -fstack-protector-all native.c -o libnative.dylib
# 编译 C 代码为静态库
clang -c -fstack-protector-all native.c -o native.o && ar rcs libnative.a native.o
# 编译仓颉代码并链接
cjc -L . -l native main.cj -o main
# 运行(动态库须确保在搜索路径上)
export DYLD_LIBRARY_PATH=.:$DYLD_LIBRARY_PATH
./main
# 编译 C 代码为动态库(导出函数需加 __declspec(dllexport) 修饰)
clang -shared -fstack-protector-all native.c -o libnative.dll
# 编译仓颉代码并链接
cjc -L . -l native main.cj -o main.exe
# 运行(动态库须确保在搜索路径上)
./main.exe
注意:Windows 平台上 C 函数需使用
__declspec(dllexport)修饰以导出符号。
编译 C 代码时应启用栈保护选项,防止缓冲区溢出攻击:
# 推荐选项(二选一)
clang -fstack-protector-all ... # 全部函数开启栈保护
clang -fstack-protector-strong ... # 对含局部数组/地址操作的函数开启栈保护
cjpm init # 初始化项目
在 cjpm.toml 中通过 [ffi.c] 节配置 C 库依赖:
[package]
name = "myproject"
cjc-version = "1.0.5"
version = "1.0.0"
output-type = "executable"
[ffi.c]
native = { path = "./libs/" } # path 是 C 动态/静态库所在路径
cjpm build # 构建时自动链接 [ffi.c] 设置的 C 库
cjpm run # 构建并运行
| 配置项 | 说明 | 示例 |
|---|---|---|
output-type | 输出类型 | "executable" / "static" / "dynamic" |
compile-option | 传给 cjc 的额外编译选项 | "-O1" |
link-option | 传给链接器的选项 | "-z noexecstack -z relro -z now" |
当需要区分不同目标平台的库路径时,可使用 [target] 节:
Linux x86_64:
[ffi.c]
native = { path = "./libs/linux_x86_64/" }
macOS aarch64:
[ffi.c]
native = { path = "./libs/macos_aarch64/" }
Windows x86_64:
[ffi.c]
native = { path = ".\\libs\\windows_x86_64\\" }
对于需要安全加固的项目,建议在 link-option 中添加链接器安全标志:
[package]
link-option = "-z noexecstack -z relro -z now"
| 选项 | 说明 |
|---|---|
-z noexecstack | 禁止栈上执行代码,防止栈溢出攻击 |
-z relro | 设置 GOT 为只读,防止 GOT 覆写攻击 |
-z now | 立即绑定所有符号,配合 relro 使用 |
# 1. 编写 C 代码 (native.c)
# 2. 编译 C 代码为动态库
clang -shared -fPIC -fstack-protector-all native.c -o libnative.so
# 3. 使用 cjc 直接编译
cjc -L . -l native main.cj -o main
./main
# 或使用 cjpm 项目编译
# 将 libnative.so 放到 libs/ 目录下
# 在 cjpm.toml 中配置 [ffi.c] native = { path = "./libs/" }
cjpm build && cjpm run
# 1. 编写 C 代码 (native.c),导出函数加 __declspec(dllexport) 修饰
# 2. 编译 C 代码为动态库
clang -shared -fstack-protector-all native.c -o libnative.dll
# 3.1 使用 cjc 编译
cjc -L . -l native main.cj -o main.exe
./main.exe
# 3.2 基于 cjpm 项目构建
# 将 libnative.dll 放到 libs/ 目录下(用于编译链接)
# 基于前面提到的运行问题,libs/ 下还应放一个名为 native.dll 的副本
# 在 cjpm.toml 中配置 [ffi.c] native = { path = "./libs/" }
# 构建,依赖 libnative.dll
cjpm build
# 运行,依赖 native.dll
cjpm run