【问题标题】:How to avoid recompiling all the files everytime?如何避免每次都重新编译所有文件?
【发布时间】:2017-12-26 10:56:26
【问题描述】:

我有大约 20 个 .cpp 文件和许多 .h 文件。当我编译时我会这样做

g++ -std=c++11 main.cpp -o main

在 main.cpp 中,我从一些前向声明开始,然后包含所有 .h 和 .cpp 文件。

因此,在每次编译时,都必须重新编译所有文件,这非常慢。我想我需要使用.so 和/或.dll 文件,以便在以后的编译中,只需要重新编译修改后的代码。我真的不知道该怎么做。你能给我一些建议吗?

【问题讨论】:

  • 使用构建系统;建议是:适合您平台的 IDE 之一、CMake、Make
  • 除了使用构建系统之外,停止包含您的 cpp 文件。将它们编译为对象文件并将对象链接在一起。这将防止对一个修改要求重新编译所有其他修改(间接因为它们被包含在内)。这并不是说SCU 技术并非没有用处。但你显然似乎不想要它。
  • 使用 SConsCMake 之类的构建系统,并确保正确配置它,以便它可以跟踪文件之间的依赖关系。
  • 并尽可能使用前向声明
  • 如果可以避免的话,我建议不要使用像 CMake 这样的构建文件生成器。我建议使用行业标准 GNU Make。与 C++ 一样,学习 GNU Make 需要一些努力,但值得付出努力。并使用 GNU Make 和 GCC 功能自动生成依赖项。

标签: c++ performance compiler-errors compilation


【解决方案1】:

您通常希望每个 translation unit 单独编译,甚至可以并行编译它们(例如,使用 make -j,见下文)。

(我猜测并希望您在 Linux 上并使用 GCC 作为 g++;如果没有,请将此答案调整为您的编译器和操作系统。)

如果您有src1.cpp src2.cpp src3.cpp(每个都包含适当的#include directives,可能带有一个公共头文件),您可以将src1.cpp 编译成object file src1.o using GCC 为:

g++ -Wall -Wextra -g src1.cpp -c -o src1.o

-Wall -Wextra 选项要求提供所有警告和一些额外的警告,而您确实希望它们(改进您的代码以不收到警告)。 -g 选项要求提供DWARF 调试信息(以便以后能够use the gdb debugger,也可以使用valgrind)。 -c 选项只需要编译步骤而不需要链接。 -o src1.o 明确输出目标文件。

同样,你会将src2.cpp 编译成src2.o

g++ -Wall -Wextra -g src2.cpp -c -o src2.o

src3.cpp

g++ -Wall -Wextra -g src3.cpp -c -o src3.o

顺便说一句,我更喜欢较短的 .cc 后缀而不是 .cpp。为了进行基准测试,请在编译器中启用 optimizations,例如通过在-g 之后添加-O2 -march=native

最后你想将link所有三个对象文件src1.osrc2.osrc3.o转换成myprogexecutable

g++ -g src1.o src2.o src3.o -o myprog

您可以添加其他选项,例如链接外部库。

请注意C++14(以及 C++11 甚至 C++17)没有真正的modules(与 Ocaml 或 Go 相比)。所以预处理器用的很多,实际上你需要包含很多代码;例如,#include <vector> 正在从我的 Linux/Debian 桌面上的标准和内部头文件中提取一万多行 C++ 代码。这解释了为什么 C++ 编译器很慢,因此我建议避免使用太小的 C++ 文件(例如,只有 100 行 C++ 行的源文件,包括 几个 头文件,这实际上会拉出数十万行 C++ 行来自各种内部标题)。我的偏好是在一行或几千行 C++ 的每个 .cc(或 .cpp)源文件中定义几个相关函数(可能还有类)。

(未来的 C++ 标准,也许是 C++20,可能会在语言中添加模块;但这可能会被推迟......)

我的建议是学习使用GNU makeninja。确实,您需要一个build automation 工具。

您当然应该学习如何在命令行上调用编译器。如果您使用g++,请阅读invoking GCCg++ 的参数顺序非常重要。

您可以使用cmakemeson 等工具生成配置文件(用于makeninja)。但我推荐比cmakemeson 更简单的东西(例如,手动编写Makefile 并使用make)。 HereMakefile 的示例,用于 make。您需要了解您的构建过程。在某些情况下,您可能会在构建过程中生成一些(简单的)C++ 文件(例如,使用GNU bisonQt moc 或您自己的脚本或程序发出一些C++ 文件)。

我想我需要使用.so

不一定。 .so 文件是共享对象,在共享库中使用。见this。如上所述,您可以(并且可能一开始想要)拥有多个目标文件。您以后可能会考虑制作自己的软件libraries,但这仅对可重用的源代码是值得的。

要链接外部库,您甚至可能想要使用pkg-config(对于那些知道它的包),它扩展为g++ 的适当构建选项。

还可以查看现有的 free software 项目以获取灵感,并研究它们的源代码(包括它们的构建过程)。您会在 Linux 发行版、githubsourceforge 和其他地方找到其中的许多。

【讨论】:

  • 这很有帮助。我发现很难获得关于汇编的那些非常介绍性的信息以及您易于阅读的帖子以及大量的链接对我有很大帮助。谢谢
【解决方案2】:

... 然后我包含所有 .h 和 .cpp 文件。

.cpp 文件(又名翻译单元)不应该被包含。您应该使用脚本或任何其他类型的构建系统,分别编译每个 .cpp 文件,并将所有生成的 .o 目标文件链接到可执行程序中。

如果它们不受头文件更改的影响,可以启用此功能以避免重新编译所有 .cpp 文件。

【讨论】:

    猜你喜欢
    • 2011-05-29
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多