Skip to content

仓颉笔记:仓颉调用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 Powershelldumpbin /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

最后编辑时间:

Version 4.3