如何在C中链接目标文件?失败"为架构x86_64定义未定义的符号"

adi*_*adi 48 c gcc compilation

所以我正在尝试使用我文件(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
Run Code Online (Sandbox Code Playgroud)

我被告知我需要"将目标文件链接在一起"才能使用file2中file1的功能,但我不知道这意味着什么:(

bas*_*h.d 79

我假设您正在使用gcc,只需链接目标文件:

$ gcc -o output file1.o file2.o
Run Code Online (Sandbox Code Playgroud)

获取对象文件只需使用编译

$ gcc -c file1.c
Run Code Online (Sandbox Code Playgroud)

这会产生file1.o等等.

如果要将文件链接到可执行文件,请执行

$ gcc -o output file1.c file2.c
Run Code Online (Sandbox Code Playgroud)

  • 您能否给出一个更复杂的示例(即链接到“librt.so”)。如果超出这个问题的范围,您能否提供另一个更复杂问题的链接? (2认同)
  • 这个答案中的“main.c”在哪里?:/ 如果 file1.c 是主文件,如何将它与其他已编译的 .o 文件链接? (2认同)
  • 嗨,这篇文章很老了...我只是对第一个命令行和第三个命令行的区别有疑问.编译器是否自动识别输入是目标文件还是源文件? (2认同)

小智 21

现有的答案已经涵盖了"如何",但我只是想详细说明可能想知道的其他人的"什么"和"为什么".

编译器(gcc)的作用是什么:术语"编译"是一个过载的术语,因为它在高级用于表示"将源代码转换为程序",但在技术上更具意味着"将源代码转换为目标代码".像gcc这样的编译器实际上执行两个相关但可以说是不同的函数来将源代码转换为程序:编译(如后一个将源代码转换为目标代码的定义)和链接(将必要的目标代码文件组合到一起的过程)一个完整的可执行文件

您看到的原始错误在技术上是一个"链接错误",并由链接器"ld"抛出.与(严格)编译时错误不同,没有对源代码行的引用,因为链接器已经在对象空间中.

默认情况下,当gcc被赋予源代码作为输入时,它会尝试编译每个源代码,然后将它们全部链接在一起.如其他响应中所述,可以使用标志来指示gcc首先进行编译,然后稍后使用目标文件在单独的步骤中进行链接.这个两步过程似乎是不必要的(也可能是非常小的程序)但是在管理一个非常大的程序时非常重要,每次进行小的更改时编译整个项目都会浪费相当多的时间.

  • 不错的解释,但是你能举一个具体的例子来说明如何链接两个文件让我们说ao和bo通过"ld"命令? (2认同)

Joh*_*web 8

您可以在一个命令中编译和链接:

gcc file1.c file2.c -o myprogram
Run Code Online (Sandbox Code Playgroud)

并运行:

./myprogram
Run Code Online (Sandbox Code Playgroud)

但要回答问题,只需将目标文件传递给gcc:

gcc file1.o file2.o -o myprogram
Run Code Online (Sandbox Code Playgroud)


ash*_*ew2 5

由于没有提及如何将 .c 文件与一堆 .o 文件一起编译,并且此评论要求这样做:

\n\n
\n

这个答案中的 main.c 在哪里?:/ 如果 file1.c 是主文件,\n 如何将它与其他已编译的 .o 文件链接?\xe2\x80\x93 汤姆·布里托 2014 年 10 月 12 日 19:45

\n
\n\n

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

\n\n

这里,main.c 是带有 main() 函数的 C 文件,目标文件 (*.o) 是预编译的。GCC 知道如何一起处理这些,并相应地调用链接器并产生最终的可执行文件,在我们的例子中是 x0rbin。

\n\n

您将能够使用未在 main.c 中定义的函数,但可以使用对目标文件 (*.o) 中定义的函数的外部引用。

\n\n

如果目标文件具有正确的格式(例如 COFF),您还可以使用 .obj 或其他扩展名进行链接。

\n


Ar *_*maj 5

将foo1.c,foo2.c,foo3.c和makefile添加到bash中make类型的一个文件夹中

如果您不想使用makefile,则可以运行该命令

gcc -c foo1.c foo2.c foo3.c
Run Code Online (Sandbox Code Playgroud)

然后

gcc -o output foo1.o foo2.o foo3.o
Run Code Online (Sandbox Code Playgroud)

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 ();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

foo2.c

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

foo3.c

#include <stdio.h>

void funk4(){
    printf("\nfunk4\n");
}
void funk5(){
    printf("\nfunk5\n");
}
Run Code Online (Sandbox Code Playgroud)

生成文件

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
Run Code Online (Sandbox Code Playgroud)