Blog:
韬睿 CE 库发展历程

2015年3月25日星期三
Library

Library 从旧版本软件编译和维护中学到的经验

如果你是使用我们 Toradex Windows CE 库的用户,你或许已经发现有两个不同版本的库可以下载。我想要告诉你这变化背后的故事并鼓励你使用新的 API。接下来让我们从头说起。

退回到2005年,我的几个充满激情的朋友决定成立自己的技术公司,我有幸成为了其中的一员。一年之后,我们一致认为我们应该有自己的产品,所以我们开始了第一块 Arm 计算机模块开发 - Colibri PXA270。硬件设计很快就完成了,那个时候我们已经预计到软件部分会在接下来的数月,甚至数年中够我们忙的。不仅 WinCE 操作系统需要调整,我们还想要开发一整套工具,能够在产品研发和最终产品量产阶段帮助我们的用户。针对操作系统和应用程序开发软件有着极大的不同。但也有不少的代码能够在两种环境中被共同使用,例如从简单的内存分配函数到 LED 控制或者 I2C 通信以及其他接口。

为了使我们的日子好过些,我们编写了库文件既可以用于操作系统也可以用于应用程序开发。当时由于时间紧迫,我们采用了相对容易的措施,针对最适合 PXA270 的方法开发了库代码,并且效果还很好。接下来就是把库文件发布给我们的用户。Colibri PXA270 在当时非常成功,所以我们基于 PXA 家族最新的芯片设计了新的 Colibri 模块。这些模块的功能基本相似,我们使用大量的 if else 语句处理不同 CPU,将 xyz_Init 变成 xyz_InitEx 函数来支持之前没有想到的新功能,而从扩展了软件库的支持。当然,这个方法也很奏效。

与此同时,模块的销售情况也非常好,这激励我们使用新的 CPU 扩展模块系列。这时,CPU 构架之间的差异就非常大了,需要我们更多的修改来适配所有模块。那时的理念仍旧是继续尽可能多地使用公共代码,这种方法针对应用程序,再次表现得很好。然而,对于设备驱动,却不是那么理想,因为我们需要解决针对不同 CPU 的代码引起的链接问题。正如之前一样,我们采用了务实的方法,插入了大量的 #ifdefs 语句,在编译期间排除不需要使用的代码。

SPI 支持引起了另外一个问题:一方面我们想要使用基于 DMA 的支持,另一方面,在有些场合下需要使用基于 PIO 的支持。如何解决呢?生成两个使用相同调用接口函数的库文件,用户就可以在编译的时候选择想要的支持方式。结果证明,这种方法被想得太过于简单,很快在同样的应用中就需要同时使用 PIO 和 DMA 模式,于是这种方法就失效了。我们必须整合两种支持和另一组函数来重新定向到DMA 或者 PIO 支持。

更多的问题在我们修复新 CPU 问题的时候出现,突然我们得知有些函数对老的 CPU 失效了。代码中的依赖关系,使得测试针对一种 CPU 的修改是否会造成对其他 CPU 不可知的影响,便变得异常困难。我们也可以很容易地预测到,当我们对更多 CPU 构架扩展库文件支持时,会遇到更多意想不到的故障。这对软件质量来说完全没有出路。

走出这困境的唯一方法就是回到过去并重新开始。我们必须定义新的库文件架构,以及新的 API,使得其足够灵活,从而可以满足现有硬件和现在我们还不知道的未来 CPU 构架的需求。做这个决定十分的困难,因为我们的用户依赖于我们向后兼容的承诺。然而,如果继续使用老的库文件架构,为了支持新 CPU 的重要专有功能,无论如何都会导致不兼容。

现在,我们仍在努力完善新库文件架构的支持。难道我们不应该从一开始就采用这个方法吗?是的,如果在理想的情况下。但是在现实中,我们无法遇见我们产品的演进。所以,在采用了当时认为正确的方法。

难道我们不应该在更早的时候就采用这个方法吗?或许是的。这本来可以节省我们大量的时间来定位和解决一些问题,如果采用了合适的软件构架,这些问题也可以更早得被发现。

敬请期待我下一篇博文,关于韬睿库文件代码背后的理念。

作者: Andy Kiser, Senior Development Engineer, Toradex AG

评论

Please login to leave a comment!
Have a Question?