我从较大的遗留代码库中找到了一个小辅助子程序,它计算了一个向量的一些统计数据并单独编译它并试图从Julia(0.6.2)调用它来进行练习。
首先,我找到了一些论坛帖子和话语线程,但我想仔细检查,因为语言很快就开发了,有些可能会使用过时的语法like this one。另外,我使用Windows和许多论坛帖子,我遇到了参考.so文件,我的理解是针对UNIX系统,而不是Windows?
我正在引用的Fortran代码(称为meansd.f)是:
SUBROUTINE MEANSD (A,N,ABAR,VAR,STD)
IMPLICIT NONE
C COMPUTE THE MEAN AND STANDARD DEVIATION OF A REAL VECTOR.
C PARAMETERS:
C A: REAL VECTOR TO COMPUTE MEAN AND STANDARD DEVIATION OVER.
C N: LENGTH OF A.
C ABAR: COMPUTED MEAN OF A.
C VAR: VARIANCE OF A.
C STD: COMPUTED STANDARD DEVIATION OF A.
C
REAL A(N)
INTEGER I,N
DOUBLE PRECISION APX, ABAR, VAR, STD, SUM, SUMSQ, DN, Z
C
DN=N
APX=0D0
DO 30 I=1,N
APX=APX+A(I)
30 CONTINUE
APX=APX/DN
SUM=0D0
SUMSQ=0D0
DO 40 I=1,N
Z=A(I)-APX
SUM=SUM+Z
SUMSQ=SUMSQ+Z*Z
40 CONTINUE
ABAR=SUM/DN
VAR=(SUMSQ-(SUM*ABAR))/(DN-1)
STD=DSQRT(VAR)
ABAR=ABAR+APX
RETURN
END
我使用gcc编译了这个
gcc (x86_64-posix-seh-rev1, Built by MinGW-W64 project) 7.2.0
主要跟随this question,完成时没有错误:
gfortran -c meansd.f
gfortran -shared -fPIC meansd.o -o meansd.dll
当我用Libdl
进行测试时,一切似乎都恢复正常,我得到一个指针
path=joinpath(pwd(),"meansd.dll")
dl=Libdl.dlopen(path)
然后我尝试将ccall
函数构建为:
a_ref=Ref{Array{Float64,1}}([5.0,5.0,5.0,5.0,5.0])
i_ref=Ref{Int64}(1)
n_ref=Ref{Int64}(length([5.0,5.0,5.0,5.0,5.0]))
apx_ref=Ref{Float64}(0)
abar_ref=Ref{Float64}(0)
var_ref=Ref{Float64}(0)
std_ref=Ref{Float64}(0)
sum_ref=Ref{Float64}(0)
sumsq_ref=Ref{Float64}(0)
dn_ref=Ref{Float64}(0)
z_ref=Ref{Float64}(0)
ccall((:meansd_,"meansd.dll"),Void,(
Ref{Array{Float64,1}},#A
Ref{Int64}, #I
Ref{Int64}, #N
Ref{Float64}, #APX #I think I have to pass these too?
Ref{Float64}, #ABAR
Ref{Float64}, #VAR
Ref{Float64}, #STD
Ref{Float64}, #SUM
Ref{Float64}, #SUMSQ
Ref{Float64}, #DN
Ref{Float64}, #Z
),a_ref,i_ref,n_ref,apx_ref,
abar_ref,var_ref,std_ref,sum_ref,sumsq_ref,dn_ref,z_ref)
这完成了我已经完成的内容,但abar_ref
作为NaN
返回。然后我创建了一个Float / Int 32版本,完成但abar_ref
作为0.0
返回。我以为我应该使用64位,因为我用64位gfortran编译。
我认为我搞砸了如何传递数组,但是我已经尝试了许多不同的接近我想到的但没有成功。
我也很困惑何时使用Julia类型与ccall
类型(Float32
vs Cint
?)。我已经看到了两个分散在网络中的例子,但是如果我正确阅读,那么在这一点后面有内置的转换语句可以处理它吗?
答案 0 :(得分:1)
编辑扩展说明
根据皮埃尔的评论,我回过头来重新阅读文档,并设法获得了一个有效的版本:
我首先删除了实例化除函数调用中命名的变量之外的任何变量:
SUBROUTINE MEANSD (A,N,ABAR,VAR,STD)
。
接下来,我重新阅读the documentation section on calling FORTRAN,特别是此警告部分。
警告
对于字符串参数(char *),Julia类型应该是Cstring(如果是NUL- 预期终止数据)或Ptr {Cchar}或Ptr {UInt8} 否则(这两种指针类型具有相同的效果),如上所述 上面,不是String。同样,对于数组参数(T []或T *), Julia类型应该再次是Ptr {T},而不是Vector {T}。
结果代码是:
#declare variables
a=Float32[1.0,2.0,3.0,4.0,5.0] #changed values from OP to have non-zero var/sd for demo
n=length(a) #works as Int32(length(a)) as well?
abar_ref=Ref{Float64}(0)
var_ref=Ref{Float64}(0)
std_ref=Ref{Float64}(0)
#call function
ccall((:meansd_,"meansd.dll"),Void,(
Ptr{Float32},#A
Ref{Int32}, #N
Ref{Float64}, #ABAR
Ref{Float64}, #VAR
Ref{Float64}, #STD
),a,n,abar_ref,var_ref,std_ref)
#check results
abar_ref[] #returns 3.00
var_ref[] #returns 2.50
std_ref[] #returns 1.58