2009-12-14 152 views
2

如果你有一个包含多个源文件的C++项目,并且你需要编译,那么编译器开始使用哪个文件?C++编译器在哪里启动?

我问的原因我在图书馆有一些#包括依赖关系问题。

编译器是:VC2003。

回答

15

它不应该是顺序依赖的。唯一相关的步骤如下:

  1. 每个编译单元包括它依赖的内容,应该单独编译。这意味着,首先,每个CPP文件包含它所依赖的所有标题;其次,每个头文件应该包含它所需要的内容,以便它可以编译,即使它是第一个被编译的。
  2. 链接步骤将所有编译的目标代码放在一起并生成最终的二进制文件。
+1

@Daniel:您还可以添加每个头还应该包含它所依赖的内容,以便即使它是模块包含的第一个头也会进行编译。 – quamrana 2009-12-14 13:29:31

+0

谢谢@quamrana,我试图将你的评论纳入我的答案。 – 2009-12-14 13:44:19

+3

我的方式是:只包含一个'#include'的源文件应该始终编译(到.o文件)而不会出错。我使用了一个“hcheck”脚本,它创建了一个.c或.cc文件,它包含在命令行中指定的文件,然后尝试编译它,并删除临时.c/.cc文件完成。 – 2009-12-14 14:15:02

3

这取决于环境。一般来说,“编译器”一次只能在单个源文件上工作;您使用更高级的工具来引导它并计算正确的构建顺序。

此类工具的示例可以是make,ant,CMake,SCons,Eclipse和Visual Studio。基本检查通常是源代码文件的修改日期,以及定义各种输出文件如何依赖于输入的内置和自定义规则。

4

无关。发布确切的问题。编译顺序是非确定性和任意的,并且不会影响项目的可编译性。

+1

事实上,甚至可能没有编译分配的编译命令。如果它发生在不同的机器上,你不能说在b.cpp之前或之后编译a.cpp。 – MSalters 2009-12-15 11:18:57

5

它不应该的问题它开始哪个文件,所有文件都被编译

1

编译器编译中不应该有所作为,正如其他人指出的顺序后,链接器解析外部引用。

从编译器的角度来看,当您编译一个带有#include的文件时,包含的文件会插入正在编译的文件中#include所在的位置,并在必要时进行递归。

0

正如其他人所指出的那样,从概念上讲,从哪个文件开始并不重要。但是,从具有最多依赖性的文件开始使用最近编辑的文件(假定编辑了多个文件)可能很有用。某些环境(如Code :: Blocks)实际上允许您对源文件进行加权,以使您能够控制编译顺序。

1

我能想到的唯一的“包含依赖”问题是递归包含。对于其修复通常与#ifdef

#ifndef INCLUDED_THEFILENAME_H 
#define INCLUDED_THEFILENAME_H 

/* content goes here * 

#endif 

守着,但你最好在你所遇到的问题的阐述。

+1

请注意,名称__THEFILENAME_H在用户编写的C++代码中是非法的。 – 2009-12-14 13:14:12

+0

uhm ...对于宏?好吧,无论如何,这个名字是无关紧要的。 – 2009-12-14 13:21:58

+1

@ hacker:即使是宏,你仍然不应该有前导下划线。对于一个宏来说,大写就足够了,当你有'_H''结尾时,它就是一个包含守卫的充分惯例。 – quamrana 2009-12-14 13:27:06

1

其他人已经表示,订单不应该有所作为。

你可能没有意识到的是编译器编译每.cpp.cc文件。它确实不是编译头文件。而且通常情况下,您只有#include头文件,而永不.cpp文件,所以顺序无关紧要。每个.cpp文件都是独立处理的。它包含许多标题,但这些标题永远不会单独编译,而且它的确不是而是通常还包含其他.cpp文件。

+0

它不编译头文件?如果一个类在头文件中包含所有的代码,并且没有cpp文件呢? – clamp 2009-12-14 15:11:37

+0

Jalf的含义(甚至在后面的段落中提到)是编译器通常不会自己编译头文件*。相反,它通过编译包含它的.cpp文件隐式编译头文件,从这个意义上讲,头文件经常被编译*多次*,每个包含它的源文件编译一次。链接器将所有重复都作为最终构建步骤进行分类。 – 2009-12-14 16:53:58

+0

是的。编译器处理“翻译单元”。一个翻译单元是一个.cpp文件的结果,并且复制/粘贴所有'#inc'并评估所有的宏。所以编译器看到的基本上是一个.cpp文件,并附有所有头文件。但它从不编译头文件* *。 – jalf 2009-12-14 17:42:14

0

make工具构建make文件中指定的依赖项的有向非循环图。这通常会说可执行文件取决于一些目标文件。目标文件依赖于源文件,每个源文件都依赖于头文件等等。

这基本上生成一个多路树。该树将以可执行文件为根,并且通常主要包含叶节点的标题(尽管如果您使用的是某种代码生成器,它也可以将该代码生成器的输入文件作为叶)。

然后,它走过那棵从叶节点到根节点的树,然后继续建筑。说“无关紧要”的答案基本上指出,它可以选择树的任何一个分支来构建第一个分支。但是,当它选择一个分支时,它会按照为该分支指定的顺序进行构建。