是否应将 STM32 HAL 作为预编译库包含在内

Should the STM32 HAL be included as a precompiled library

我有一个用于 STM32L0 的 Keil STM32 项目。我有时(比我想要的更频繁)必须更改包含路径或全局定义。这将触发对 所有 代码的完全重新编译,因为它需要“检查”由于这些更改而改变的行为。问题是:我没有必要更改 HAL 的相关参数,因此(据我所知)不需要完全重新编译这些文件。这次重新编译占用了相当多的时间,因为我包含了我的 STM32L0 的所有 HAL 驱动程序。

一个好的做法是创建一个单独的项目,将 HAL 编译为一个库,并将其包含在我的主项目中吗? (这当然会针对每个微控制器分别完成,因为它们具有不同的 HAL)。

ps。该问题不一定仅对这个特定示例有用,但该示例为问题提供了一定范围。

pps。对于不熟悉 STM32 HAL 的人。它是程序与底层硬件接口的标准化接口。它在 .c.h 文件中提供,而不是 STD/STL.

的预编译形式

更新

这是我的示例项目中需要管理的定义示例:

STM32L072xx,USE_B_BOARD,USE_HAL_DRIVER, REGION_EU868,DEBUG,TRACE

只有 STM32L072xxDEBUG 可用于配置 HAL 库,因此当我从已定义的 TRACE 更改时,不需要重新编译 HAL未定义。因此,在我看来,HAL 可以单独管理。


编辑

看到投票结果接近:我已经阅读了 don't ask section,我的问题旨在建设性地增加构建 STM32 程序的知识,并找到有关如何更有效地使用HAL 库。我还没有在 SO 上发现任何关于将 HAL 构建为静态库的问题,因此这个问题至少可以说是独一无二的。这个问题也是为了邀请一个丰富的答案,详细说明 pros/cons 将 HAL 构建为一个单独的静态库。

这里的答案是..这取决于。正如评论中已经指出的那样,这取决于您计划如何管理您的项目。以公正的方式回答您的问题:

选项 #1 - 在您的项目中直接拥有 HAL 源意味着每次在其(和底层)headers 发生任何变化时重建 HAL,您已经注意到了这一点。它的缺点是构建时间更长。好处 - 您确信所建即所得。

选项 #2 - 将 HAL 作为预编译静态库。好处 - 更短的构建时间,坏处 - 您无法再绝对确定您包含的 HAL 库是否确实按您希望的方式工作。特别是,您需要以某种方式确保所有 #define 与构建库时完全相同。这包括 project-wide 定义(DEBUGSTM32L072xx 等),以及 HAL 配置文件中的任何内容 (stm32l0xx_hal_conf.h)。

看看你是一个 Keil 用户 - 也许这只是启用 multi-core 构建的问题?请参阅此 link:http://www.keil.com/support/man/docs/armcc/armcc_chr1359124201769.htm。 HAL 库不是很大,因此在重建其源文件时应该考虑构建时间。

如果我要表达我的意见和经验 - 就我个人而言,我不会这样做,因为它可能会导致可靠性降低或副作用,这些副作用将很难诊断,并且随着您添加更多来源只会变得更糟文件和更多这样的库。更不用说增加更多人参与该项目并向他们解释他们如何 "need to remember to rebuild X library when they change given set of header files or project-wide definitions".

事实上,对于我工作的代码库,我们 运行 陷入了同样的困境 - 它总共跨越 10k 源和 header 文件,其中一些是 configuration-specific,其中许多是共享的。它是高度模块化的,这使我们能够通过配置现有代码(主要是通过一组 header 文件)来快速创建新的东西(包括硬件和 software-wise)。然而,由于此配置是通过 headers 完成的,因此对它们进行更改通常意味着重建项目的很大一部分。尽管有时构建时间很烦人,但出于上述原因,我们选择不制作静态库。就我个人而言,最好优先考虑可靠性,如 "I know what I build".

如果我要提供任何有助于在项目变大时避免重建的一般提示:

  • 避免全局 header 保存所有配置。通常很容易将所有配置都放在一个地方,在这个文件中为每个软件模块创建漂亮的注释和部分。以这种方式管理起来更容易(直到这个文件变得太大),但是因为这个文件太常见了,这意味着对它所做的任何更改都会导致完全重建。将此类文件拆分为与项目中每个模块相对应的 headers。

  • 仅在您需要的地方包含 header 文件。我有时会看到一种方法,其中创建了 header 个文件,但仅 "bundle" 个其他 header 个文件,并且稍后包含此类 header 个文件。在这种情况下,对 "smaller" header 中的任何一个进行更改都会产生必须重新编译所有源文件(包括较大文件)的效果。如果这样的文件不存在,那么只有明确包含那个小 header 的源代码才需要重新编译。显然这里有一条线 - 也包括 "low level" headers 可能也不是最好的主意,例如它们可能不会作为内部库文件包含在内,这些文件可能随时更改。

  • 源文件中的 header 优先于 header 文件。如果你有一对自己的 *.c (*.cpp) 和 *.h 文件 - 假设 temp_logger.c/.h 并且你需要 ADC - 那么除非你真的需要一些 ADC 定义header(您可能不会),然后将 ADC header 文件包含在您的 temp_logger.c 文件中。稍后,所有使用 temp_logger 函数的文件都不必是 re-compiled,以防再次重建 HAL。

我的意见是,把HAL做成库。更快构建时间的好处超过了库过时的风险。在项目早期的某个时间点之后,我很少更改会影响 HAL 的内容。但是更快的构建时间带来了很多回报。

我创建了一个 multi-project 工作区,其中一个项目用于 HAL 库,另一个项目用于引导加载程序,第三个项目用于应用程序。当我开发时,我只重建应用程序项目。当我进行发布构建时,我 select Project->Batch Build 并重建所有三个项目。这样,发布版本始终使用所有最新代码和构建设置。

此外,在“目标选项”对话框的“输出”选项卡上,取消选中“浏览信息”将大大减少构建时间。