gpt4 book ai didi

c++ - 为嵌入式 C/C++ 项目构建系统

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:32:33 25 4
gpt4 key购买 nike

我正在寻找可以帮助我将嵌入式 C 项目组织成“模块”和“组件”的高级构建系统/工具。请注意,这两个术语非常主观,因此我的定义如下。

  • 模块是 c 和 h 文件的内聚集合,但只有一个公共(public) h 文件对其他模块可见。
  • 另一方面,组件(或层)是模块的集合(例如应用层、库层、驱动层、RTOS 层等)。

构建系统/工具应该——

  • 防止组件和模块之间的循环依赖(模块内部的循环依赖是可以的)
  • 防止访问模块的私有(private)屏障。如果其他模块试图包含模块私有(private)的头文件,则构建系统必须抛出错误。但是,私有(private)屏障内的文件必须能够包含该屏障内的其他文件。
  • 支持在主机上自动构建和执行单元测试(TDD 的快速反馈循环)
  • 支持在目标模拟器上运行单元测试
  • 支持代码静态分析
  • 支持代码生成
  • 支持代码重复检测(强制DRY原则)
  • 支持代码美化
  • 支持生成单元测试代码覆盖率指标
  • 支持生成代码质量指标
  • 独立于平台

我可以编写自己的构建工具并在上面花费大量时间。但是,这不是我的专业领域,如果有人已经创建了这样的工具,我宁愿不重新发明轮子。

最佳答案

实现这一目标的传统方法是将每个模块的源代码放入单独的目录中。每个目录都可以包含模块的所有源文件和头文件。

每个模块的公共(public)头文件可以放在一个单独的、公共(public)的头文件目录中。我可能会为每个 header 使用从公共(public)目录到相关模块目录的符号链接(symbolic link)。

编译规则简单地声明除了公共(public)目录中的头文件外,任何模块都不能包含来自其他模块的头文件。这实现了没有模块可以包含来自另一个模块的 header 的结果 - 除了公共(public) header (因此强制执行私有(private)屏障)。

自动防止循环依赖并非易事。问题是您只能通过一次查看多个源文件来确定存在循环依赖,而编译器一次只查看一个。

考虑一对模块 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 的私有(private) header ,上面写着“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...

这远非自动。

您可以对包含的文件进行分析,并要求依赖关系的无循环拓扑排序。曾经有一个程序tsort在 UNIX 系统(和配套程序 lorder )上,它们一起提供所需的服务,以便可以创建静态 ( .a ) 库,其中包含目标文件的顺序不需要重新扫描存档。 ranlib程序,最终 arld承担了管理单个库重新扫描的职责,从而使 lorder特别多余。但是tsort有更普遍的用途;它在某些系统上可用(例如 MacOS X;RHEL 5 Linux)。

因此,使用 GCC 的依赖项跟踪加上 tsort ,您应该能够检查模块之间是否存在循环。但这必须小心处理。

可能有一些 IDE 或其他工具集可以自动处理这些东西。但通常情况下,只要仔细记录需求和模块间依赖关系,程序员就可以受到足够的纪律来避免问题。

关于c++ - 为嵌入式 C/C++ 项目构建系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7606604/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com