如何链接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函数,但是我不知道这意味着什么:

我假设你使用的是gcc ,只需链接目标文件即可:

 $ gcc -o output file1.o file2.o 

获取对象文件简单地编译使用

 $ gcc -c file1.c 

这产生file1.o等等。

如果你想链接你的文件到一个可执行文件

 $ gcc -o output file1.c file2.c 

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

编译器(gcc)做了什么:术语“编译”是一个超载的术语,因为它被用在高级别的意思是“将源代码转换成程序”,但更技术上意味着“将源代码转换为目标代码“。 像gcc这样的编译器实际上执行了两个相关的,但可以说是截然不同的function来将你的源代码转换成一个程序:编译(如在后来的源代码转换为目标代码的定义)和链接(将必要的目标代码文件组合到一起一个完整可执行文件)

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

默认情况下,当gcc被赋予源代码作为input时,它会尝试编译每个然后将它们连接在一起。 正如其他回复中指出的那样,可以使用标志来指示gcc首先编译,然后稍后使用目标文件在单独的步骤中进行链接。 这个两步过程可能看起来没有必要(可能是非常小的程序),但是在pipe理一个非常大的程序时非常重要,在每次进行小的更改时编译整个项目会浪费相当多的时间。

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

 gcc file1.c file2.c -o myprogram 

并运行:

 ./myprogram 

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

 gcc file1.o file2.o -o myprogram 

将foo1.c,foo2.c,foo3.c和makefile添加到bash中的maketypes的文件夹中

如果您不想使用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 

由于没有提到如何编译一个.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中没有定义的函数,但是使用extern引用来定义目标文件(* .o)中定义的函数。

如果对象文件具有正确的格式(如COFF),您也可以链接.obj或其他扩展名。