我正在为嵌入式系统(dsPIC33平台)编写C代码,我正在考虑建立一个可重用的代码库,以便在多个项目中使用。
将图书馆绑定到每个项目的最佳做法是什么?
显然,库将具有一些特定于硬件(因此特定于项目)的依赖关系,因此可以合理地假设它将与每个项目一起编译(而不是以二进制形式链接)。
到目前为止,我提出的是保持库的中心位置,但需要一个包含函数定义,宏等的项目特定的libraryConfig.h。这要求库在其自己的代码中包含头,这意味着项目源目录需要在include路径中(而不仅仅是库源目录)。这种混淆了#include ""
和#include <>
之间的区别,不是吗?
这是正常的吗?
答案 0 :(得分:8)
一个非常好的问题,答案并不简单。需要考虑的几件事情。以下是我迄今为止的一些观点。
公共代码与项目本地副本
一个重要的决定是,是否使用从中央位置(贵公司的“重用库”)自动更新的“通用”库代码,或者是否保留项目本地副本。
这在this SO question中有详细讨论。
中央图书馆的好处是,一次完成的工作可以使许多项目受益。项目本地副本的难点在于,任何错误修复和改进都不会返回到中央库,并且中央库中的任何错误修复都可能无法进入您的项目。
但是使用中央图书馆的一个潜在困难是,如果他们的特定人员以不受控制的方式修改它以适应他们的项目,并且无意中打破了其他项目。我亲眼看到,在“常见”代码中充满了#ifdef并且经常打破其他项目。
为了从公共代码(即中央重用库)中获得良好的价值:
图书馆:
个别项目:
如果公司没有这样的流程,那么项目应该只制作一段代码的本地副本(比如从以前的项目中复制),然后从那时起承担全部的项目本地责任。 。在这种情况下,你仍然可以从重用中获得一些好处,因为你不是从头开始重写它。
项目特定配置
如果代码需要特定于项目的配置,理想情况下应该尽可能保持代码的一小部分 - 而不是分散在一堆源文件中。理想情况下,单个头文件。但很可能是一个.C文件(比方说,如果你需要定义一些查找表)。该库应该提供一个模板,其中有很好的评论选项。
有关如何执行此操作的良好示例,请参阅µC/OS-II RTOS中Jean Labrosse的book(Micrium)。
答案 1 :(得分:1)
它并没有搞砸这种区别,无论如何几乎完全是平台定义的。唯一定义的行为是,如果使用""
的包含无法找到该文件,则会再次搜索,就像您说<>
一样。
我认为你做的是正确的。根据我的经验,处理特定于平台的标题的正常方法是,给它一个名称,尽可能自信不会与其他任何内容发生冲突,并将#include与""
一起使用。然后你告诉平台搬运工做任何必要的编译器事情,以确保找到它。通常,这意味着指定一些编译器参数,如-I,用于他想保留文件的位置。是的,他的项目目录之一。但如果一切都失败了,他总是可以将他的文件复制到他的编译器所在的某个地方。他甚至可以将它复制到你的库源的本地副本中,如果他的编译器对整个事情的处理过程非常困难。
另一种方法是在库中选择一个文件selectplatform.h,如下所示:
// obviously WIN32 isn't an embedded platform, and GCC is too broad
// to be supported by a single header file. Replace with whatever platforms
// it is you do support out of the box.
#if _WIN32
#include "platforms/msvc32.h"
#elif __GNUC__
#include "platforms/gcc.h"
#else
#error "You must add a new clause to selectplatform.h for your platform"
#endif
这避免了编译器配置的需要,但是每个新平台端口都必须修改文件。如果你是唯一一个进行任何移植的人,那肯定不是问题。否则,一个文件由第三方分叉。然后他们可能会在您的库中向platforms/
添加一个新文件,或者他们可能会将其文件放在其他位置。所以对于第三方来说,只有可能不是问题。如果他们和你们都想要,他们可以将他们的变化(可能包括他们的平台标题)提供回上游。
答案 2 :(得分:1)
没有。
通常,您使用编译器中的命令标志定义lib的包含目录的路径(通常是-I标志)。
比如说,如果您使用的是GCC编译器,那么您的库的头文件位于
中/usr/local/include/mylibheaders
然后你必须使用以下选项调用编译器:
-I/usr/local/include/mylibheader/mycurrentplatform
其中 mycurrentplatform 目录对于每个项目都是不同的,并且包含特定于项目的 libraryConfig.h
因此,您可以在每个项目中使用#include<libraryConfig.h>
。
答案 3 :(得分:1)
这实际上是一个配置管理问题,而不是C问题。根据我的经验,使用一个好的版本控制程序是最有帮助的。找到一个允许您通过从几个不同位置提取源代码来定义“项目”的方法。意识到您的版本控制程序对“项目”的定义将成为构建项目的基本要素。
能够对项目分支的库代码进行更改并将其多次检入版本控制系统,而不必检查主库位置的更改,直到更改得到证实,这一点也很重要。可能会影响许多不同的项目。
您的库模块也可能最终得到一个文件,该文件为每个特定项目定义库选项。我采用的一种做法是命名这些接口文件_PAL.h,其中_PAL表示项目抽象层文件。