【问题标题】:How to use multiple source files to create a single object file with gcc如何使用多个源文件通过 gcc 创建单个目标文件
【发布时间】:2011-09-23 07:05:06
【问题描述】:

我使用 g++ 的 -c 选项来创建一堆目标文件,它只让我为每个目标文件指定一个源文件。我想让多个文件进入其中的一些。有没有办法做到这一点?

【问题讨论】:

  • 你能解释一下为什么吗?你想建立一个图书馆吗?
  • 如果你真的想要,只需创建一个空的 C 文件并包含所有其他 C 文件。
  • 我正在使用链接器脚本来链接它,我需要目标文件才能使用它。我只是不想运行这么多命令来构建它。
  • 如果不想每次运行这么多命令,可以考虑编写一个简单的 Makefile。

标签: c++ object gcc g++


【解决方案1】:

其他人提到了archive,但另一个选项是Unity builds

代替:

g++ -c file1.cpp file2.cpp

创建一个单独的“统一文件”

// This is the entire file (unity.cpp)
#include "file1.cpp"
#include "file2.cpp"
// more if you want...

然后

g++ -c unity.cpp

在很多情况下,这还具有编译和链接速度更快的优点(因为file1.cppfile2.cpp 使用的标头只解析一次)。然而,如果你将太多的文件放在一个单一的单元中,那么你会发现你需要重建比你想要的更多的源,所以你需要尝试平衡。

【讨论】:

  • 太糟糕了,简单的“统一构建实现”仍然公开有关所有内部符号的信息,这些符号在编译为单个对象时可能是静态的。有什么跨平台解决方案吗?
【解决方案2】:

您可以使用ld -r 组合对象,同时保留重定位信息并使构造函数未解析:

ld -r -o everything.o object1.o object2.o ...

【讨论】:

    【解决方案3】:

    您可以创建archive,这是一组目标文件。

    ar mylib.a file1.o file2.o
    

    您已经有效地将file1.cppfile2.cpp 组合成mylib.a

    【讨论】:

    • 但是我仍然需要制作 file1.o 和 file2.o 而不仅仅是 files.o
    • @David,在这种情况下,是的。我不知道我们是否可以将多个文件合并到一个目标文件中。你也可以考虑写一个智能脚本:g++ -c file1.cpp file2.cpp ; ar files.a file1.o file2.o
    【解决方案4】:

    您可以使用ar 命令创建一个存档供您的程序使用。

    【讨论】:

    • 这并不能帮助我减少目标文件的数量。
    【解决方案5】:

    使用来自Peter Alexander 的解决方案是我想到的主要解决方案。

    但是,请记住,通过使用这种方法,您每次都必须编译整个源文​​件。当您的项目变得更大时,编译时间会变得很痛苦。

    此外,自行编译多个文件可以使用现代 CPU 上的各种内核:每个源文件都将在其自己的进程中全速编译。不要充分利用多核的力量。

    【讨论】:

      【解决方案6】:

      我知道您在询问如何将 .cpp 文件合并到一个目标文件中。我假设您这样做的目标是稍后将组合对象与其他单个对象文件链接。如果是这种情况,您可以改用静态或动态库。为了您的目标,我建议使用动态库,因为您可以执行单个编译和链接步骤,完全跳过目标文件的生成。使用诸如g++ -shared -fpic file1.cpp file2.cpp file3.cpp -o libtest.so 之类的命令,您可以将需要合并到库中的 .cpp 文件合并。要使用您的单个目标文件编译库,请使用诸如g++ -ltest individual1.o individual2.o individual3.o -o myexecutable 之类的命令。在最后的链接步骤中,我假设libtest.so 在您的当前目录中。如果它不在您的当前目录中,请添加 -L 标志并且目录 libtest.so 位于其中。

      【讨论】:

      • 是的 - 虽然我猜目标是提高性能以避免 PLT(进程链接表)开销,每当符号可能位于另一个对象而不是引用它的对象时,这是必需的。
      【解决方案7】:

      从某种意义上说,你不能。编译器一次只编译一个文件。当您给它一个文件列表时,无论是使用-c 还是变成单个可执行文件或共享库,它实际上都会使用一些临时输出文件(通常在/tmp 或类似文件中)多次调用编译器,并且然后在事后链接它们。

      因此,解决方案是只要求它编译一个文件。已经提到是写一个文件来编译

      tocompile.cpp
      --------------------
      #include "file1.cpp"
      #include "file2.cpp"
      

      您甚至可以在 Makefile 中自动生成此文件,但事实证明没有必要这样做,因为编译器很乐意从 -(标准输入)读取。

      这意味着你可以简单地运行

      printf '#include "%s"\n' ./*.cpp | $CXX $CXXFLAGS -o combined.o -x c++ -
      

      注意-x 告诉编译器输入是什么语言,通常它根据编译器调用(gcc vs g++ 或类似名称)和文件名进行猜测,但由于文件名是- ,我们必须指定。

      执行此操作时,假设您包含整个项目,gcc 中的-fwhole-program 是减小生成输出大小的好方法,请注意,要使其正常工作,您还需要列出所需的所有库。

      【讨论】:

        【解决方案8】:

        我知道的唯一解决方案是创建一个单独的 C++ 文件,其中包含您要编译的所有文件,然后对其进行编译。在我看来,这是一个非常糟糕的解决方案;通常,您希望增加而不是减少目标文件的粒度。

        我想,真正的问题是你想要达到什么目标。为什么只需要一个目标文件?

        【讨论】:

          【解决方案9】:

          我们使用 -o 选项来创建一个目标文件......默认情况下,当我们使用 gcc 或 g++ 编译文件时,我们会得到一个名为 a.out 的目标文件,但我们可以更改它的名称......使用以下编译文件

          gcc Filename.c -o NewFilename.out

          然后运行文件,你可以使用 ./NewFilename.out

          【讨论】:

          • 这不是 OP 所要求的。他/她要求将多个源文件编译成一个目标文件。
          • 创建目标文件的选项是-c 而不是-o
          • 正如 Andry 所说 -c 用于目标文件。 -o 用于指定输出文件的名称。格式:-o
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多