# 使用 julia 代码创建 C 共享库
此示例说明了如何使用 julia 函数创建 C 共享库。
注意
Syslab AppBundler 暂不支持在 Syslab Online 中使用。
# 1. 创建独立文件夹
准备一个独立的文件夹,其中包含用户依赖的 jl 文件以及一些其他的资源文件。
在此示例中,创建一个 example 的空文件夹。
# 2. 创建 Julia 函数
在 example 文件夹中创建 main.jl 文件,并在其中创建函数。
代码如下:
using TyMath
function add(a1, a2)
return a1 + a2
end
function multiply_string(a1, a2)
return a1 * a2
end
function eig_matrix(A)
V,D,W = eig(A)
return V,D,W
end
测试 julia 函数,执行 main.jl 文件,在 julia 终端输入:
add(3,4)
输出为:
7
在 julia 终端输入:
add(1.2+1.5im,3.4+2.8im)
输出为:
4.6 + 4.3im
在 julia 终端输入:
multiply_string("hello ","world!")
输出为:
"hello world!"
在 julia 终端输入:
V,D,W = eig_matrix([1 7 3; 2 9 12; 5 22 7])
输出为:
V =
3×3 Matrix{ComplexF64}:
-0.260977+0.0im -0.973445+0.0im 0.189104+0.0im
-0.587027+0.0im 0.228061+0.0im -0.581573+0.0im
-0.766349+0.0im -0.0198078+0.0im 0.79121+0.0im
D =
3×3 Matrix{ComplexF64}:
25.5548+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im -0.578934+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im -7.9759+0.0im
W =
3×3 Matrix{ComplexF64}:
-0.179108+0.0im -0.958733+0.0im -0.188133+0.0im
-0.812659+0.0im 0.0648539+0.0im -0.74771+0.0im
-0.554531+0.0im 0.276814+0.0im 0.636817+0.0im
# 3. 创建 C 共享库
在 example 文件中创建 build.jl 文件,用于构建 C 共享库。
使用以下模板代码,填写对应信息后构建 C 共享库。
using TyAppBundler
# 动态库名称
library_name = "libexample"
# 打包文件夹
src_dir = @__DIR__
# 目标文件夹
dest_dir = joinpath(dirname(src_dir), library_name)
# 主文件
user_file = joinpath(src_dir, "main.jl")
# 依赖函数库
deps = ["TyMath"]
# 是否打包 runtime
has_runtime = false
# 是否创建日志文件(若创建日志文件,则输出不会在终端打印)
create_log_file = false
# 是否需要加密代码
encrypt = true
# 是否覆盖目标文件夹(如果文件夹已存在)
force = false
# 需要打包的函数,结构为(c 函数名称,julia 函数名称,julia 输入类型,julia 输出类型)
# 对于同一个 julia 函数,可以根据不同的输入输出,生成不同的 c 函数
func1 = TyAppBundler.CFuncInfo("add_int64_t", "add", (Int64, Int64), (Int64,))
func2 = TyAppBundler.CFuncInfo("add_double_complex", "add", (ComplexF64, ComplexF64), (ComplexF64,))
func3 = TyAppBundler.CFuncInfo("multiply_string", "multiply_string", (String, String), (String,))
func4 = TyAppBundler.CFuncInfo("eig_matrix","eig_matrix", (Array,), (Array,Array,Array))
func_list = [func1, func2, func3, func4]
# 开始构建
TyAppBundler.bundle_clibrary(
src_dir,
dest_dir,
user_file,
deps,
func_list;
library_name=library_name,
has_runtime=has_runtime,
create_log_file=create_log_file,
encrypt=encrypt,
force=force,
)
TyAppBundler.CFuncInfo 数组,每一个元素包含(c 函数名,julia 函数名,julia 输入类型,julia 输出类型),代表一个需要打包的函数,支持的 julia 输入输出类型及对应的 C 类型表格如下:
| C 类型 | 标准 Julia 别名 | Julia 基本类型 |
|---|---|---|
| int8_t | / | Int8 |
| uint8_t | Cuchar | UInt8 |
| int16_t | Cshort | Int16 |
| uint16_t | Cushort | UInt16 |
| int32_t | Cint | Int32 |
| uint32_t | Cuint | UInt32 |
| int64_t | Clonglong | Int64 |
| uint64_t | Culonglong | UInt64 |
| float | Cfloat | Float32 |
| double | Cdouble | Float64 |
| complex_float | ComplexF32 | Complex{Float32} |
| complex_double | ComplexF64 | Complex{Float64} |
| char * | / | String |
| jlArray * | / | Array |
运行 build.jl 文件进行打包,打包完成后会在目标文件夹下获得以下文件:

# 4. 在 C 应用程序中实现 C 共享库
打包 C 共享库后,您可以从 C 应用程序中调用它。使用 C 应用程序代码调用共享库中包含的函数。
在上述目标文件夹中创建 main.c 文件,内容如下:
#include <stdio.h> #include "libexample.h" #include <string.h> void jlarray_print_info(const jlArray* arr) { if (!arr) { printf("NULL array\n"); return; } int i,j; int row,col; row = arr->size[0]; col = arr->size[1]; // 打印二维数组 if(arr->complexflag){ for(i = 0; i < row; i++){ for(j = 0; j < col; j++){ complex_double v = ((complex_double*)arr->data)[j * row + i]; printf("%6f + %6fi\t", v.real, v.imag); } printf("\n"); } }else{ for(i = 0; i < row; i++){ for(j = 0; j < col; j++){ printf("%6f\t",((double *)arr->data)[j * row + i]); } printf("\n"); } } printf("\n"); } int main() { if (!jlInitializeApplication()){ fprintf(stderr, "%s\n", "init julia failed!"); return -1; } if (!libexampleInitialize()){ fprintf(stderr, "%s\n", "init library failed!"); return -1; } // add_int64_t int64_t add_input1 = 3; int64_t add_input2 = 4; int64_t add_output1; int retcode = add_int64_t(&add_output1, add_input1, add_input2); if(!retcode){ printf("add_int64_t failed\n"); return -1; } printf("add_output1 = %lld\n\n", add_output1); // add_double_complex complex_double add_complex_input1 = { 1.2 , 1.5 }; complex_double add_complex_input2 = { 3.4 , 2.8 }; complex_double add_complex_output1; retcode = add_double_complex(&add_complex_output1, add_complex_input1, add_complex_input2); if(!retcode){ printf("add_double_complex failed\n"); return -1; } printf("add_complex_output1 = %4.2f + %4.2fi\n\n", add_complex_output1.real, add_complex_output1.imag); // multiply_string char str_input1[] = "hello "; char str_input2[] = "world!"; char* str_output1; retcode = multiply_string(&str_output1, str_input1, str_input2); if(!retcode){ printf("multiply_string failed\n"); return -1; } printf("str_output1 = %s\n\n",str_output1); jlDestroyString(str_output1); //eig_matrix int sizes_arr[] = {3,3}; double data[] = {1,2,5,7,9,22,3,12,7}; // 矩阵采用列主 jlArray* arr_input1; arr_input1 = jlCreateArray(2,sizes_arr,jlFloat64,jlReal); memcpy(arr_input1->data, data, 9*sizeof(double)); jlArray* arr_output1 = NULL; jlArray* arr_output2 = NULL; jlArray* arr_output3 = NULL; retcode = eig_matrix(&arr_output1, &arr_output2, &arr_output3, arr_input1); if(!retcode){ printf("eig_matrix failed\n"); return -1; } printf("arr_output1 =\n"); jlarray_print_info(arr_output1); printf("arr_output2 =\n"); jlarray_print_info(arr_output2); printf("arr_output3 =\n"); jlarray_print_info(arr_output3); jlDestroyArray(arr_output1); jlDestroyArray(arr_output2); jlDestroyArray(arr_output3); libexampleTerminate(); jlTerminateApplication(); return 0; }启动系统命令提示符,导航至目标文件夹,使用 gcc 编译并链接应用程序(此步骤需要安装 gcc)。
Windows:
gcc main.c -o main.exe -I. -L. -lexampleLinux:
gcc main.c -o main -I. -L. -lexample -Wl,-rpath,.
提示
若要使用 Visual Studio 编译并链接应用程序,需要添加 libexample.lib 依赖项,使用 libexample.h 头文件和 main.c 源文件生成 exe 可执行文件,最后将 exe 可执行文件拷贝至 libexample.dll 同级目录后可正常运行。
要在 Linux 系统上编译或运行该应用程序(脱离 Syslab ),需要将 Runtime 添加到 LD_LIBRARY_PATH 库路径中。
如果打包时设置 has_runtime 为 false,则需要安装 Syslab,在 LD_LIBRARY_PATH 中添加 <JULIA_HOME>/lib 和 <JULIA_HOME>/lib/julia 路径。<JULIA_HOME> 的值为 Syslab 中 julia 的路径,以 Syslab 2025b 为例,<JULIA_HOME> 的值为 <Syslab安装目录>/Tools/julia-1.9.3。执行命令如下:
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}\ <JULIA_HOME>/lib:\ <JULIA_HOME>/lib/julia:"如果打包时设置 has_runtime 为 true,则无需安装 Syslab,在 LD_LIBRARY_PATH 中添加 <APP_DIR>/julia/lib 和 <APP_DIR>/julia/lib/julia 路径,其中<APP_DIR>为打包文件夹的路径。执行命令如下:
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}\ <APP_DIR>/julia/lib:\ <APP_DIR>/julia/lib/julia:"
从系统命令提示符运行该应用程序。
首次执行会进行预编译,需要等待一段时间。
Windows:
.\main.exeLinux:
./main运行结果:

# 5. 部署 c 共享库
打包好的文件夹即为最终部署产物,将该文件夹拷贝到用户指定机器即可使用,无需安装。
该示例需要依赖 Syslab 运行,若用户不想依赖 Syslab 就可运行部署应用程序,则需要在步骤 3 创建 C 共享库中,将 has_runtime 设置为 true。
# 6. 局限性
不支持一个 C/C++ 应用程序同时调用多个 syslab 打包的动态库。
注意
初次运行或移动文件夹后运行应用程序均需要预编译,此过程会花费一定时间,此时无需操作,等待编译结束即可;
如果打包依赖了多个 jl 文件或依赖了外部资源文件,则需要将这些文件全部放在打包文件夹中,并在 jl 代码中使用相对路径进行引用;
执行打包脚本需要在全局环境下进行,如果用户代码依赖了本地开发的函数库,需要将该函数库安装在全局环境中,并在打包脚本中将该函数库添加至依赖函数库中;
若用户选择打包 Runtime,且打包产物中存在 miniforge3 文件夹,则打包的文件夹不能放在中文路径下,这会导致 TyPlot 无法使用。