fortran生成dll给python调用

c++和python调用fortran77生成dll同理,但需要注意subroutine名称要大写,不然不认

Fortran(90)代码如下:

!  fortranDLLExample.f90 
!
!  FUNCTIONS/SUBROUTINES exported from fortranDLLExample.dll:
!  fortranDLLExample - subroutine 

FUNCTION ABZERO(P) bind(C,name="ABZERO")
    !DEC$ ATTRIBUTES DLLEXPORT :: ABZERO
    !DEC$ ATTRIBUTES VALUE :: P
    integer, INTENT(IN) :: P   
    integer :: ABZERO
    integer :: result1
    ! Examle calculation
    result1 = P - 273
    print *, "The p==", P, ";"
    print *, "The p-273 [", result1, "]"
    ABZERO = result1
    RETURN 
END FUNCTION

FUNCTION ABZERO_FLOAT(P) bind(C,name="ABZERO_FLOAT")
    !DEC$ ATTRIBUTES DLLEXPORT :: ABZERO_FLOAT
    !DEC$ ATTRIBUTES VALUE :: P
    real, INTENT(IN) :: P   
    real :: ABZERO_FLOAT
    real :: result1
    ! Examle calculation
    result1 = P - 273.15
    print *, "The p==", P, ";"
    print *, "The p-273 [", result1, "]"
    ABZERO_FLOAT = P - 273.15
    RETURN 
END FUNCTION

FUNCTION sum(length1, P) bind(C,name="sum")
    !DEC$ ATTRIBUTES DLLEXPORT :: sum
    implicit none
    integer::length1
    real, dimension(*):: P
    real :: sum
    integer::i
    
    print *, "The length1==", length1, ";"
    sum =0.0
    do i = 1,length1 ! sum the array elements
        sum = sum + p(i)
        PRINT *,p(i)
    end do
    RETURN 
END FUNCTION

subroutine func01( a ) bind(C,name="func01")
    !DEC$ ATTRIBUTES DLLEXPORT :: func01
    implicit none
    character(len=1), dimension(90) , intent(in) :: a
    character(len=30), dimension(3) :: b
    integer*4 :: count,i,j

    count=1
    do j=1,3
        b(J)=''
        do I=1,30
            b(J)=trim(b(J))//a(count)
            count=count+1
        enddo
    enddo

    print *
    print *, "char length = ", len(b(1)), len(b(2)), len(b(3))
    print *, "raw a(1) : [", b(1), "]"
    print *, "raw a(2) : [", b(2), "]"
    print *, "raw a(3) : [", b(3), "]"
    print *, "trim     : [", trim(b(1)), "] [", trim(b(2)), "]  [", trim(b(3)), "]"
end

FUNCTION SUMANDTIMES(P, length1, Q) bind(C,name="SUMANDTIMES")
    !DEC$ ATTRIBUTES DLLEXPORT :: SUMANDTIMES
    implicit none
    integer::length1
    real, dimension(*):: P
    real :: SUMANDTIMES, Q
    integer::i
    
    print *, "The length1==", length1, ";"
    SUMANDTIMES =0.0
    do i = 1,length1 ! sum the array elements
        SUMANDTIMES = SUMANDTIMES + p(i) * Q
        PRINT *,p(i)
    end do
    RETURN 
END FUNCTION

FUNCTION array2by2(P, row, col) bind(C,name="array2by2")
    !DEC$ ATTRIBUTES DLLEXPORT :: array2by2
    USE ISO_C_BINDING
    implicit none
    integer::row, col, i, j, array2by2
    !real,DIMENSION(row*col)::
    real P(*)
    real PP(row, col)
    print *, "---->row-----", row
    print *, "---->col-----", col
    do i=1,row
        do j=1,col
            PP(i,j) = P((i-1)*row+j)
            P((i-1)*row+j) = PP(i,j) * 100
            print *, PP(i,j), i, j, (i-1)*row+j
        end do
        print *, "----row-----", i
    end do
    array2by2 = 0
    RETURN 
END FUNCTION

 

Python调用代码如下(dll放在py文件的同一目录)

# coding=utf-8

from _ctypes import byref
from ctypes import cdll, c_int, c_float
import ctypes

my_dll = cdll.LoadLibrary('fortranDLLExample.dll')
result = my_dll.ABZERO(c_int(324))
print "my_dll.ABZERO(c_int(324))==", result, type(result)


my_dll.ABZERO_FLOAT.restype = c_float  # 要设置返回值的类型,不然默认会返回int型,导致数据混乱
result = my_dll.ABZERO_FLOAT(c_float(500.44))
print "my_dll.ABZERO_FLOAT(c_float(500.44))", result, type(result)
# tip:dll.addf.argtypes = (c_float, c_float)
# addf 有两个形参,都是 float 类型。虽然也可以用数组设置,但是元祖的效率更高


FloatArray = c_float * 5
ia = FloatArray(5.32, 1.12, 7.321, 33.12, 99.3)
for i in ia:
    print i
my_dll.sum.restype = c_float
result = my_dll.sum(byref(c_int(len(ia))), byref(ia))
print "dll.sum == ", result


FloatArray = c_float * 3
ia2 = FloatArray(1.1, 2.2, 3.3)
my_dll.SUMANDTIMES.restype = c_float
result = my_dll.SUMANDTIMES(byref(ia2),
                     byref(c_int(len(ia2))),
                     byref(c_float(100.1)))
print "dll.SUMANDTIMES == ", type(result), result


# 出现win32不是有效的应用程序bug的时候,记得在fortran编辑器选择好x86或x64,版本要和python的位数对应上
d = ctypes.create_string_buffer("abcde67890b234567             "
                                "waeofijo                      "
                                "awoijewfawfe                  ", size=90)
my_dll.func01(d)


j_table = (c_float * 16)(1.1, 1.2, 1.3, 1.4,
                         2.1, 2.2, 2.3, 2.4,
                         3.1, 3.2, 3.3, 3.4,
                         4.1, 4.2, 4.3, 4.4)  # 给力
my_dll.array2by2(byref(j_table),
                 byref(c_int(4)),
                 byref(c_int(4)))
for i in j_table:
    print i,
print "--------------------- 操作完后的结果 ---------------------"


h_table = (c_float * 16)(91.1, 51.2, 1.35, 1.45,
                         92.1, 52.2, 2.35, 2.45,
                         93.1, 53.2, 3.35, 3.45,
                         94.1, 54.2, 4.35, 4.45)  # 给力
my_dll.array2by2(byref(h_table),
                 byref(c_int(4)),
                 byref(c_int(4)))
for i in h_table:
    print i,
print "--------------------- 操作完后的结果 ---------------------"


my_dll.array2by2(byref(j_table),
                 byref(c_int(4)),
                 byref(c_int(4)))
for i in j_table:
    print i,
print "默认传给dll的是指针,因此在fortran中如果动了地址里面的内容,那么反映到python上也会跟着改变"

 

输出结果如下:

 The p==         324 ;
 The p-273 [          51 ]
my_dll.ABZERO(c_int(324))== 51 <type 'int'>
 The p==   500.4400     ;
 The p-273 [   227.2900     ]
my_dll.ABZERO_FLOAT(c_float(500.44)) 227.290008545 <type 'float'>
5.32000017166
1.12000000477
7.32100009918
33.1199989319
99.3000030518
 The length1==           5 ;
   5.320000    
   1.120000    
   7.321000    
   33.12000    
   99.30000    
dll.sum ==  146.180999756
 The length1==           3 ;
   1.100000    
   2.200000    
   3.300000    
dll.SUMANDTIMES ==  <type 'float'> 660.66003418
 
 char length =           30          30          30
 raw a(1) : [abcde67890b234567             ]
 raw a(2) : [waeofijo                      ]
 raw a(3) : [awoijewfawfe                  ]
 trim     : [abcde67890b234567] [waeofijo]  [awoijewfawfe]
 ---->row-----           4
 ---->col-----           4
   1.100000               1           1           1
   1.200000               1           2           2
   1.300000               1           3           3
   1.400000               1           4           4
 ----row-----           1
   2.100000               2           1           5
   2.200000               2           2           6
   2.300000               2           3           7
   2.400000               2           4           8
 ----row-----           2
   3.100000               3           1           9
   3.200000               3           2          10
   3.300000               3           3          11
   3.400000               3           4          12
 ----row-----           3
   4.100000               4           1          13
   4.200000               4           2          14
   4.300000               4           3          15
   4.400000               4           4          16
 ----row-----           4
110.0 120.000007629 130.0 140.0 209.999984741 220.0 230.0 240.000015259 310.0 320.0 330.0 340.0 410.0 419.999969482 430.000030518 440.0 --------------------- 操作完后的结果 ---------------------
 ---->row-----           4
 ---->col-----           4
   91.10000               1           1           1
   51.20000               1           2           2
   1.350000               1           3           3
   1.450000               1           4           4
 ----row-----           1
   92.10000               2           1           5
   52.20000               2           2           6
   2.350000               2           3           7
   2.450000               2           4           8
 ----row-----           2
   93.10000               3           1           9
   53.20000               3           2          10
   3.350000               3           3          11
   3.450000               3           4          12
 ----row-----           3
   94.10000               4           1          13
   54.20000               4           2          14
   4.350000               4           3          15
   4.450000               4           4          16
 ----row-----           4
9110.0 5120.0 135.0 145.0 9210.0 5220.0 234.999984741 245.0 9310.0 5320.0 335.0 345.0 9410.0 5420.0 435.0 444.999969482 --------------------- 操作完后的结果 ---------------------
 ---->row-----           4
 ---->col-----           4
   110.0000               1           1           1
   120.0000               1           2           2
   130.0000               1           3           3
   140.0000               1           4           4
 ----row-----           1
   210.0000               2           1           5
   220.0000               2           2           6
   230.0000               2           3           7
   240.0000               2           4           8
 ----row-----           2
   310.0000               3           1           9
   320.0000               3           2          10
   330.0000               3           3          11
   340.0000               3           4          12
 ----row-----           3
   410.0000               4           1          13
   420.0000               4           2          14
   430.0000               4           3          15
   440.0000               4           4          16
 ----row-----           4
11000.0 12000.0009766 13000.0 14000.0 20999.9980469 22000.0 23000.0 24000.0019531 31000.0 32000.0 33000.0 34000.0 41000.0 41999.9960938 43000.0039062 44000.0 默认传给dll的是指针,因此在fortran中如果动了地址里面的内容,那么反映到python上也会跟着改变

 

bind(C,name="RUN_S_ENTERFUNC")不是必须的,加上bind后传入字符串有可能报错

当使用不定长度数组或者字符串的时候,应该去掉!DEC$ ATTRIBUTES VALUE :: P以避免编译器反复提示你要给数组分配一个固定的长度

The character length of a dummy argument with the VALUE attribute must be an initialization expression.   [INPUTFILE]

关于fortran数组:

Syntactically, assumed shape used colons (:) instead of 
an asterisk in the dimension declaration.  The difference in meaning 
is exactly the subject in question - assumed shape arrays automatically 
get their shape information passed, whereas assumed size arrays basically 
get nothing but a starting address passed. 

http://computer-programming-forum.com/49-fortran/f2a81d00123cad00.htm

 

运行python遇到这个错误   error: Unable to find vcvarsall.bat 可以这么解决:

报错原因:在生成的时候,编译器从%PythonInstallPath%\distutils\msvc9compiler.py里的219行find_vcvarsall(version)函数中找不到vcvarsall.bat文件。

更具体的原因是,msvc9compiler.py从sys.version里提取MSVC的版本号,但是在注册表中并没有根据版本号找到vcvarsall.bat,在系统的环境变量中也没有找到版本号对应的路径。后来我根据版本号,在环境变量中添加了路径,但因为msvc9compiler.py主要是针对VS2008和VS2010所做的路径识别,因此还是不能正确地找到vcvarsall.bat。

解决方法:直接在find_vcvarsall(version)函数中返回vcvarsall.bat的绝对路径。

https://blog.csdn.net/sad_sugar/article/details/73743863

Tip:运行.bat后,相当于添加了vs各种工具的环境变量,我们可以使用dumpbin /symbols xxx.lib来查看lib中有多少function供我们使用

 

在安装VS 2015期间遇到这么一个问题(即使是去官网下载的版本也会遇到https://www.visualstudio.com/zh-hans/vs/older-downloads/):

setup detected an issue during the operation.

“安装程序检测到一个问题......”

解决方法是:

找到C:\Windows\Fonts目录,
备份fonts下面所有的字体
然后删除C:\Windows\Fonts下面所有的字体(系统字体如果删除不了的,那么就留着,一些字体集提示警告不要删除的,也留着)
然后再安装vs2015就OK了!
这个确实问题很诡异,但就是这么解决的:https://stackoverflow.com/questions/33622151/setup-detected-an-issue-during-visual-studio-community-edition-2015-installation

 

当出现这个错误的时候Visual Studio cannot debug because a debug target has not been specified或者cannot start debugging because the debug target is missing

(在编译dll的时候尤其容易出现,可以选择一个exe来debug)

 

 

编辑VS里的fortran时,如果我们希望开启转跳到定义功能,在这里设置:

开启fortran转跳到定义

转载于:https://my.oschina.net/u/2996334/blog/1807823

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值