1

Fortran で gsl ライブラリを使用するためのラッパーを作成しようとしています。シンプルなラッパーを動作させることができました - http://www.helsinki.fi/~fyl_tlpk/luento/ohj-13-GSL-e.htmlの例

Fortran コード

program gsltest
    implicit none

    real(kind=selected_real_kind(12)) :: a = 0.11, res
    external :: glsgateway

    call gslgateway(a,res)
    write(*,*) 'x', a, 'atanh(x)', res

end program gsltest

c 関数

#include <gsl/gsl_math.h>

void gslgateway_(double *x, double *res){
   *res = gsl_atanh(*x);
}

それはすべて順調です。ただし、より複雑なラッパーに問題があります。http://apwillis.staff.shef.ac.uk/aco/freesoftware.htmlの例から次のコードを変更しました。

c ラッパー (rng_initialise.c)

#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

static gsl_rng* r;

void rng_initialise__(int* s) {
   r = gsl_rng_alloc(gsl_rng_taus); 
   gsl_rng_set(r, (unsigned long int)(*s)); 
}

Fortran メイン (main.f90)

PROGRAM main
    integer seed

    call system_clock(seed)
    WRITE (*,*) 'calling rng_initialise'
    call rng_initialise(seed)

END PROGRAM main

次に、コンパイルしてリンクします

gcc -c rng_initialise.c
g95 -c main.f90
g95 -o main main.o rng_initialise.o -L/usr/libs -lgsl

このプログラムを実行すると、出力が得られません。ただし、rng_initialise 内の行をコメントアウトすると、

...
void rng_initialise__(int* s) {
   // r = gsl_rng_alloc(gsl_rng_taus);  
   // gsl_rng_set(r, (unsigned long int)(*s)); 
}

次に、Fortran コードから出力を取得します (「calling_rng_initialise」を STDOUT に書き込みます)。

したがって、問題は gsl_rng_alloc と gsl_rng_set の呼び出しにあるようです。しかし、エラー メッセージは表示されず、Fortran コードが何も実行できない理由がわかりません。何か案は?

4

3 に答える 3

4

すでに提案したように、これを行う最良の方法は、Fortran ISO Cバインディングを使用することです。これは、FortranにC呼び出し規約を使用してGSLライブラリのCルーチンと一致させるように指示するためです。ISOCバインディングはFortran2003標準の一部であり、数年前から多くのFortran95コンパイラーで使用可能になっています。標準の一部として、FortranとCの双方向のインターフェースを可能にし、以前は必要だったOSやコンパイラーに依存するハックよりも移植性が高く、はるかに簡単です。ISOCバインディングが廃止された以前の手順は無視することをお勧めします。

通常、GSLライブラリを呼び出すためにCラッパーコードを記述する必要はありません。Fortran構文でFortranへのCルーチンインターフェイスを記述するFortran仕様ステートメントのみを記述します。これは、GSLルーチンgsl_cdf_chisq_Qを呼び出す簡単な例です。

program cum_chisq_prob

   use iso_c_binding

   interface GSL_CummulativeChiSq_Prob_Upper   

      function gsl_cdf_chisq_Q  ( x, nu )  bind ( C, name="gsl_cdf_chisq_Q" )

         import

         real (kind=c_double) :: gsl_cdf_chisq_Q

         real (kind=c_double), VALUE, intent (in) :: x
         real (kind=c_double), VALUE, intent (in) :: nu

      end function gsl_cdf_chisq_Q

   end interface GSL_CummulativeChiSq_Prob_Upper

   real (kind=c_double) :: chisq_value
   real (kind=c_double) :: DoF
   real (kind=c_double) :: Upper_Tail_Prob    

   write ( *, '( / "Calculates cumulative upper-tail probability for Chi-Square distribution." )' )
   write ( *, '( "Input Chisq Value, Degrees of Freedom: " )', advance='no' )
   read ( *, * ) chisq_value, DoF

   Upper_Tail_Prob = gsl_cdf_chisq_Q  ( chisq_value, DoF )

   write ( *, '( "Probability is:", 1PG17.10 )' )  Upper_Tail_Prob

   stop

end program cum_chisq_prob

さらに簡単: http: //www.lrz.de/services/software/mathematik/gsl/fortran/で、FortranからGSLを呼び出すことができる事前に作成されたライブラリを見つけることができます。

于 2011-09-08T17:11:29.547 に答える
1

ほとんどの場合、2 つのルーチン間のリンクが何らかの形で間違っています。そのインターフェイスをホップするときにスタックが正しく処理されない場合、何かが発生する可能性があります。

Fortran 側または C 側のいずれかで、他方の呼び出し規約を指定するコードに気付いていません。私は Gnu Fortran の専門家ではありませんが、ほとんどのコンパイラでは、別のコンパイラの呼び出し規則を使用する必要があること、または悪いことが起こる可能性があることを知っています。

少しウェブを検索しただけで、G95 Fortran マニュアル (PDF)に「G95 プログラムとのインターフェイス」というタイトルの長いセクションがあり、これについて詳しく説明しているようです。スキミングから、BIND(C)その C ルーチンの Fortran 関数宣言で属性を使用する必要があるように見えます。

于 2011-09-08T12:45:04.527 に答える