# 外部语言封装规范
在 Syslab 平台,我们提供了基于 Julia 的函数库。对于那些使用 C/C++ 或 Python 开发的外部语言函数库,我们可以通过封装成 Julia 函数库来快速集成到 Syslab 平台中。这种封装的方式使得外部语言函数库能够与 Syslab 平台进行无缝集成。通过将外部语言函数库进行封装,我们可以提供统一的接口,使得用户可以直接在 Julia 中调用这些外部语言函数库的功能,而无需关注底层的实现细节和语言差异。
封装外部语言函数库的过程往往涉及到对函数接口的映射和数据类型的转换,以确保外部语言函数库在 Syslab 平台中的正常运行。
# C/C++ 语言封装规范
# 对 C/C++ 库的要求
为了满足跨平台的要求,对于使用 C/C++ 开发的函数库,我们需要同时提供适用于 Windows 和 Linux 系统的库文件,即动态链接库(DLL)和共享对象库(SO)。
通过提供 DLL 和 SO 库,我们可以确保函数库在不同操作系统下的兼容性。DLL 是 Windows 平台上常见的库文件格式,而 SO 则是 Linux 平台上的标准库文件格式。通过同时提供这两种库文件,可以为不同的操作系统封装相应的函数库。
# ccall 组件
ccall组件是 Julia 语言内核提供的调用 C/C++ 动态库的模块。通过ccall组件可以将 C/C++ 函数封装成Julia函数。ccall函数使用方法如下:
ccall((function_name, library), returntype, (argtype1, ...), argvalue1, ...)
ccall(function_name, returntype, (argtype1, ...), argvalue1, ...)
ccall(function_pointer, returntype, (argtype1, ...), argvalue1, ...)
其中,参数解释如下:
function_name:需要调用的 C 函数名
library:包含函数的 C 库文件名
returntype:函数的返回类型
argtype:函数的输入参数类型列表
argvalue:函数的输入参数值
# 数据类型转换
使用ccall函数调用 C++ 库函数时,需要遵循 C/C++ 数据类型与 Julia 数据类型之间的映射规则。目前,基本的 C/C++ 值类型可以转换为 Julia 类型,以 C 为前缀。Julia 数据类型转换为 C/C++ 数据类型的对应关系如下表所示:
| C 类型 | 标准 Julia 别名 | Julia 基本类型 |
|---|---|---|
| unsigned char | Cuchar | UInt8 |
| bool (_Bool in C99+) | Cuchar | UInt8 |
| short | Cshort | Int16 |
| unsigned short | Cushort | UInt16 |
| int, BOOL (C, typical) | Cint | Int32 |
| unsigned int | Cuint | UInt32 |
| long long | Clonglong | Int64 |
| unsigned long long | Culonglong | UInt64 |
| intmax_t | Cintmax_t | Int64 |
| uintmax_t | Cuintmax_t | UInt64 |
| float | Cfloat | Float32 |
| double | Cdouble | Float64 |
| complex float | ComplexF32 | Complex{Float32} |
| complex double | ComplexF64 | Complex{Float64} |
| ptrdiff_t | Cptrdiff_t | Int |
| ssize_t | Cssize_t | Int |
| size_t | Csize_t | UInt |
| void | / | Cvoid |
| void and [[noreturn]] or _Noreturn | / | Union{} |
| void* | / | Ptr{Cvoid} (或 Ref{Cvoid}) |
| T* (where T represents an appropriately defined type) | / | Ref{T} (只有当 T 是 isbits 类型时,T 才可以安全地转变) |
| char* (or char[], e.g. a string) | / | Cstring if NUL-terminated, or Ptr{UInt8} if not |
| char** (or *char[]) | / | Ptr{Ptr{UInt8}} |
| jl_value_t* (any Julia Type) | / | Any |
| jl_value_t* const*(一个 Julia 值的引用) | / | Ref{Any}(常量,因为转变需要写屏障,不可能正确插入) |
| va_arg | / | Not supported |
| ... (variadic function specification) | / | T...(其中 T 是上述类型之一,当使用 ccall 函数时) |
| ... (variadic function specification) | / | ; va_arg1::T、va_arg2::S 等(仅支持 @ccall 宏) |
# Python 语言封装规范
# PyCall 组件
PyCall是 Julia 语言调用 Python 库的组件,这个组件提供了直接调用 Python 库并与 Python 完全互操作的能力。通过 PyCall组件可以将 Python 函数封装成 Julia 函数。
PyCall组件可以从 Julia 导入任意的 Python 模块,调用 Python 函数(在 Julia 和 Python 之间自动转换类型),从 Julia 方法定义 Python 类,并在 Julia 和 Python 之间共享大型数据结构。
# 数据类型转换
在使用 PyCall 调用 Python 函数或库时,需要使用 Python object interfaces 来表示和操作 Python 对象,这些接口如下表所示:
| Python 对象 | 功能描述 |
|---|---|
| PyObject | 一个表示 Python 对象的 Julia 类型。通常情况下,Python object 的返回值都是 PyObject 类型 |
| PyNone | 表示 Python 中的 None 对象 |
PyCall.PyString | 表示 Python 中的字符串对象。可以通过string函数将 Julia 的字符串转换为PyCall.PyString对象 |
PyCall.PyDict | 表示 Python 中的字典对象。可以通过Dict函数将 Julia 字典转换为PyCall.PyDict对象,并且可以使用get,setindex和index 等函数进行访问 |
PyCall.PyTuple | 表示 Python 中的元组对象。可以通过Tuple函数将 Julia 元组转换为PyCall.PyTuple对象,并且可以使用getindex和setindex等函数进行访问 |
PyCall.PyArray | 表示 Python 中的数组对象。可以通过传递 NumPy 数组到PyCall.PyArray函数,得到等效于 python 的 ndarray 的 Julia 对象,PyArray 还支持广播 |
PyCall.PyAny | 表示 Python 中的任何对象。可以在函数的参数列表中使用 PyAny,以便接受任何 Python 对象或类型 |
这些 Python object interfaces 提供了一些基本的 API,使得 Julia 可以与 Python 交互,并且可以方便地访问和操作 Python 对象。同时,PyCall还提供了一些额外的函数和工具,可以帮助用户更方便地使用 Python 库。