我有一个使用 Fortran
写的积分代码,现在我想把它编译为动态链接库,然后使用 Julia
来调用。
使用时需要给动态库传入一个函数指针(应该这么称呼?我不确定,请原谅我计算机知识薄弱!),我阅读文档后认为 @cfunction
宏可能可以实现我的需求。我测试了传入非数组的参数的函数可以正常工作,一个简单的示例如下:
SUBROUTINE test1(fun, x)
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
COMMON /DATATABLE/ANS
external fun
ANS=0.0D0
ANS=fun(x, x)
RETURN
END
将这份 f77
代码编译为动态链接库:
gfortran -shared -fPIC test1.f -o libtest1.so
然后运行以下 julia
代码来调用上述动态库:
function foo(x::Cdouble, y::Cdouble)::Cdouble
return exp(x)*y
end
ccall((:test1_, "./libtest1.so"), Cvoid, (Ptr{Cvoid}, Ref{Cdouble}),
@cfunction(foo, Cdouble, (Ref{Cdouble}, Ref{Cdouble})), 1.2)
@info unsafe_load(cglobal((:datatable_, "./libtest1.so"), Cdouble))
可以得到预期的结果:
[ Info: 3.9841403072838566
但是当我的 Fortran
代码中的 fun
函数的参数需要传入数组的时候,我不知道该如何修改代码。
例如对应如下的 Fortran
代码:
SUBROUTINE test2(fun, x)
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
DIMENSION y(3)
COMMON /DATATABLE/ANS
external fun
ANS=0.0D0
y(1)=2.3D0
y(2)=3.4D0
ANS=fun(y, x)
RETURN
END
使用如下的 Julia
代码调用动态库会返回段错误:
function foo2(x::Array{Cdouble}, y::Cdouble)::Cdouble
return exp(x[1]*x[2])*y
end
ccall((:test2_, "./libtest1.so"), Cvoid, (Ptr{Cvoid}, Ref{Cdouble}),
@cfunction(foo2, Cdouble, (Array{Cdouble}, Ref{Cdouble})), 1.2)
@info "test2" unsafe_load(cglobal((:datatable_, "./libtest1.so"), Cdouble))
signal (11): Segmentation fault
in expression starting at /mnt/d/Work/julia/XJet/julia/test_test1.jl:14
jl_object_id_ at /buildworker/worker/package_linux64/build/src/builtins.c:371
type_hash at /buildworker/worker/package_linux64/build/src/jltypes.c:981
typekey_hash at /buildworker/worker/package_linux64/build/src/jltypes.c:993 [inlined]
lookup_type at /buildworker/worker/package_linux64/build/src/jltypes.c:585
inst_datatype_inner at /buildworker/worker/package_linux64/build/src/jltypes.c:1249
jl_inst_arg_tuple_type at /buildworker/worker/package_linux64/build/src/jltypes.c:1521
arg_type_tuple at /buildworker/worker/package_linux64/build/src/gf.c:1836 [inlined]
jl_lookup_generic_ at /buildworker/worker/package_linux64/build/src/gf.c:2363 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2415
unknown function (ip: 0x7fb61dd95ee4)
test2_ at ./libtest1.so (unknown line)
top-level scope at /mnt/d/Work/julia/XJet/julia/test_test1.jl:14
jl_toplevel_eval_flex at /buildworker/worker/package_linux64/build/src/toplevel.c:871
jl_toplevel_eval_flex at /buildworker/worker/package_linux64/build/src/toplevel.c:825
jl_toplevel_eval_in at /buildworker/worker/package_linux64/build/src/toplevel.c:929
eval at ./boot.jl:360 [inlined]
include_string at ./loading.jl:1094
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2237 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2419
_include at ./loading.jl:1148
include at ./Base.jl:386
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2237 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2419
exec_options at ./client.jl:285
_start at ./client.jl:485
jfptr__start_34289.clone_1 at /mnt/d/linux/opt/julia-1.6.1/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2237 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2419
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1703 [inlined]
true_main at /buildworker/worker/package_linux64/build/src/jlapi.c:560
repl_entrypoint at /buildworker/worker/package_linux64/build/src/jlapi.c:702
main at julia (unknown line)
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x4007d8)
Allocations: 747009 (Pool: 746722; Big: 287); GC: 1
Segmentation fault (core dumped)
所以,我应该如何修改 Julia
代码,才能成功地将函数传入动态库?