7

コンパイルの仕組みを説明できる人はいますか?

コンパイルがどのように機能するのか理解できないようです..

より具体的には、ここに例を示します.Lua状態をロードするために、MSVC++ 6でいくつかのコードを記述しようとしています..

私はすでに:

  • ライブラリとインクルード ファイルの追加ディレクトリを適切なディレクトリに設定します。
  • extern "C" を使用 (Lua は C のみと聞いているため)
  • 正しいヘッダファイルをインクルード

しかし、未解決の外部シンボルに関する MSVC++6 のエラーがまだ発生しています (使用した Lua 関数の場合)。

この問題を解決して先に進む方法を知りたいのですが、関連する基本的なプロセスを理解するようになった方がはるかに良いと思います. 私が知りたいのはプロセスです..次のようになります。

ステップ1:

  • 入力: ソースコード
  • プロセス: 解析 (おそらくここに詳細を追加します)
  • 出力: ここに出力されるものは何でも..

ステップ2:

  • 入力: ステップ 1 の出力に加えて、他に必要なもの (ライブラリ? DLL? .so? .lib? )
  • プロセス: 入力に対して行われることすべて
  • 出力: 出力されるものは何でも

等々..

ありがとう..

おそらく、これはシンボルとは何か、「リンク」とは何か、「オブジェクト」コードとは何か、または何かを説明するでしょう..

ありがとう..初心者でごめんなさい..

PS これは言語固有である必要はありません..しかし、あなたが最も慣れている言語で自由に表現してください.. :)

編集:とにかく、エラーを解決することができました.libファイルをプロジェクトに手動で追加する必要があることがわかりました; IDE 設定またはプロジェクト設定でライブラリ ディレクトリ (.lib が存在する場所) を指定するだけでは機能しません。

ただし、以下の回答は、プロセスをよりよく理解するのに多少役立ちました。どうもありがとう!.. まだ完全なガイドを書きたい人がいたら、どうぞ.. :)

編集: 追加の参照用に、1 人の著者 (Mike Diehl) による 2 つの記事を見つけて、これを非常によく説明しています.. :) コンパイル プロセスの調査: パート 1 コンパイル プロセスの調査: パート 2

4

5 に答える 5

13

ソースから実行可能ファイルへの変換は、通常、C および関連言語では 2 段階のプロセスですが、IDE ではおそらくこれが 1 つのプロセスとして表示されます。

1/ ソースをコード化し、コンパイラで実行します。この段階のコンパイラは、ソースと、リンクしようとしている他のもののヘッダー ファイルを必要とします (以下を参照)。

コンパイルでは、ソース ファイルをオブジェクト ファイルに変換します。オブジェクトファイルには、コンパイルされたコードと、他に必要なものを知るのに十分な情報がありますが、他のもの (LUA ライブラリなど) を見つける場所はありません。

2/ 次の段階であるリンクでは、すべてのオブジェクト ファイルをライブラリと組み合わせて、実行可能ファイルを作成します。動的リンクについては説明が複雑になり、メリットがほとんどないため、ここでは説明しません。

リンカーが他のコードを見つけることができるディレクトリを指定する必要があるだけでなく、そのコードを含む実際のライブラリを指定する必要があります。未解決の外部を取得しているという事実は、これを行っていないことを示しています。

例として、次の簡略化された C コード ( xx.c) とコマンドを考えてみましょう。

#include <bob.h>
int x = bob_fn(7);

cc -c -o xx.obj xx.c

xx.cこれにより、ファイルが にコンパイルされますxx.obj。には、コンパイルが成功するようにのbob.hプロトタイプが含まれています。bob_fn()-c、実行可能ファイルではなくオブジェクト ファイルを生成するようにコンパイラに指示し-o xx.obj、出力ファイル名を設定します。

しかし、 の実際のコードはヘッダー ファイルでbob_fn()はなく にある/bob/libs/libbob.soため、リンクするには次のようなものが必要です。

cc -o xx.exe xx.obj -L/bob/libs;/usr/lib -lbob

これは、フォームのライブラリ (指定されたパスで検索される) を使用してxx.exefromを作成します (通常、lib と .so はリンカーによって追加されます)。この例では、ライブラリの検索パスを設定します。は、必要に応じて実行可能ファイルに含めるために検索するライブラリを指定します。リンカーは通常、「bob」を受け取り、 で指定された検索パスで最初の関連ライブラリ ファイルを見つけます。xx.objlibbob.so-L-l-L

ライブラリ ファイルは、実際にはオブジェクト ファイルのコレクションです (zip ファイルに複数の他のファイルが含まれているのと似ていますが、必ずしも圧縮されているわけではありません)。未定義の外部ファイルの最初の関連する出現が見つかった場合、オブジェクト ファイルはライブラリからコピーされ、追加されます。ファイルと同じように実行可能xx.objファイルに。これは通常、未解決の外部がなくなるまで続きます。「関連する」ライブラリは「bob」テキストの変更であり、、、、、、などlibbob.aを検索できlibbob.dllます。関連性はリンカー自体によって決定され、文書化する必要があります。libbob.sobob.abob.dllbob.so

どのように動作するかはリンカーによって異なりますが、基本的にはこれです。

1/ すべてのオブジェクト ファイルには、解決する必要がある未解決の外部のリストが含まれています。リンカーは、これらすべてのオブジェクトをまとめて、それらの間のリンクを修正します (できるだけ多くの外部オブジェクトを解決します)。

2/ 次に、まだ解決されていないすべての外部に対して、リンカはライブラリ ファイルを調べて、リンクを満たすことができるオブジェクト ファイルを探します。見つかった場合は、それを引き込みます。取り込まれたオブジェクトには、満たす必要のある独自の外部リストがあるため、さらに未解決の外部が発生する可能性があります。

3/ 未解決の外部がなくなるか、ライブラリ リストから解決される可能性がなくなるまで、手順 2 を繰り返します (LUA ライブラリ ファイルを含めていないため、ここで開発が行われました)。

前述の複雑な点は、動的リンクです。これは、実際のルーチンではなく、ルーチンのスタブ (一種のマーカー) とリンクする場所であり、後でロード時 (実行可能ファイルの実行時) に解決されます。Windows コモン コントロールなどはこれらの DLL に含まれているため、オブジェクトを新しい実行可能ファイルに再リンクしなくても変更できます。

于 2009-02-04T07:17:47.933 に答える
5

ステップ 1 - コンパイラ:

  • 入力: ソース コード ファイル[s]
  • プロセス: ソース コードの解析とマシン コードへの変換
  • 出力: 以下で構成されるオブジェクトファイル:
    • このオブジェクトで定義され、このオブジェクト ファイルが「エクスポート」するシンボルの名前
    • このオブジェクト ファイルで定義されている各シンボルに関連付けられているマシン コード
    • このオブジェクト ファイルで定義されていないが、このオブジェクト ファイルのソフトウェアが依存し、後でリンクする必要があるシンボルの名前。つまり、このオブジェクト ファイルが「インポート」する名前

ステップ 2 - リンク:

  • 入力:
    • 手順 1 のオブジェクト ファイル
    • 他のオブジェクトのライブラリ (例: O/S および他のソフトウェアから)
  • プロセス:
    • リンクするオブジェクトごとに
    • このオブジェクトがインポートするシンボルのリストを取得します
    • 他のライブラリでこれらのシンボルを見つける
    • 対応するライブラリをオブジェクト ファイルにリンクする
  • 出力: すべてのオブジェクトのマシン コードと、オブジェクトにインポート (リンク) されたライブラリのオブジェクトを含む単一の実行可能ファイル。
于 2009-02-04T07:10:50.880 に答える
3

2 つの主要なステップは、コンパイルとリンクです。

コンパイルは、単一のコンパイル ユニット (これらは、含まれるすべてのヘッダーを含む単なるソース ファイルです) を取り、オブジェクト ファイルを作成します。これらのオブジェクト ファイルには、特定の場所 (アドレス) で定義された多くの関数 (および静的データなどのその他のもの) があります。次のステップであるリンクでは、これらの関数に関する少しの追加情報、つまり名前も必要です。したがって、これらも保存されます。単一のオブジェクト ファイルは、実際には他のオブジェクト ファイルにある関数を参照できます (コードを実行するときに呼び出す必要があるため)。ただし、ここでは単一のオブジェクト ファイルを扱っているため、シンボリック参照 (それらの「名前」) のみを参照できます。これらの他の関数は、オブジェクト ファイルに保存されます。

次はリンクです (ここでは静的リンクに限定しましょう)。リンクは、最初のステップで (直接、または .lib ファイルに一緒にスローされた後に) 作成されたオブジェクト ファイルがまとめられ、実行可能ファイルが作成される場所です。リンク手順では、正しいオブジェクト内の名前を検索し、関数のアドレスを見つけ、アドレスを右側に配置することにより、1 つのオブジェクト ファイルまたは lib から別のオブジェクト ファイルへのすべてのシンボリック参照が解決されます (可能な場合)。場所。

さて、あなたが必要とする「extern "C"」について何かを説明するには:

C には関数のオーバーロードがありません。関数は常にその名前で認識できます。したがって、コードを C コードとしてコンパイルすると、関数の実際の名前だけがオブジェクト ファイルに格納されます。

ただし、C++には「関数/メソッドのオーバーロード」と呼ばれるものがあります。これは、関数の名前だけではもはやそれを識別するのに十分ではないことを意味します。そのため、C++ コンパイラは、関数のプロトタイプを含む関数の「名前」を作成します (名前とプロトタイプによって関数が一意に識別されるため)。これは「ネームマングリング」として知られています。

C++ プロジェクトから「C」コードとしてコンパイルされたライブラリ (たとえば、コンパイル済みの Lua バイナリ) を使用する場合は、「extern "C"」仕様が必要です。

正確な問題について: それでも機能しない場合は、次のヒントが役立つ可能性があります: * Lua バイナリは同じバージョンの VC++ でコンパイルされていますか? * VC ソリューション内で、または C++ コードとして別のプロジェクトとして、Lua を自分でコンパイルできますか? * 'extern "C"' の内容はすべて正しいですか?

于 2009-02-04T07:16:31.463 に答える
1

プロジェクト設定に移動し、その LUA ライブラリ *.lib ファイルがあるディレクトリを「リンカー」タブのどこかに追加する必要があります。「ライブラリを含む」という設定か何か、調べられなくてすみません。

「未解決の外部シンボル」が表示される理由は、C++ でのコンパイルが 2 段階で機能するためです。最初に、コードがコンパイルされ、各 .cpp ファイルが独自の .obj ファイルに含まれます。次に、「リンカー」が開始され、そのすべての .obj ファイルが .exe ファイルに結合されます。.lib ファイルは、ライブラリの配布を少しだけ簡単にするためにマージされた .obj ファイルの集まりです。したがって、すべての「#include」と extern 宣言を追加することで、これらの署名を持つコードをどこかで見つけることができるが、リンカーは実際のコードを含む .lib ファイルがどこにあるかわからないため、そのコードを見つけることができないことをコンパイラーに伝えました配置されます。

ライブラリの REDME を読んだことを確認してください。通常、コードに含めるために何をしなければならなかったかについてかなり詳細に説明されています。

于 2009-02-04T07:00:01.543 に答える
1

これもチェックしてみてください: COMPILER, ASSEMBLER, LINKER AND LOADER: A BRIEF STORY .

于 2009-06-08T20:45:26.207 に答える