エピグラフ
約15年前、MSBuildをまだ知らなかったときに、Fortranで大規模な決済プログラムを作成するのが好きでしたが、宗教上の理由でmakeを使用しなかった人がいました...
トレーニングレベル
中
まえがき
良い一日!
「Fortran」という言葉は、あなたの魂にさまざまな倍音を引き起こす可能性があります(オベロンと混同しないでください)。
彼の時間がすでに過ぎていると思われる場合は、この記事を無視してください。
はじめに
あなたは書くときに何が起こるのだろうと思った
call Foo();
?
正解-それはすべてあなたがそれを書く場所に依存します。 フェンスにチョークがある場合-すぐに悪意のある管理人があなたに近づきます。
ファイルFooProgram.f90のお気に入りのテキストエディターでこれを記述する場合、この方法で、Fortranコンパイラにパラメーターを渡さずにこの時点でFOOプロシージャを呼び出すように依頼する可能性があります。
!FooProgram.f90 Program FooProgram call Foo(); end program
私の経験では、この時点で、インテル®コンパイラーは_FOOサブルーチン呼び出しコードを挿入します。
つまり この段階では検証は行われません。 オブジェクトファイルと静的ライブラリのアセンブリ中にリンカが_FOO文字を検出した場合(Fortranは小文字と大文字を区別しないため、文字は常に大文字です。Fortranでアンダースコアを使用して識別子の識別を開始することも禁じられています)、_ FOOへのリンクを許可します。すべてがあなたのために働くでしょう。
彼がそれを見つけなければ、彼は書く:
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>FooProgram.f90 1>Linking... 1>FooProgram.obj : error LNK2019: unresolved external symbol _FOO referenced in function _MAIN__ 1>Debug\Console1.exe : fatal error LNK1120: 1 unresolved externals 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 2 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
キャッチを感じますか?
そうです-静的チェックは行われません。 また、Fooが別のコンパイルユニットBar.f90で次のように定義されている場合:
!Bar.f90 Subroutine Foo(bar) Integer, intent(in) :: bar Write(*,*) bar; end subroutine
?
不確実性はあなたを歓迎し、あなたの半姉妹の脆弱性を呼びます。
問題は、Bar.f90内のFOOが「External Procedure」タイプのプログラムユニット(Program Units)であることです。
しかし、Fortran95にはさらに3つのプログラム単位があることを覚えています。
- 主なプログラム
- モジュール
- ブロックデータプログラムユニット
この中で最も興味深いのは、もちろん、ソフトウェアユニットモジュールです。
コンパイルの段階で静的検証を得るのを助けるのは彼女です
変更されたプログラムを検討してください。
!FooProgram2.f90 Program FooProgram use BarModule; call Foo(); end program !Bar.f90 module BarModule contains Subroutine Foo(bar) Integer, intent(in) :: bar Write(*,*) bar; end subroutine end module
アセンブリを開始すると、思いやりのあるコンパイラーは、パラメーターなしではFOOを呼び出さないように指示します。
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>Bar.f90 1>FooProgram.f90 1>F:\2011_03_12\CPP_PROJECTS\Console1\Console1\FooProgram.f90(4): error #6631: A non-optional actual argument must be present when invoking a procedure with an explicit interface. [BAR] 1>compilation aborted for F:\2011_03_12\CPP_PROJECTS\Console1\Console1\FooProgram.f90 (code 1) 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 2 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
メインプログラムのプログラムユニットでのFOO呼び出しが実装と一致しないことをコンパイラーはどのように知りましたか? 一部には、彼自身があなたに答えを促しました。彼はFOOを明示的なインターフェースを備えた手順と見なし始めました。
ここでは、コンパイルプロセスに関する命令的な観点を宣言的なものに一時的に変更します。
2つのプロセスを検討します。
最初:プログラム単位のコンパイルの結果として、次のような要素を含む仕様モジュールを作成します。
- データオブジェクト
- パラメータ
- 構造
- 手続き
- オペレーター
この情報は、Fortranコンパイラによってbarmodule.modファイルに配置されます(ヘッダーファイルとCLRに挨拶します)。
2番目:モジュール仕様を別のソフトウェアユニットにインポートします。
これが行のコンパイル中に発生することです
use BarModule;
最初のプロセスがプロセス2の前に暗黙的に呼び出されると仮定すると、コンパイラーがエラーについてどのように通知できるかが明らかになります。
実際、今ではFOO()は明示的であり、以前のように暗黙的ではなく、FOOプロシージャの呼び出しです。 コンパイラーはチェックできます。
すべてがうまくいくようです。 誰もが幸せです。
モジュールごとにモジュールを書き始め、アプリケーションを構築します。 また、コンパイラは、コンパイル段階で愚かなコーディングエラーをキャッチするのに役立ちます。
FOO_BAZmoduleモジュールとその中にFOO_BAZプロシージャがあります。
つまり 「原子炉冷却ループ内の冷却材のダイナミクスを計算するための重いプロジェクト」は次のようになります。
!FooProgram.f90 Program FooProgram use BarModule; call Foo(1); end program !Bar.f90 module BarModule contains Subroutine Foo(bar) use FOO_BAZModule Integer, intent(in) :: bar Write(*,*) bar; call Foo_BAZ(); end subroutine end module !Foo_Baz.f90 module FOO_BAZModule contains subroutine FOO_BAZ() write(*,*) "FOO_BAZ" endsubroutine end module
依存関係FooProgram <-Foo <-Foo_BAZのチェーンは2つに分割できるようです。
FooProgram <-FooおよびFoo <-Foo_BAZ。
ただし、コンパイラは全能ではありません。 Foo_Bazの実装に変更があると、ビルドログは次のようになります。
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>FOO_BAZ.f90 1>Bar.f90 1>FooProgram.f90 1>Linking... 1>Embedding manifest... 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 0 error(s), 0 warning(s) ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Bar.f90およびFooProgram.f90は、事前に再保険のために再コンパイルされました。
私を信じて、文字列定数に余分なスペースを1つ追加したという事実のために、アプリケーションの半分が再構築されたとき、これは耐えられません...
しかし、ビルドシステム(私の例では、Intel Visual Fortranに基づいています)がこのように明白なアクションで動作する場合はどうすればよいでしょうか?
実際にハック
ご覧のとおり、FOOおよびFOO_BAZのインターフェイスは暗黙的に生成されました。 これらの手順をコンパイラに提供しただけです。 さて-暗黙性が再び私たちを防ぐ...
FOO_BAZプロシージャのインターフェイスの明示的な説明を使用して削除します。
interface subroutine FOO_BAZ() endsubroutine endinterface
このインターフェイスをモジュールFOO_BAZModuleに配置します
!Foo_baz.f90 module FOO_BAZModule interface subroutine FOO_BAZ() endsubroutine endinterface contains subroutine FOO_BAZ() write(*,*) "FOO_BAZ 2" endsubroutine end module
しかし、コンパイル時には、不快な驚きが待っています。
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>FOO_BAZ.f90 1>F:\2011_03_12\CPP_PROJECTS\Console1\Console1\FOO_BAZ.f90(8): error #6645: The name of the module procedure conflicts with a name in the encompassing scoping unit. [FOO_BAZ] 1>compilation aborted for F:\2011_03_12\CPP_PROJECTS\Console1\Console1\FOO_BAZ.f90 (code 1) 1>Bar.f90 1>FooProgram.f90 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 2 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
モジュラープロシージャの名前は、インターフェイスの名前と競合します。
どうする?
敗北しようとしている暗黙の可能性が私たちに勝ち、私たちの作業時間の半分を変更されていないコードの事実の再コンパイルに費やす運命にあるでしょうか?
ハック。 第二段階
FOO_BAZインターフェースの実装を別のコンパイルユニットで取り出します。
!Foo_baz.f90 module FOO_BAZModule interface subroutine FOO_BAZ() endsubroutine endinterface end module !FOO_BAZ_Implementation.f90 subroutine FOO_BAZ() write(*,*) "FOO_BAZ 2" endsubroutine
コンパイル...
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>FOO_BAZ_Implementation.f90 1>FOO_BAZ.f90 1>Bar.f90 1>FooProgram.f90 1>Linking... 1>Embedding manifest... 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 0 error(s), 0 warning(s) ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
さて、3つのファイルの代わりに、4つのファイルをコンパイルする必要があります。 ハックが機能しませんでしたか?
「外部プロシージャ」タイプのプログラム単位になったFOO_BAZの実装に変更を加え、コンパイルを実行します。
1>------ Build started: Project: Console1, Configuration: Debug Win32 ------ 1>Compiling with Intel(R) Visual Fortran 11.1.051 [IA-32]... 1>FOO_BAZ_Implementation.f90 1>Linking... 1>Embedding manifest... 1> 1>Build log written to "file://F:\2011_03_12\CPP_PROJECTS\Console1\Console1\Debug\BuildLog.htm" 1>Console1 - 0 error(s), 0 warning(s) ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
以上です。 ハックは機能しました。
追加のコンパイルユニットに加えて、このハックの費用はいくらですか?
仕様「外部プロシージャ」FOO_BAZがモジュールFOO_BAZModuleからのインターフェイスFOO_BAZを満たす(一致する)事実に責任があるという事実。
結論
入り口で持っていたものと同じものを受け取っていませんか?
実用的な観点から-いいえ、彼らはそれを得なかった、なぜなら 手動検証は、最後の段階、つまりインターフェースの実装でのみ必要になります。
私の設計プロジェクトでは、同様のハックにより、開発中のモジュールから巨大な安定したコードを切り離すことができました。
エピローグ
もちろん、.NETプラットフォーム用のコンパイラファミリは、Microsoft Visual Studioでコードを記述している瞬間にプロジェクト全体にアクセスできるようになったため、これらの考えは気さくな笑顔を引き起こしますが、エンジニアリング環境では急いで移動しないことを忘れないでくださいインテルは引き続きFortranコンパイラーの開発を続けています。
また、Fortran自体は静止していません。Fortran2003およびFortran 2008の標準は、長い間利用可能です。
1年前、私の同僚は、あなたのトライアルのために今日提案されたハックが新しい標準に反映されているという事実に注意を喚起しましたが、私が知る限り、これはほとんどのFortranコンパイラでまだ実装されていません:商用および無料で配布されています。
参照資料
この記事では、Microsoft Visual Studio * 2008、11.1.3468.2008、Copyright©2002-2009 Intel Corporation向けインテル®Visual Fortranコンパイラー統合を使用したインテル®Visual Fortranコンソールアプリケーションプロジェクトのコンパイルログを使用しました。
*他の名前およびブランドは、他者の財産として主張される場合があります。
Microsoft Visual Studio 2008へ
バージョン9.0.30729.1 SP©2007 Microsoft Corporation
インテル®Fortranコンパイラー11.1ユーザーおよびリファレンスガイドの資料
Ps作者は、行われたいかなる言明についても心から誤解するかもしれません。