web-dev-qa-db-ja.com

Cでオブジェクトファイルをリンクするにはどうすればよいですか? 「アーキテクチャx86_64の未定義のシンボル」で失敗する

だから私は私のファイル(file2.c)で別のC(file1.c)ファイルで定義された関数を使用しようとしています。これを行うために、file1(file1.h)のヘッダーを含めています。

ただし、gccを使用してファイルをコンパイルしようとすると、常に次のエラーが表示されます。

Undefined symbols for architecture x86_64:
  "_init_filenames", referenced from:
      _run_worker in cc8hoqCM.o
  "_read_list", referenced from:
      _run_worker in cc8hoqCM.o
ld: symbol(s) not found for architecture x86_64

File2のfile1の関数を使用するには、「オブジェクトファイルをリンクする」必要があると言われましたが、それが何を意味するのかわかりません:(

45
adi

オブジェクトファイルを単にリンクするためにgccを使用していると仮定します。

$ gcc -o output file1.o file2.o

オブジェクトファイルを取得するには、単に次を使用してコンパイルします

$ gcc -c file1.c

これにより、file1.oなどが生成されます。

ファイルを実行可能ファイルにリンクしたい場合

$ gcc -o output file1.c file2.c
79
bash.d

既存の答えはすでに「どのように」をカバーしていますが、私は疑問に思うかもしれない他の人のために「何」と「なぜ」について詳しく述べたかっただけです。

コンパイラー(gcc)の機能:「コンパイル」という用語は、「ソースコードをプログラムに変換する」という意味で高レベルで使用されますが、技術的には「ソースコードをオブジェクトコード」。 gccのようなコンパイラは、実際には、ソースコードをプログラムに変換するための2つの関連する、しかし間違いなく異なる機能を実行します。コンパイル(ソースをオブジェクトコードに変換する後者の定義)とリンク(必要なオブジェクトコードファイルを結合するプロセス) 1つの完全な実行可能ファイル)。

あなたが見た元のエラーは技術的には「リンクエラー」であり、リンカーである「ld」によってスローされます。 (厳密な)コンパイル時エラーとは異なり、リンカはすでにオブジェクト空間にあるため、ソースコード行への参照はありません。

デフォルトでは、gccに入力としてソースコードが渡されると、gccはそれぞれをコンパイルしてから、それらをすべてリンクしようとします。他の応答で述べたように、フラグを使用してgccに最初にコンパイルするよう指示し、その後オブジェクトファイルを使用して別のステップでリンクすることができます。この2段階のプロセスは不必要に思えるかもしれません(おそらく非常に小さなプログラムの場合です)が、非常に大きなプログラムを管理する場合は非常に重要です。小さな変更を加えるたびにプロジェクト全体をコンパイルすると、かなりの時間が無駄になります。

21
SeKa

1つのコマンドでコンパイルおよびリンクできます。

gcc file1.c file2.c -o myprogram

そして実行:

./myprogram

ただし、質問に答えるには、オブジェクトファイルをgccに渡すだけです。

gcc file1.o file2.o -o myprogram
8
Johnsyweb

Foo1.c、foo2.c、foo3.cおよびmakefileをbashのmakeタイプの1つのフォルダーに追加します

メイクファイルを使用したくない場合は、コマンドを実行できます

gcc -c foo1.c foo2.c foo3.c

それから

gcc -o output foo1.o foo2.o foo3.o

foo1.c

#include <stdio.h>
#include <string.h>

void funk1();

void funk1() {
    printf ("\nfunk1\n");
}


int main(void) {

    char *arg2;
    size_t nbytes = 100;

    while ( 1 ) {

        printf ("\nargv2 = %s\n" , arg2);
        printf ("\n:> ");
        getline (&arg2 , &nbytes , stdin);
        if( strcmp (arg2 , "1\n") == 0 ) {
            funk1 ();
        } else if( strcmp (arg2 , "2\n") == 0 ) {
            funk2 ();
        } else if( strcmp (arg2 , "3\n") == 0 ) {
            funk3 ();
        } else if( strcmp (arg2 , "4\n") == 0 ) {
            funk4 ();
        } else {
            funk5 ();
        }
    }
}

foo2.c

#include <stdio.h>
void funk2(){
    printf("\nfunk2\n");
}
void funk3(){
    printf("\nfunk3\n");
}

foo3.c

#include <stdio.h>

void funk4(){
    printf("\nfunk4\n");
}
void funk5(){
    printf("\nfunk5\n");
}

メイクファイル

outputTest: foo1.o foo2.o foo3.o
    gcc -o output foo1.o foo2.o foo3.o
    make removeO

outputTest.o: foo1.c foo2.c foo3.c
    gcc -c foo1.c foo2.c foo3.c

clean:
    rm -f *.o output

removeO:
    rm -f *.o
5
Ar maj

.cファイルを多数の.oファイルと一緒にコンパイルする方法については言及されていないため、このコメントはそれを求めています。

この答えのmain.cはどこですか? :/ file1.cがメインの場合、既にコンパイルされている他の.oファイルとどのようにリンクしますか? –トムブリトー14年10月12日19:45

$ gcc main.c lib_obj1.o lib_obj2.o lib_objN.o -o x0rbin

ここで、main.cはmain()関数を含むCファイルであり、オブジェクトファイル(* .o)はプリコンパイルされています。 GCCはこれらを一緒に処理する方法を知っており、それに応じてリンカーを呼び出し、最終的な実行可能ファイル(この場合はx0rbin)を生成します。

Main.cで定義されていない関数を使用できますが、オブジェクトファイル(* .o)で定義されている関数への外部参照を使用できます。

オブジェクトファイルの形式が正しい場合(COFFなど)、. objまたは他の拡張子とリンクすることもできます。

2
ashmew2