头文件C ++模块之间的依赖关系

时间:2009-07-21 16:50:39

标签: c++ dependencies development-environment

在我的位置,我们有一个很大的C ++代码库,我认为头文件的使用方式存在问题。

有很多Visual Studio项目,但问题出在概念上,与VS无关。每个项目都是一个模块,执行特定的功能。每个项目/模块都编译为库或二进制文件。每个项目都有一个包含所有源文件的目录 - * .cpp和* .h。一些头文件是模块的API(我的意思是声明创建的库的API的头文件的子集),有些是内部的。

现在问题 - 当模块A需要使用模块B时,A会添加B的源目录以包含搜索路径。因此,A在编译时可以看到所有B的模块内部头文件。

作为副作用,开发人员不必强调每个模块的确切API,我认为这是一个坏习惯。

我考虑一下如何选择它应该是什么。我想过创造 每个项目只有一个包含接口头文件的专用目录。希望使用该模块的客户端模块仅允许包含接口目录。

这种方法可以吗?你的位置如何解决问题?

UPD 在我以前的地方,开发是在Linux上使用g ++ / gmake完成的,我们确实用于将API头文件安装到公共目录中,这是一些建议的答案。现在我们使用cmake生成项目文件的Windows(Visual Studio)/ Linux(g ++)项目。我如何强制在Visual Studio中预先安装API头文件?

由于 梅德

6 个答案:

答案 0 :(得分:3)

这听起来像是在正确的轨道上。许多第三方图书馆都做同样的事情。例如:

3rdParty / myLib / src / - 包含编译库所需的头文件和源文件
3rdParty / myLib / include / myLib / - 包含外部应用程序包含

所需的标头

有些人/项目只是将标题包含在/ 3rdParty / myLib / include中的外部应用程序中,但添加额外的myLib目录可以帮助避免名称冲突。

假设您使用的结构:3rdParty / myLib / include / myLib /


In Makefile of external app:
---------------
INCLUDE =-I$(3RD_PARTY_PATH)/myLib/include
INCLUDE+=-I$(3RD_PARTY_PATH)/myLib2/include
...
...

In Source/Headers of the external app
#include "myLib/base.h"
#include "myLib/object.h"

#include "myLib2/base.h"

答案 1 :(得分:2)

将接口标头放在项目的根目录中,并为非API标头创建一个子文件夹(称之为'internal'或'helper'或类似的东西),这不是更直观吗?

答案 2 :(得分:2)

在我工作的地方,我们在构建时创建了一个交付文件夹结构。定义库的头文件将复制到include文件夹。我们使用自定义构建脚本,让开发人员表示应该导出哪些头文件。

然后我们的构建以subst驱动为根,这允许我们使用包含目录的绝对路径。

我们还有一个基于网络的参考版本,允许我们使用映射驱动器进行include和lib引用。

更新:我们的参考版本是我们的构建服务器上的网络共享。我们使用一个引用构建脚本来设置构建环境并在构建服务器上映射(使用net use)命名共享(即\ BLD_SRV \ REFERENCE_BUILD_SHARE)。然后在每周构建(或手动)期间,我们设置共享(使用net share)指向新构建。

我们的项目然后是include和lib引用的绝对路径列表。

例如:

subst'ed local build drive j:\
mapped drive to reference build: p:\
path to headers: root:\build\headers
path to libs: root:\build\release\lib
include path in project settings j:\build\headers; p:\build\headers
lib path in project settings     j:\build\release\lib;p:\build\release\lib

这将首先进行本地更改,然后如果您尚未进行任何本地更改(或者至少您尚未构建它们),它将使用您最后在构建服务器上构建的头文件和库。

答案 3 :(得分:0)

我已经看到这样的问题通过在模块B中具有一组头文件来解决,这些头文件作为构建过程的一部分被复制到版本目录中。模块A然后只看到那些标题,并且永远不能访问B的内部。通常我只在公开发布的大型项目中看到过这种情况。

对于内部项目,它不会发生。通常发生的事情是,当它们很小时,它并不重要。当他们长大后,把它分开是很混乱的,没有人愿意这样做。

答案 4 :(得分:0)

通常我只看到一个包含所有接口标头的include目录。它当然可以很容易地包含标题。人们在为链接器指定模块时仍然需要考虑他们依赖哪些模块。

那就是说,我有点像你的方法更好。您甚至可以避免将这些目录添加到包含路径,以便人们可以通过顶部的#includes中的相对路径来判断源文件所依赖的模块。

根据项目的布局方式,从头文件中包含它们时可能会出现问题,因为标题的相对路径来自.cpp文件,而不是来自.h文件,因此.h文件不一定知道.cpp文件的位置。

但是,如果您的项目具有平面层次结构,则这将起作用。说你有

base\foo\foo.cpp
base\bar\bar.cpp
base\baz\baz.cpp
base\baz\inc\baz.h

现在任何头文件都可以包含
#include "..\baz\inc\baz.h
并且它将起作用,因为所有cpp文件都比基础深一层。

答案 5 :(得分:0)

在我工作的一个小组中,所有公共内容都保存在特定于模块的文件夹中,而私有内容(私有标头,cpp文件等)保存在_imp文件夹中:

base\foo\foo.h
base\foo\_imp\foo_private.h
base\foo\_imp\foo.cpp

这样你就可以在你的项目文件夹结构中找到并获得你想要的标题。您可以为包含_imp的#include指令进行grep,并仔细查看它们。您还可以获取整个文件夹,将其复制到某个位置,并删除所有_imp子文件夹,因为您知道已准备好发布API。 在项目标题中,通常包含在

#include "foo/foo.h"

但是,如果项目必须使用某些API,则API标头将由构建系统在该平台上的任何位置复制/安装,然后安装为系统标头:

#include <foo/foo.h>