我们正在重构我们的代码库,并试图限制不同组件之间的直接依赖关系。我们的源代码树有几个顶级目录:src/a、src/b 和 src/c。
我们要强制执行一组限制:
- a 中的文件不能依赖于 b 或 c 中的文件
- b 中的文件可以依赖文件 a 但不能依赖 c
- c 中的文件可以直接依赖于 b 中的文件,但不能依赖 a
执行第一个很简单。我有一个这样的隐含规则:
build/a/%.o : src/a/%.cpp
$(CXX) -I src/a $(OTHER_FLAGS) -o $@ $<
如果 a 下的文件尝试包含来自 b 或 c 的头文件,则构建失败,因为找不到头文件。
第二条规则有一个类似的规则,将 src/a 和 src/b 指定为包含目录。问题出现在建筑 c 上。以下是允许的。
src/c/C.cpp
#include "b.h"
void C() { ... }
src/b/b.h
#include "a.h"
class B { ... };
src/a/a.h
class A { ... };
这里,来自 c 的文件包括来自 b 的文件(允许),而后者又包括来自 a 的文件(也允许)。我们要防止这样的代码:
src/c/C_bad.cpp
// Direct inclusion of a
#include "a.h"
src/c/c_bad.h
// Direct inclusion of a
#include "a.h"
对于允许的情况进行编译,用于在 src/c 中构建文件的编译命令必须包含 -Isrc/a,但这允许第二种情况也可以编译。
我怀疑我的问题的答案是编写一个脚本,该脚本查看编译器生成的依赖项,找到潜在的非法依赖项,然后查看源文件以确定这是否是直接依赖项。有没有一种合理的方法可以结合编译器和/或 makefile 结构来做到这一点?
如果重要的话,我们正在使用 GNU Make 3.81 和 g++ 4.5.3,但如果可能的话,希望是可移植的。
更新
我们正在寻找一种需要努力违反规则的东西,而不是一种需要努力遵守规则的东西。(过去的经验表明后者不太可能奏效。)虽然在另一个答案中有一些好主意,但我接受说要编写脚本的那个,因为这是最需要努力工作的那个大约。
感谢大家的回答。