34

昨年、私は研究大学で Fortran でプログラミングを始めました。私の以前の経験のほとんどは、PHP や古い ASP などの Web 言語に関するものでした。そのため、ステートメントをコンパイルする初心者です。

変更している 2 つの異なるコードがあります。

実行可能ファイルを作成する前に、モジュールから .o ファイルを作成 する明示的なステートメント ( gfortran -c filea.f90 など) があります。

もう 1 つ、実行可能ファイルを直接作成する方法です (.mod ファイルを作成する場合もありますが、.o ファイルは作成しません。例: gfortran -o 実行可能ファイルa.f90 ファイルb.f90 メインファイル.f90)。

  • ある方法が他の方法よりも優先される理由 (おそらく Makefile 以外) はありますか?
4

5 に答える 5

32

最初にオブジェクト ファイルにコンパイルすることを個別コンパイルと呼びます。多くの利点といくつかの欠点があります。

利点:

  • オブジェクト ファイル (.o) をライブラリに簡単に変換し、後でそれらにリンクする
  • 多くの人が同時に異なるソース ファイルで作業できる
  • コンパイルの高速化 (ソースが変更されていない場合、同じファイルを何度もコンパイルする必要はありません)
  • オブジェクト ファイルは、異なる言語ソースから作成し、後でリンクすることができます。これを行うには、オブジェクト ファイルが同じ形式と互換性のある呼び出し規則を使用する必要があります。
  • 個別のコンパイルにより、静的または共有のシステム全体のライブラリ (OS ライブラリ、言語標準ライブラリ、またはサードパーティ ライブラリのいずれか) の配布が可能になります。

欠点:

  • コンパイラーが実行できないいくつかの最適化 (関数の最適化など) があり、リンカーは気にしません。ただし、多くのコンパイラには現在、「リンク時の最適化」を実行するオプションが含まれており、この欠点を大幅に解消しています。しかし、これはシステム ライブラリやサード パーティ ライブラリ、特に共有ライブラリでは依然として問題です (実行のたびに変更される可能性のあるコンポーネントの部分を最適化することはできませんが、JIT コンパイルなどの他の手法でこれを軽減できる可能性があります)。
  • 一部の言語では、プログラマーは、このオブジェクトにリンクする他のオブジェクトを使用するために、ある種のヘッダーを提供する必要があります。たとえば C.hでは、オブジェクト ファイルと一緒にファイルを提供する必要があります。しかし、とにかくそれは良い習慣です。
  • C や C++ などのテキスト ベースのインクルードを使用する言語では、関数プロトタイプを変更する場合、2 つの場所で変更する必要があります。ヘッダー ファイルで 1 回、実装ファイルで 1 回。
于 2011-03-12T16:48:46.357 に答える
15

数 100 個のソース ファイルを含むプロジェクトがある場合、 1 つの変更のたびにすべてを再コンパイルする必要はありません。各ソース ファイルを個別のオブジェクト ファイルにコンパイルし、変更の影響を受けるソース ファイルのみを再コンパイルすることで、ソース コードの変更から新しい実行可能ファイルまでの時間を最小限に抑えます。

makeこのような依存関係を追跡し、何かが変更されたときにバイナリを再作成するために使用される一般的なツールです。通常、各ソース ファイルが何に依存するかを設定し (これらの依存関係は通常、コンパイラによって生成されます - に適した形式でmake)、最新のバイナリの作成に関する詳細は make に処理させます。

于 2011-03-12T16:46:59.923 に答える
6

.o ファイルはオブジェクト ファイルです。これは、最終的なプログラムの中間表現です。

具体的には、通常、.o ファイルにはコンパイル済みのコードが含まれていますが、さまざまなルーチンやデータすべての最終アドレスは含まれていません。

プログラムを実行する前に必要なものの 1 つは、メモリ イメージに似たものです。

例えば。

メインプログラムがあり、それがルーチン A を呼び出すとします。

PROGRAM MAIN
INTEGER X,Y
X = 10
Y = SQUARE(X)
WRITE(*,*) Y
END

次に、SQUARE 関数があります。

FUNCTION SQUARE(N)
SQUARE = N * N
END

は個別にコンパイルされたユニットです。MAIN がコンパイルされると、「SQUARE」がどこにあるのか、どのアドレスにあるのかがわからないことがわかります。そのため、マイクロプロセッサの JUMP SUBROUTINE (JSR) 命令を呼び出すとき、その命令にはどこかへ行く場所があることを知る必要があります。

.o ファイルにはすでに JSR 命令がありますが、実際の値はありません。これは、後でリンクまたはロード フェーズで行われます (アプリケーションによって異なります)。

そのため、MAINS .o ファイルには main のすべてのコードと、解決したい参照のリスト (特に SQUARE) が含まれています。SQUARE は基本的にスタンドアロンであり、参照はありませんが、同時にメモリ内のどこに存在するかについてのアドレスはまだありません。

リンカーはすべての .o ファイルを取り出し、それらを 1 つの exe に結合します。昔は、コンパイルされたコードは文字通りメモリ イメージでした。プログラムは、あるアドレスから開始し、単純に RAM ホールセールにロードされてから実行されます。したがって、このシナリオでは、リンカが 2 つの .o ファイルを取得し、それらを連結して (SQUARE の実際のアドレスを取得するため)、戻って MAIN で SQUARE 参照を見つけ、アドレスを入力することがわかります。

最新のリンカはそこまでは進んでおらず、その最終処理の多くをプログラムが実際にロードされるまで延期します。しかし、コンセプトは似ています。

.o ファイルにコンパイルすることで、再利用可能なロジック ユニットが作成され、実行前にリンクおよびロード プロセスによって結合されます。

もう 1 つの優れた点は、.o ファイルをさまざまな言語から取得できることです。呼び出しメカニズムに互換性がある限り (つまり、関数やプロシージャとの間で引数がどのように渡されるか)、.o にコンパイルされると、ソース言語の関連性は低くなります。たとえば、C コードと FORTRAN コードをリンク、結合できます。

PHP などでは、実行時にすべてのコードが 1 つのイメージに読み込まれるため、プロセスが異なります。FORTRAN の .o ファイルは、PHP のインクルード メカニズムを使用してファイルを結合し、まとまりのある大きな全体にする方法に似ていると考えることができます。

于 2011-03-12T17:00:57.120 に答える
2

コンパイル時間以外のもう 1 つの理由は、コンパイル プロセスがマルチステップ プロセスであることです。

マルチパートプロセス。

オブジェクト ファイルは、そのプロセスからの中間出力の 1 つにすぎません。それらは最終的にリンカーによって使用され、実行可能ファイルが生成されます。

于 2011-03-12T16:51:10.217 に答える
1

オブジェクトファイルにコンパイルして、それらをリンクしてより大きな実行可能ファイルを形成できるようにします。それが唯一の方法ではありません。

そのようにしないコンパイラもありますが、代わりにメモリにコンパイルして結果をすぐに実行します。以前、学生がメインフレームを使用しなければならなかったときは、これが標準でした。Turbo Pascal もこのようにしました。

于 2011-03-12T17:50:33.213 に答える