天天看點

python調用fortran dll_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

The p== 500.4400 ;

The p-273 [ 227.2900 ]

my_dll.ABZERO_FLOAT(c_float(500.44)) 227.290008545

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 == 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.

運作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的絕對路徑。

Tip:運作.bat後,相當于添加了vs各種工具的環境變量,我們可以使用dumpbin /symbols xxx.lib來檢視lib中有多少function供我們使用

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)

python調用fortran dll_fortran生成dll給python調用

編輯VS裡的fortran時,如果我們希望開啟轉跳到定義功能,在這裡設定:

python調用fortran dll_fortran生成dll給python調用

新bug解決方案:

有人發覺使用python3的時候調用錯誤,debug半天發覺進到dll裡的字元串不對。查找原因,最終發覺是python2、3字元串表述問題。python2字元串預設是ascii的str,而python3是unicode,而一般c語言、fortran語言接收的是char或char數組,是以應該轉為ascii,使用語句:

import ctypes

DLL_PATH = 'C:./Test2.dll'

lib = ctypes.cdll.LoadLibrary(DLL_PATH)

lib.printString('abc'.encode('ascii'))