简体   繁体   English

源代码构建混乱(预处理和链接)

[英]Source code build confusion (preprocessing and linking)

Why is it that during the preprocessing step, the #includes in a main file are only replaced with the contents of the relevant header files (and not the function definitions as well (.cpp files))? 为什么在预处理步骤中,仅将主文件中的#includes替换为相关头文件的内容(而不是函数定义(.cpp文件))?

I would think that during this step it should first go into the header files and replace the #includes there with the contents of their associated .cpp files and then and only then go back to replace the #includes in the main file with everything, thus negating the need for any linking (one giant file with everything). 我认为在此步骤中,它应该首先进入头文件,并用与其相关的.cpp文件的内容替换其中的#includes,然后再返回,然后用所有内容替换主文件中的#includes,因此无需进行任何链接(一个巨型文件包含所有内容)。 Why does it not happen this way? 为什么不这样发生?

Why is it that during the preprocessing step, the #includes in a main file are only replaced with the contents of the relevant header files (and not the function definitions as well (.cpp files))? 为什么在预处理步骤中,仅将主文件中的#includes替换为相关头文件的内容(而不是函数定义(.cpp文件))?

Simply put, the header files are the only files you've told the preprocessor about. 简而言之,标头文件是您告诉预处理器的唯一文件。 It can't assume the names of the source files, because there could be many source files for any given header. 它不能假定源文件的名称,因为任何给定的标头都可能有许多源文件。 You may be thinking "Hey, why don't I just include the source files?" 您可能会想:“嘿,为什么我不只包含源文件?” and I'm here to tell you No! 我在这里告诉你不! Bad! 坏! Besides, who's to say that you have access to the source files in the first place? 此外,谁能说您首先有权访问源文件?

The only way for the compiler to know about and compile all of your source files is for you to pass the compiler each source file, have it compile them into objects, and link together those objects into a library or executable. 编译器了解和编译所有源文件的唯一方法是让编译器将每个源文件传递给它,将其编译为对象,然后将这些对象链接到库或可执行文件中。

There's a great difference between compiling and linking : compiling and linking之间有很大的区别:

Pre-processor, Pre-compile-time and Compile-time: 预处理器,预编译时间和编译时间:

The pre-processor check for # symbol and replaces it with the relevant content eg: 预处理程序检查#符号并将其替换为相关内容,例如:

#include <iostream> // the content will be replaced here and this line will be removed

So the content of iostream will be added above. 因此,iostream的内容将添加到上面。

eg2: EG2:

#define PI 3.14 // wherever PI is used in your source file the macro will be expanded replacing each PI with the constant value 3.14 

The compiler only checks for syntax errors, functions prototypes ... and doesn't care about the body of functions, resulting in an .obj file`. 编译器仅检查syntax errors,函数原型... and doesn't care about the body of functions, resulting in an .obj文件。

Link-time: 链路时间:

The linker links these obj files with the relevant libraries, and in this very time functions called must have a definition; 链接器将这些obj files与相关的库链接起来,这时functions called必须具有定义; without a definition will issue in a link-time error. 没有定义将在链接时错误中发出。

Why does it not happen this way? 为什么不这样发生?

History and the expectations of experienced programmers, and their experience with bigger programs (see last statements, below) 经验丰富的程序员的历史和期望,以及他们使用大型程序的经验(请参阅下面的最后声明)


I would think that during this step it should first go into the header files and replace the #includes there with the contents of their associated .cpp files ... 我认为在此步骤中,它应该首先进入头文件,并用其相关的.cpp文件的内容替换其中的#includes ...

If you accept a job coding in C++, your company will provide to you a coding standard detailing guide lines or rules which you will want to follow, or face defending your choices when you deviate from them. 如果您接受C ++的工作编码,则您的公司将为您提供编码标准,详细说明您要遵循的准则或规则,或者在您偏离选择时面临辩护。

You might take some time now to look at available coding standards. 您现在可能需要花费一些时间来查看可用的编码标准。 For example, try studying the Google C++ Style Guide (I don't particularly like or dislike this one, its just easy to remember). 例如,尝试研究Google C ++样式指南(我并不特别喜欢或不喜欢这一本书,它很容易记住)。 A simple google search can also find several coding standards. 一个简单的谷歌搜索还可以找到几种编码标准。 Adding a 'why conform to coding standard?' 添加“为什么符合编码标准?” to your search might provide some info. 您的搜索可能会提供一些信息。


negating the need for any linking (one giant file with everything). 无需进行任何链接(一个巨型文件包含所有内容)。

Note: this approach can not eliminate linking with compiler tools or 3rd party provided libraries. 注意:这种方法无法消除与编译器工具或第三方提供的库的链接。 I often use -lrt, and -pthread, and some times -lncurses, -lgmp, -lgmpxx, etc. 我经常使用-lrt和-pthread,有时还使用-inccurses,-lgmp,-lgmpxx等。

For now, as an experiment, you can manually achieve the giant file approach (which I often do for my smaller trial and development of private tools). 现在,作为一个实验,您可以手动实现巨型文件方法(我经常在较小的试用和私有工具开发中使用该方法)。

Consider: 考虑:

if main.cc has: 如果main.cc具有:

#include "./Foo.hh" // << note .hh file

int main(int argc, char* argv[])
{
   Foo  foo(argc, argv);

   foo.show();   
...

and Foo.cc has Foo.cc有

#include "./Foo.hh"  // << note .hh file

// Foo implementation

This is the common pattern (no, not the pattern book pattern), and will require you link together Foo.o and main, which is trivial enough for small builds, but still something more to do. 这是常见的模式(不,不是模式书模式),将需要您将Foo.o和main链接在一起,这对于小型构建来说是微不足道的,但还有更多事情要做。

The 'small'-ness allows you to use #include to create your 'one giant file with everything' easily: “小”状态使您可以轻松地使用#include创建“包含所有内容的一个巨型文件”:

change main to 将main更改为

#include "./Foo.cc"   // << note .cc also pulls in  .hh
                      // (prepare for blow back on this idea)    

int main(int argc, char* argv[])
{
   Foo  foo(argc, argv);

   foo.show();   
...

The compiler sees all the code in one compilation unit. 编译器可以在一个编译单元中看到所有代码。 No linking of local .o's needed (but still library linking). 无需链接本地.o(但仍链接库)。


Note, I do not recommend this. 注意,我不建议这样做。 Why? 为什么?

Probably the primary reason is that many of my tools have 100's of objects (ie. 100's of .cc files). 可能的主要原因是我的许多工具都有100个对象(即100个.cc文件)。 That single 'giant' file can be quite giant. 单个“巨型”文件可能非常庞大。

For most development churn (ie early bug fixes), ONLY one or TWO of the .cc files gets changes. 对于大多数开发变更(即早期的错误修复),只有.cc文件中的一个或两个会更改。 Recompiling all of the source code can be a big waste of your time, and your compiler's time. 重新编译所有源代码可能会浪费大量时间,并浪费编译器的时间。

The alternative is what the experience developers have already learned: 另一种选择是开发人员已经学习的经验:

A) Compiling the much smaller number of .cc's that have changed (perhaps one or two?), A)编译已更改的.cc数量少得多(也许一两个?),

B) then linking them with the 100's of other .o's that have not changed is much quicker build. B)然后将它们与未更改的其他.o的100链接起来,可以更快地构建。

A major key to your productivity is to minimize your edit-compile-debug duration. 提高工作效率的主要关键是最大程度地减少编辑-编译-调试时间。 A and B and a good editor are important to this development iteration. A和B以及出色的编辑器对于此开发迭代很重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM