fortran生成dll給python調用

c++和python調用fortran77生成dll同理,但須要注意subroutine名稱要大寫,否則不認html

Fortran(90)代碼以下:python

!  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文件的同一目錄)c++

# 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上也會跟着改變"

 

輸出結果以下:express

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. visual-studio

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轉跳到定義

 

新bug解決方案:

有人發覺使用python3的時候調用錯誤,debug半天發覺進到dll裏的字符串不對。查找緣由,最終發覺是python二、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'))

參考:python3讀取字符串亂碼而python2沒問題

相關文章
相關標籤/搜索