我正在寻找一个高层次的构建系统/工具,可以帮助组织我的嵌入式C项目为“模块”和“组件”。请注意,这两个术语非常主观,因此我的定义如下所示。
构建系统/工具应该-
)。
我可以写我自己的构建工具,并花很多时间在它上。然而,这不是我的专业领域,如果有人已经发明了这样一个工具,我宁愿不重新发明轮子。
发布于 2011-09-30 07:08:33
实现这一目标的传统方法是将每个模块的源代码放在一个单独的目录中。每个目录都可以包含模块的所有源文件和头文件。
每个模块的公共头可以放置在一个单独的、通用的标题目录中。我可能会为每个标头使用从公共目录到相关模块目录的符号链接。
编译规则简单地声明,除公共目录中的标头外,任何模块都不能包含来自其他模块的标头。这样做的结果是,没有任何模块可以包含来自另一个模块的标头--除了公共标头(因此强制执行私有屏障)。
自动防止循环依赖关系并不容易。问题是,您只能通过一次查看多个源文件来确定是否存在循环依赖关系,而编译器一次只查看一个源文件。
考虑一对模块,ModuleA和ModuleB,以及一个使用这两个模块的程序Program1。
base/include
ModuleA.h
ModuleB.h
base/ModuleA
ModuleA.h
ModuleA1.c
ModuleA2.c
base/ModuleB
ModuleB.h
ModuleB1.c
ModuleB2.c
base/Program1
Program1.c在编译Program1.c时,如果它使用了两个模块的服务,则包含ModuleA.h和ModuleB.h是完全合法的。因此,如果ModuleB.h包含在同一个翻译单元( TU )中,那么ModuleA.h不能抱怨,如果ModuleA.h包含在同一个TU中,ModuleB.h也不能抱怨。
让我们假设ModuleA使用ModuleB的设施是合法的。因此,在编译ModuleA1.c或ModuleA2.c时,同时包含ModuleA.h和ModuleB.h是没有问题的。
但是,为了防止循环依赖,您必须能够禁止ModuleB1.c和ModuleB2.c中的代码使用ModuleA.h。
据我所见,做这件事的唯一方法是一些技术,它需要一个私有的ModuleB头,上面写着"ModuleA已经包含了“,尽管它还没有包含,这是在包含ModuleA.h之前包含的。
ModuleA.h的骨架将是标准格式( ModuleB.h将类似):
#ifndef MODULEA_H_INCLUDED
#define MODULEA_H_INCLUDED
...contents of ModuleA.h...
#endif现在,如果ModuleB1.c中的代码包含:
#define MODULEA_H_INCLUDED
#include "ModuleB.h"
...if ModuleA.h is also included, it will declare nothing...
...so anything that depends on its contents will fail to compile...这远不是自动的。
您可以对包含的文件进行分析,并要求存在无循环的依赖关系拓扑类型。以前在UNIX系统上有一个程序tsort (以及一个配套的程序,lorder),它一起提供所需的服务,这样就可以创建一个静态(.a)库,按照不需要重新扫描归档的顺序包含对象文件。ranlib程序,以及最终的ar和ld承担了管理单个库的重新扫描的职责,从而使lorder变得特别多余。但是tsort有更广泛的用途;它可以在某些系统上使用(例如,RHEL;RHEL5Linux)。
因此,使用GCC和tsort的依赖项跟踪,您应该能够检查模块之间是否存在循环。但这得小心处理。
可能有一些IDE或其他工具集可以自动处理这些内容。但通常情况下,程序员可以受到足够的约束,以避免出现问题--只要需求和模块间的依赖关系被仔细记录下来。
发布于 2011-09-30 07:39:37
对于一般的解决方案,我建议采用Jonathan的解决方案。但是,如果您绝对需要自动测试您的模块是否是独立的和独立的,那么您可以尝试一下Debian的构建系统。
将每个模块打包到一个Debian包中(当它已经是autoconf‘s时,这个包会很快完成),正确地声明build -依赖并在pbuilder环境中构建包。这确保只有每个模块的公共头是可用的(因为只有那些在.deb包中,这些包是由pbuilder安装来构建其他包的),并且有很好的工具可以查看Debian包树并确保它们是无周期的。
不过,这可能是过头了。仅仅说明它的完整性和情况,您肯定需要一个自动化的解决方案。
https://stackoverflow.com/questions/7606604
复制相似问题