仓颉笔记:仓颉调用C语言
编写 C,编译成 lib
c
#include<stdio.h>
#include<stdint.h>
typedef struct {
int64_t x;
int64_t y;
} Point;
typedef struct {
float x;
float y;
float z;
} Cube;
extern "C"
int32_t drawPicture(Point* point, Cube* cube) {
point->x = 1;
point->y = 2;
printf("Draw Point finished.\n");
printf("Before draw cube\n");
printf("%f\n", cube->x);
printf("%f\n", cube->y);
printf("%f\n", cube->z);
cube->x = 4.4;
cube->y = 5.5;
cube->z = 6.6;
printf("Draw Cube finished.\n");
return 0;
}
cmake_minimum_required(VERSION 3.28)
project(demo)
set(CMAKE_CXX_STANDARD 17)
#add_executable(demo main.cpp)
# 指定输出的 DLL 名称
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) # 使得所有符号被导出
add_library(demo SHARED main.cpp) # 创建一个共享库(DLL)
查看导出符号
编译完会生成 libdemo.dll
,复制到仓颉工程目录。
Windows
下可使用 VS Powershell
的 dumpbin /EXPORTS .\libdemo.dll
查看导出的符号是否正常。
Dump of file .\libdemo.dll
File Type: DLL
Section contains the following exports for libdemo.dll
00000000 characteristics
674C3898 time date stamp Sun Dec 1 18:21:12 2024
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 00008DD0 _Z6printfPKcz
2 1 000014B0 drawPicture
编写仓颉程序
cj
package call_c
@C
struct Point {
var x: Int64 = 0
var y: Int64 = 0
}
@C
struct Cube {
var x: Float32 = 0.0
var y: Float32 = 0.0
var z: Float32 = 0.0
init(x: Float32, y: Float32, z: Float32) {
this.x = x
this.y = y
this.z = z
}
}
foreign func drawPicture(point: CPointer<Point>, cube: CPointer<Cube>): Int32
main() {
let pPoint = unsafe { LibC.malloc<Point>() }
let pCube = unsafe { LibC.malloc<Cube>() }
var cube = Cube(1.1, 2.2, 3.3)
unsafe {
pCube.write(cube)
drawPicture(pPoint, pCube) // in which x, y will be changed
println(pPoint.read().x)
println(pPoint.read().y)
println(pCube.read().x)
println(pCube.read().y)
println(pCube.read().z)
LibC.free(pPoint)
LibC.free(pCube)
}
}
编译仓颉程序并链接库
sh
# 编译,在当前目录下查找 libdemo.dll
cjc -L . -l demo ./main.cj
也可以用 CJPM
配置 link-option
,然后就可以用 cjpm build
编译了。
toml
[dependencies]
[package]
cjc-version = "0.57.3"
compile-option = ""
description = "nothing here"
link-option = "-L . -l demo"
name = "call_c"
output-type = "executable"
override-compile-option = ""
src-dir = ""
target-dir = ""
version = "1.0.0"
package-configuration = {}
通过配置ffi.c链接(推荐)
toml
[ffi.c]
demo = { path = "libs/demo" } # libs/demo/libdemo.dll
映射规则
cj
// typedef void (*startDocumentSAXFunc) (void *ctx);
type StartDocumentFunc = CFunc<(CPointer<Unit>) -> Unit>
// typedef void (*endDocumentSAXFunc) (void *ctx);
type EndDocumentFunc = CFunc<(CPointer<Unit>) -> Unit>
// typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, const xmlChar **atts);
type StartElementFunc = CFunc<(CPointer<Unit>, CString, CPointer<CPointer<UInt8>>) -> Unit>
// typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
type EndElementFunc = CFunc<(CPointer<Unit>, CString) -> Unit>
// typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, const xmlChar *value);
type CharactersFunc = CFunc<(CPointer<Unit>, CString, UInt32) -> Unit>
// void SAX_HandlesCreate(startDocumentSAXFunc sd, endDocumentSAXFunc ed, startElementSAXFunc se, endElementSAXFunc ee, charactersSAXFunc charsse, const char *file_name);
foreign func SAX_HandlesCreate(sd: StartDocumentFunc, ed: EndDocumentFunc, se: StartElementFunc, ee: EndElementFunc, chars: CharactersFunc, buff: CString): Unit