61

所以我试图在我的文件(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 中的函数,但我不知道这意味着什么:(

4

5 回答 5

103

我假设您正在使用gcc, 来简单地链接目标文件:

$ gcc -o output file1.o file2.o

要获取目标文件,只需使用编译

$ gcc -c file1.c

这会产生 file1.o 等等。

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

$ gcc -o output file1.c file2.c
于 2013-03-15T20:53:30.270 回答
26

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

编译器 (gcc) 的作用:术语“编译”是一个有点重载的术语,因为它在高层次上用于表示“将源代码转换为程序”,但更技术上的意思是“将源代码转换为目标代码”。像 gcc 这样的编译器实际上执行了两个相关但可以说是不同的功能来将您的源代码转换为程序:编译(如后一个将源代码转换为目标代码的定义)和链接(将必要的目标代码文件组合在一起的过程)一个完整的可执行文件)。

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

默认情况下,当 gcc 被提供源代码作为输入时,它会尝试编译每个源代码,然后将它们链接在一起。正如其他响应中所指出的,可以使用标志来指示 gcc 先编译,然后使用目标文件在单独的步骤中链接。这个两步过程似乎没有必要(并且可能适用于非常小的程序),但在管理非常大的程序时非常重要,因为每次进行小的更改都编译整个项目会浪费大量时间。

于 2013-03-16T04:04:36.680 回答
12

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

gcc file1.c file2.c -o myprogram

并运行:

./myprogram

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

gcc file1.o file2.o -o myprogram
于 2013-03-15T20:53:23.720 回答
8

将 foo1.c 、 foo2.c 、 foo3.c 和 makefile 添加到一个文件夹中,在 bash 中键入 make

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

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
于 2016-02-15T16:04:34.417 回答
3

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

这个答案中的 main.c 在哪里?:/ 如果 file1.c 是主要文件,你如何将它与其他已编译的 .o 文件链接?– 汤姆布里托 2014 年 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 或其他扩展名进行链接。

于 2015-08-26T09:44:41.643 回答