- ベストアンサー
FortranプログラムからC言語で実装された関数を呼ぶには?
Windows Vista Home PremiumにFTN95をインストールしたPCにて、Fortranのプログラミングをし始め、「Cpad for Salford FTN77」を利用してプログラミングをしています(FORTRAN77・Fortran90ともに)。FTN95でのFortranプログラミングに際し、FortranプログラムからC言語で実装された関数を呼ぶには、どのように対処すれば可能になりますでしょうか? ユーザーガイドによれば、「Fortranプログラム中に、C_EXTERNALという宣言をした関数は、Cの関数と同じくアクセスできるようになり、C側では、#extern <返り値>関数名(引数)を与えれば、Cの関数として呼び込むことができる。」とのことがかかれています。 実際に使っているファイルをいくつか書き出します。 <D:\fortran\sample.f> C_EXTERNAL WRITE 'WriteFile' : INTEGER*4 INTEGER*4 RESULT RESULT=WRITE() write(*,*) result return end <D:\fortran\sample.c> #extern int Writefile(int); <C:\Program Files\Silverfrost\FTN95\ftn95c.bat> ftn95.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 /link ちなみに、「Cpad for Salford FTN77」での実行/設定/実行/コンパイル時のパラメータは「/link /dreal」です。もちろんftn95.exeへのパスは通してあります。何が問題でしょうか? 何分初心者ですので、拙い質問かと思いますが、何卒ご教示願います。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
ftn77 と ftn95 で違ったりするみたいですね。 コンパイルオプションでどうにかなるのかもしれませんが、とりあえずC側のファイルの関数名を hello から HELLO のように全部を大文字にしてください。 これでリンクが通るようになると思います。
その他の回答 (8)
- Tacosan
- ベストアンサー率23% (3656/15482)
C_EXTERNAL hello を C_EXTERNAL hello 'hello' にしたら動いたりして.
- sakusaker7
- ベストアンサー率62% (800/1280)
>パスを通した上でコマンドプロンプトから「gcc lib.c」とするとエラーとなり、 ここで、gcc -c lib.c のようにしてください。 これをつけないとlib.cだけで実行ファイルを作りに行ってしまうので それが理由でエラーになります。 あれ、でも#3の補足を見るとオブジェクトファイルが、とかあるなあ。 まあそれはおいといて、 -cをつけると、(エラーがなければ)lib.o を作って終わりますから Fortranのソースからできた sample.obj と一緒にリンクしてください。 あ、Fortranのコンパイルも ftn95.exe /link /dreal sample.f /link の /link は指定しないでくださいね。 ftn95 dreal sample.f gcc -c lib.c slink sample.obj lib.o てな手順で sample.exe が最終的に手に入るはずです。
お礼
重要な点を含んだ回答していただき、ありがとうございます。何度も何度も回答していただいているにも関わらず、当方での動作がうまくいかず「再質問→再回答」の繰り返しとなっていること、申し訳なく思います。 さて、プログラムのほうは貴殿のようにうまく動きません。少なくとも「tes1.f」・「lib.c」についてはそれぞれ「ftn95」・「scc」で単体でなら何のエラーも返さずにコンパイルできます。しかし、「slink」の段階でWarningが出てきてしまい、実行ファイルができるにはできてもエラーになってしまいます。どのようにすれば対処できますでしょうか? D:\math\fortran>type tes1.f lib.c tes1.f program mogera C_EXTERNAL hello call hello stop end lib.c #include <stdio.h> #define near() asm volatile("fldcw __RoundNear") #define down() asm volatile("fldcw __RoundDown") #define up() asm volatile("fldcw __RoundUp") #define chop() asm volatile("fldcw __RoundChop") int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; void hello() { printf("%s\n", "hello from C function!"); } D:\math\fortran>ftn95 /dreal tes1.f [FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006] NO ERRORS [<MOGERA> FTN95/Win32 v5.01.0] D:\math\fortran>scc lib.c [Silverfrost SCC/WIN32 Ver 3.65 Copyright (c) Silverfrost Ltd 2006] NO ERRORS [<LIB> SCC/WIN32 Ver 3.65] D:\math\fortran>slink tes1.obj lib.obj WARNING the following symbols are missing: HELLO D:\math\fortran\tes1.obj (D:\MATH\FORTRAN\TES1. Creating executable: D:\math\fortran\tes1.exe D:\math\fortran>tes1 D:\math\fortran>type error.txt Runtime error from program:d:\math\fortran\tes1.exe Run-time Error *** Error 29, Call to missing routine : _HELLO at 0x00401020. 00401000 main [+0025] [recur= 1] D:\math\fortran>
補足
「gcc -c」で対処しても下記の通りうまくいきませんでしたので、「scc」でやってみましたが結局現状ではどちらも当方ではうまく動きません。 D:\math\fortran>type tes1.f lib.c tes1.f program mogera C_EXTERNAL hello call hello stop end lib.c #include <stdio.h> #define near() asm volatile("fldcw __RoundNear") #define down() asm volatile("fldcw __RoundDown") #define up() asm volatile("fldcw __RoundUp") #define chop() asm volatile("fldcw __RoundChop") int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; void hello() { printf("%s\n", "hello from C function!"); } D:\math\fortran>ftn95 /dreal tes1.f [FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006] NO ERRORS [<MOGERA> FTN95/Win32 v5.01.0] D:\math\fortran>gcc -c lib.c D:\math\fortran>slink tes1.obj lib.o WARNING the following symbols are missing: HELLO D:\math\fortran\tes1.obj (D:\MATH\FORTRAN\TES1.F) Creating executable: D:\math\fortran\tes1.exe D:\math\fortran>tes1 D:\math\fortran>type error.txt Runtime error from program:d:\math\fortran\tes1.exe Run-time Error *** Error 29, Call to missing routine : _HELLO at 0x00401020. 00401000 main [+0025] [recur= 1] D:\math\fortran>
- Tacosan
- ベストアンサー率23% (3656/15482)
.... 誰だ, 「gcc での~ないといけないのです」なんて中途半端なことを言ったやつは.... 「コンパイルするだけ」なら main はいらない. gcc だろうと cl だろうと同じこと. たぶん scc でも同じはずだ. もちろん「リンクして実行ファイルを作る」ためには main が必要. 「コンパイルする」ことと「リンクして実行ファイルを作ること」とは別です. 区別してください.
お礼
>.... 誰だ, 「gcc での~ないといけないのです」なんて中途半端なことを言ったやつは.... >「コンパイルするだけ」なら main はいらない. gcc だろうと cl だろうと同じこと. たぶん scc でも同じはずだ. パスを通した上でコマンドプロンプトから「gcc lib.c」とするとエラーとなり、何のファイルもはき出されません。実際のエラーメッセージは次の通りです。 C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingw32.a(main.o):main.c:(.text+0xbd): undefined reference to WinMain@16' collect2: ld returned 1 exit status 「scc」でコンパイルする際に、「asm volatile("...")」 という形でアセンブリコードを埋め込むことができないのならば、sccはどのように記述すればいいのでしょうか? 「FTN95」に「scc」もすでにインストール済みなわけで、すでにあるものの有効活用でいけるところまでいってみたいと思うのです(「むしろ、そっちのほうが難しいんだよ!」と突っ込まれるかもしれませんが…)。
- Tacosan
- ベストアンサー率23% (3656/15482)
まさかまさかなんだけど, C のソースに「関数 main がある」ってオチはないよね?
お礼
回答ありがとうございます。「gcc」でのコンパイルには最低限 int main(){ return 0; } がないといけないのです。「FTN95」付属の「scc」ではそうではありませんが…。 部分的には貴殿の“オチ”のとおりかもしれません…。
- sakusaker7
- ベストアンサー率62% (800/1280)
scc というのがわたしがインストールしたものには入っていなかったので すぐには確認できませんが、それがCコンパイラなら使えるのではないかと思います。 ただ、asm volatile("...") という形でアセンブリコードを埋め込むことは できないと思われますので、scc 用の記述に変えるなりしなければならないのではないでしょうか。 もうひとつ、Visual C/C++ ですがExpress edition というものが 無料配布されていて、これを使うことができるでしょう。 Visual Studio 2008 Express Edition の DVD イメージからのインストール http://www.microsoft.com/japan/msdn/vstudio/express/maninstall/2008/
- sakusaker7
- ベストアンサー率62% (800/1280)
>ご教示願います。 これ、相手に敬意をはらった書き方だと思って書いてます? ま、それはともかくエラーメッセージにあるようにFORTRAN側の プログラムからして間違ってますし、C側も補足で出されたのも含めて間違ってます。 C_EXTERNAL WRITE 'WriteFile' : INTEGER*4 INTEGER*4 RESULT RESULT=WRITE() write(*,*) result return end サブルーチンでもないのに、returnがあるのは間違いということで コンパイルできてません。 手元にあって試したのはFTN77ですが、基本的には同様にできるはずです。 C:\win32app\salford>type moge.f program mogera C_EXTERNAL hello call hello stop end というFORTRANプログラムで、helloがCで記述したサブルーチンです。 C:\win32app\salford>ftn77 moge.f [Salford FTN77/Win32 v4.03, Copyright (c) Salford Software Ltd. 1988-1998] Licensed to: FTN77 Personal Edition Department: Non-commercial use only NO ERRORS [<MOGERA>FTN77 Ver 4.03] で、C側はこう。 C:\win32app\salford>type lib.c #include <stdio.h> int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; void near() { __asm fldcw _RoundNear } void down() { __asm fldcw _RoundDown } void up() { __asm fldcw _RoundUp } void chop() { __asm fldcw _RoundChop } void hello() { printf("%s\n", "hello from C function!"); } C:\win32app\salford>cl -c lib.c Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved. lib.c C:\win32app\salford>slink.exe moge.obj lib.obj Creating executable: C:\win32app\salford\moge.exe C:\win32app\salford>moge hello from C function! と、C側の関数の出力がされてます。 FORTRAN側でサブルーチンではなく関数として使うのであれば 多少変わりますが大まかな手順としてはこんな感じになります。 補足にあるCプログラムを見るとgcc用のようですが、FTN77やFTN95って gccでコンパイルしてできた.oファイルもリンクしてくれるんでしょうか?
お礼
>>ご教示願います。 >これ、相手に敬意をはらった書き方だと思って書いてます? 当方の言葉の誤用で貴殿に対して失礼となる書き込みをしてしまったこと、心よりお詫び申し上げます。 本題ですが、FortranからCを呼び出すこと自体は問題なくできました。ありがとうございます。ただ、肝心のgccでコンパイルしたオブジェクトファイルでは、(拡張子をgccでのコンパイル時に「.obj」に指定したとしても)実行ファイルができてもエラーとなってしまいます。「『main』関数が2重に定義されている」とかいうメッセージがslink実行時に出てしまい、できた実行ファイルを実行してもエラーで止まってしまいます。 ちなみにFTN95に同梱されているsccではslink不能なのでしょうか。当方はVisual Studioは有しておりませんので「cl.exe」は当然入っておりません。簡単(?)なCの関数を呼び出すのに、さらに別のソフト(有料?)を入れるという大がかりなことをしないとだめなものなのでしょうか…。 何かいい解決法はないものでしょうか?お教え願います。
- Tacosan
- ベストアンサー率23% (3656/15482)
エラーメッセージが出ているならそれを書いてください. もちろん「翻訳」なんかしないで, 一字一句そのままで. ちょっと見た感じだと C の方は特にいじらなくてもいいように見えるけどなぁ....
お礼
回答ありがとうございます。質問文の「D:\fortran\」は「D:\math\fortran\」の誤りです。訂正します。
補足
上述したエラーメッセージは以下の通りです(一字一句そのままです)。 ■D:\math\fortran> ftn95c /link /dreal sample.f D:\math\fortran>ftn95.exe /link /dreal sample.f /link [FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006] 0005) return *** RETURN cannot be inside a PROGRAM block 1 ERROR [<main program> FTN95/Win32 v5.01.0] *** Compilation failed なお、Cを呼び出す必要があるのは、Fortranの命令で浮動小数点をユーザーの希望するタイミングでUp・Down・Chop・Nearできないため、Cから呼び出すことでこれを実現したいからです。 ちなみに、<D:\fortran\sample0.c>も用意してあります。 <D:\fortran\sample0.c> #include <stdio.h> #define near() asm volatile("fldcw __RoundNear") #define down() asm volatile("fldcw __RoundDown") #define up() asm volatile("fldcw __RoundUp") #define chop() asm volatile("fldcw __RoundChop") int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; int main() { return(0); } 改めてご教示願います。
- sakusaker7
- ベストアンサー率62% (800/1280)
質問者さんの組み合わせはやったことがないのですが <D:\fortran\sample.c> #extern int Writefile(int); C側がこれだけですか? これだと、Cで関数の実装がされてませんけど。 それから、#extern というのはCコンパイラがエラーにしてしまうような気がするんですがユーザーガイドとやらを読み違えてたりしませんか? FORTRAN側のプログラムもなんか変だなあ。
お礼
回答ありがとうございます。質問文の「D:\fortran\」は「D:\math\fortran\」の誤りです。訂正します。
補足
上述したエラーメッセージは以下の通りです(一字一句そのままです)。 ■D:\math\fortran> ftn95c /link /dreal sample.f D:\math\fortran>ftn95.exe /link /dreal sample.f /link [FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006] 0005) return *** RETURN cannot be inside a PROGRAM block 1 ERROR [<main program> FTN95/Win32 v5.01.0] *** Compilation failed なお、Cを呼び出す必要があるのは、Fortranの命令で浮動小数点をユーザーの希望するタイミングでUp・Down・Chop・Nearできないため、Cから呼び出すことでこれを実現したいからです。 ちなみに、<D:\fortran\sample0.c>も用意してあります。 <D:\fortran\sample0.c> #include <stdio.h> #define near() asm volatile("fldcw __RoundNear") #define down() asm volatile("fldcw __RoundDown") #define up() asm volatile("fldcw __RoundUp") #define chop() asm volatile("fldcw __RoundChop") int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; int main() { return(0); } 改めてご教示願います。
お礼
貴殿のアドバイスのお陰で無事当方で実行したいことが可能になりました。試行錯誤の結果、ftn95のパラメータには今回のケースでは「/dreal」だけでなく「/ckc」もいるということがわかり、sccでもgccでも共に無事成功しました。何度も何度も拙い質問に堪えながらの回答ありがとうございました。またわからないことが生じましたら、そのときは再度アドバイスよろしくお願いいたします。
補足
貴殿のアドバイスのお陰で無事当方で実行したいことが可能になりました。試行錯誤の結果、ftn95のパラメータには今回のケースでは「/dreal」だけでなく「/ckc」もいるということがわかり、下記の通り、sccでもgccでも共に無事成功しました。何度も何度も拙い質問に堪えながらの回答ありがとうございました。またわからないことが生じましたら、そのときは再度アドバイスよろしくお願いいたします。 D:\math\fortran>ftn95 /dreal /ckc tes1.f [FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006] NO ERRORS [<main program> FTN95/Win32 v5.01.0] D:\math\fortran>scc lib.c [Silverfrost SCC/WIN32 Ver 3.65 Copyright (c) Silverfrost Ltd 2006] NO ERRORS [<LIB> SCC/WIN32 Ver 3.65] D:\math\fortran>type tes1.f implicit double precision(a-h, o-z) C_EXTERNAL near C_EXTERNAL down C_EXTERNAL up C_EXTERNAL chop C_EXTERNAL hello dimension a(100),b(100) cn=0.0d0 cu=0.0d0 cd=0.0d0 cc=0.0d0 do i=1,100 a(i)=0.1d0 b(i)=0.1d0 end do call near do i=1,100 cn=cn+a(i)*b(i) end do call up do i=1,100 cu=cu+a(i)*b(i) end do call down do i=1,100 cd=cd+a(i)*b(i) end do call chop do i=1,100 cc=cc+a(i)*b(i) end do write(6,10) cn,cu write(*,*) write(6,10) cd,cc 10 format(f26.19,2x,f26.19) call near end D:\math\fortran>type lib.c #include <stdio.h> int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; extern "C" void NEAR(void) { asm{fldcw _RoundNear}; printf("%s\n", "Near"); } extern "C" void DOWN(void) { asm{fldcw _RoundDown}; printf("%s\n", "Down"); } extern "C" void UP(void) { asm{fldcw _RoundUp}; printf("%s\n", "Up"); } extern "C" void CHOP(void) { asm{fldcw _RoundChop}; printf("%s\n", "Chop"); } D:\math\fortran>slink tes1.obj lib.obj Creating executable: D:\math\fortran\tes1.exe D:\math\fortran>tes1 Near Up Down Chop 1.0000000000000006661 1.0000000000000008882 0.9999999999999934497 0.9999999999999934497 Near D:\math\fortran>type lib2.c #include <stdio.h> int _RoundNear =0x133a; int _RoundDown =0x173a; int _RoundUp =0x1b3a; int _RoundChop =0x1f3a; void NEAR() { asm volatile("fldcw __RoundNear"); printf("%s\n", "Near"); } void DOWN() { asm volatile("fldcw __RoundDown"); printf("%s\n", "Down"); } void UP() { asm volatile("fldcw __RoundUp"); printf("%s\n", "Up"); } void CHOP() { asm volatile("fldcw __RoundChop"); printf("%s\n", "Chop"); } void HELLO() { printf("%s\n", "hello from C function!"); } D:\math\fortran>gcc -c lib2.c D:\math\fortran>slink tes1.obj lib2.o Creating executable: D:\math\fortran\tes1.exe D:\math\fortran>tes1 Near Up Down Chop 1.0000000000000006661 1.0000000000000008882 0.9999999999999934497 0.9999999999999934497 Near D:\math\fortran>