为什么要在C和C++项目中创建include /目录?

28 c c++ include

当我在我个人的C和C++项目工作,我通常把file.hfile.cpp在同一目录下,然后file.cpp可以参考file.h#include "file.h"指导.

但是,通常会找到库和其他类型的项目(如linux内核和freeRTOS),其中所有.h文件都放在include/目录中,而.cpp文件保留在另一个目录中.在那些项目中,.h文件也包括在内,#include "file.h"而不是#include "include/file.h"我希望的.

我对这一切有一些疑问:

  1. 这个文件结构组织有哪些优点?
  2. 为什么.h文件内include/包含#include "file.h"代替#include "include/file.h"?我知道真正的技巧是在一些Makefile中,但是这样做是否真的更好而不是明确(在代码中)我们想要包含的文件实际上在include/目录中?

Nic*_*las 32

这样做的主要原因是编译库需要标题才能被最终用户使用.按照惯例,include目录的内容是公开消费的标题.源目录可能具有供内部使用的标头,但这些标头并不意味着与已编译的库一起分发.

因此,在使用库时,您将链接到二进制文件并将库的include目录添加到构建系统的标头路径中.同样,如果将已编译的库安装到集中位置,则可以告诉哪些文件需要复制到中心位置(已编译的二进制文件和include目录)以及哪些文件不需要(源目录等).


jwd*_*hue 8

过去,<header>样式包括隐式路径类型,即在includes环境变量路径或构建宏上找到,"header"样式包括显式形式,as-in,完全相对于where-ever源文件包含它.虽然一些构建工具链仍然允许这种区别,但它们通常默认为有效地使其无效的配置.

你的问题很有意思,因为它提出了哪个更好,更隐蔽或更明确的问题?隐式形式肯定更容易,因为:

  1. 目录层次结构中相关标头的便捷分组.
  2. 您只需要在includes路径中包含一些目录,而无需了解与文件的确切位置有关的每个细节.您可以在不更改代码的情况下更改库及其相关标头的版本.
  3. .
  4. 灵活!您的构建环境不必与我的匹配,但我们通常可以获得几乎完全相同的结果.

另一方面明确有:

  1. 可重复的构建.includes宏/环境变量中路径的重新排序不会更改在构建期间找到的结果头文件.
  2. 便携式构建.只需从构建的根目录中打包所有内容并将其发送给另一个开发人员.
  3. 接近信息.您确切知道标头的位置#include "\X\Y\Z".在隐式表单中,您可能必须沿着多个路径进行搜索,甚至可能找到同一文件的多个版本,您如何知道在构建中使用哪个?

几十年来,构建者一直在争论这两种方法,但这两种方法的混合形式,大部分是胜利,因为纯粹基于显式形式维护构建所需的努力,以及人们可能熟悉自己的代码的明显困难纯粹的含蓄性.我们通常都明白,我们的各种工具链将某些公共库和标题放在特定的位置,这样它们可以在用户和项目之间共享,因此我们希望在一个地方找到标准的C/C++标题,但我们最初并不是这样.了解任何任意项目的具体结构,缺乏本地记录良好的约定,因此我们希望这些项目中的代码对于它们所特有的非标准位是明确的,并且对于标准位是隐含的.

最好始终<header>对所有标准标题和其他非项目特定的库使用include形式,并将"header"表单用于其他所有内容.您的项目中是否包含本地包含的包含目录?这在某种程度上取决于这些标题是作为接口提供给您的库还是仅由您的代码使用,也取决于您的首选项.你的项目有多大和多么复杂?如果您混合使用内部和外部接口或许多不同的组件,您可能希望将事物分组到不同的目录中.

请记住,完成的产品解压缩到的目录结构,不需要看起来像您在其中开发和构建该产品的目录结构.如果您只有几个.c/.cpp文件和标题,则可以放置它们都在一个目录中,但最终,你将要处理一些非常重要的事情,并且必须考虑构建环境选择的后果,并希望将其记录下来供其他人理解.

  • 我认为这是一个非常全面的答案。我要补充的是,我们经常混合使用 - 我们的库中需要外部链接(它们实际提供的内容)的所有标头都分组在标头目录中 - 因此它们可以作为一个块轻松移动 - 这通常是“的要求”安装”。仅内部需要的标头会显式链接到源并与源一起保存,以保持源的可移植性并对信息进行分组。 (2认同)