将多个C源文件编译成一个唯一的目标文件

22

我有一些C源文件并且我正在使用gcc。我想编译它们并创建一个单独的目标文件。当我尝试:

gcc -c src1.c src2.c src3.c -o final.o

我得到:

gcc: cannot specify -o with -c or -S with multiple files

如果我尝试:

gcc -c src1.c src2.c src3.c

我得到了三个不同的目标文件。 我该如何告诉gcc编译所有文件以返回一个单独的目标文件(我还想指定它的名称)?谢谢。

也许有另一种更常见的方法,请告诉我。


1
好的,请告诉我如何... - Andry
阅读http://tldp.org/HOWTO/Program-Library-HOWTO/,了解有关“make”的内容。 - Basile Starynkevitch
顺便问一下,你为什么要问呢? - Basile Starynkevitch
子集:使用目标文件而不是源文件:https://dev59.com/o3A85IYBdhLWcg3wBOxO - Ciro Santilli OurBigBook.com
8个回答

28

您不能将多个源文件编译成一个单独的目标文件。目标文件是单个源文件及其头文件(也称为翻译单元)的编译结果。

如果您想要合并已编译的文件,通常会使用ar命令将它们合并为静态库:

$ ar cr libfoo.a file1.o file2.o file3.o

接下来可以使用这个静态库进行链接,可以直接将它作为目标文件传递:

$ gcc file4.o libfoo.a -o myprogram

或者使用-l标志将其链接为库

$ gcc file4.o -L. -lfoo -o myprogram

3
这意味着gcc无法在不同的源文件之间将函数设为内联吗? - Crouching Kitten
6
不是编译器,而是链接器可能能够进行一些链接时优化,其中可能包括跨翻译单元的内联。 - Some programmer dude
1
请注意,在调用gcc时,库必须在目标文件之后。应为file1.o file2.o libfoo.a而不是libfoo.a file1.o file2.o - Benjamin Smus
1
请注意,在调用gcc时,库文件必须在目标文件之后。应该是file1.o file2.o libfoo.a,而不是libfoo.a file1.o file2.o - undefined

12

虽然这不是通常的做法,但您可以通过创建一个新的 final.c 文件,并使用以下内容轻松实现您想要的功能。

#include "src1.c"
#include "src2.c"
#include "src3.c"

然后您可以按照以下方式进行编译。

gcc -c final.c -o final.o

请注意,即使每个文件在单独编译时都能成功编译,但在将源文件合并为一个文件时,可能会出现问题,例如编译错误。这种情况通常发生在宏定义和包含文件时。


10

也许你正在寻找这个:

ld -r src1.o src2.o src3.o -o final.o

但保留它们的档案始终是个好习惯,使用

ar rvs libmy.a file1.o file2.o file3.o

然后使用-lmy进行链接。


1
不是ld的源文件src1.c src2.c src3.c,而是目标文件src1.o src2.o src3.o - Basile Starynkevitch

4

如果要将多个源文件合并为单个对象文件(至少从gcc 4.1开始),请使用编译器/链接器选项--combine。

(编辑)后来改用编译器选项-flto,链接取决于编译状态的自动链接:使用flto的要求


不存在?g++:错误:未识别的命令行选项 '--combine' gcc --version gcc(GCC)4.8.3 20140911(Red Hat 4.8.3-7) - gaoithe
它在 GCC 4.6 中被移除了。 - Hedede

2

您可以将文件传输到GCC中:

join file1.c file2.c file3.c | gcc -x c -c -o single.o -

请注意,不要忘记指定语言选项“-x c”,现在无法从文件扩展名中推断出。您可以使用单个尾随破折号“-”告诉GCC从stdin接受输入。

请注意,这等同于编译一个名为“final.c”的文件,并具有以下内容:

#include "file1.c"
#include "file2.c"
#include "file3.c"

随着

gcc -c -o single.o final.c

小心名称冲突。如果file1.c和file2.c声明了相同的静态变量,那将会很痛苦。 - undefined

2

我想说的是,这是一个缺失的功能。

为什么呢?

因为 cc 可以是 clang 或者 gcc

cc -c t1.c t2.c (multi-files at once)

vs

cc -c t1.c 
cc -c t2.c
...
(one by one)

有什么不同之处?

输出的 .o 文件相同,虽然逐个文件的方式可以指定-o name,这在使用自定义工具链时可能很有用。

区别在于性能。除了启动 cc 的时间外,如果多个文件使用相同的 .h 头文件集(在大多数情况下会是这样),则头文件只需加载一次,而不是每个文件都要加载。

如果使用多个库,则头文件可能非常大。一个典型的 .pch(预编译头)文件可能达到10MB。

在我的小项目的实际测试中,我将所有 .cpp 组合成一个 .cpp,使用#include "others.cpp",编译时间从 600 毫秒减少到 300 毫秒。

c/cpp 编译速度较慢,因此这可能是一个很有用的功能。

可以像这样:

cc -c t1.c -o t1.o  t2.c -o t2.o (specify output name per file)

或者

cc -c t1.c  t2.c -o mylib.a (If some one say .o can't be combined
   , then link to a lib in one command line)

我希望clang或gcc的开发者能看到这篇文章。但即使他们同意这个观点,也不必等待修复。(在开源开发者之间争论可能很无望,除非他们从自身意识到了什么)。您可以尝试其他答案中提到的方法。
#include "file1.c"
#include "file2.c"
#include "file3.c"

在编译时减少磁盘使用并为优化器提供更广泛的内存想法实际上是有意义的。同样,还有“单头文件打包器”。其他优点包括可以构建一些小型/特定的东西而无需通过Makefiles。 - DiegoJArg

0

尝试使用

gcc -o final file1.c file2.c file3.c

对我来说它有效。


1
这将生成一个二进制文件,显然不是问题所要求的(目标文件)。请检查您的答案或删除它以免混淆其他人。 - Manoel Vilela
这将创建3个目标文件,并将它们链接成一个可执行文件。由于目标文件是分开的,编译器无法内联或以其他方式优化跨模块调用和引用。 - david

0
要么您可以创建一个名为final.c的文件,其中包含所有.c文件,然后使用gcc -c final.c命令编译此最终文件。
或者,另一种方法是使用存档。将所有文件构建以获取相应的.o文件,然后将它们归档到一个库中,该库包含所有这些.o文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接