针对Windows,Linux等的跨平台API开发

我已经被赋予了为我们的硬件传感器构build一个跨平台API的任务,以使它们更容易被第三方开发人员使用。 目前,我们有很多传统的应用程序,硬件层是在GUI内部和周围构build的。

我想要做的是去除硬件层,并实现一个可靠,但devise良好的跨平台API,然后可以提供给第三方开发人员,帮助我们的硬件集成到他们的平台。

我意识到,在堆栈溢出术语中,这可能是一个红旗问题,但我会问它。

我们现有的代码库是多语言的(C#,C ++ / Qt,Delphi等),但只能在Windows上运行。 我想进一步改进,至less包括Linux,也许还有一些Mac / OSX的支持。

从更大的angular度来看,我对前面的任务的理解是在API的基础上创build一个“黑盒子”。 像connect这样的函数会带入一些参数,并传递出某种types的设备handle ,底层的连接代码对用户是隐藏的。 然后可以将该句柄传递到各种controlfunction中,以使设备执行特定的function – 可用于asynchronous通知的callbacks

这现在引导我到我的问题:

通过connectreadwrite操作系统底层IO子系统的知识,可以将这部分代码库编写成C ++类而不是C ++类。

因此,考虑一下原始device的以下伪代码:

 class Device : abstract { bool connect(...) abstract } #ifdef _WIN32 class WindowsDevice : public Device { // Calls Windows-specific functions bool connect(...) } #elif __linux class LinuxDevice : public Device { // Calls Linux-specific functions bool connect(...) } #else #error Bad platform #endif 

然后API函数…

 Device *inst; bool DEVICE_Connect(...) { // bind the device instance here #ifdef _WIN32 inst = new WindowsDevice(); #else inst = new LinuxDevice(); #endif } bool DEVICE_Command(uint8_t cmd) { if (!inst) FAIL; inst->SendCommand(cmd); } 

或者,应该是更多的C风格的API,如下面的伪代码:

 #ifdef _WIN32 HANDLE *inst; #elif __linux void *inst; #else #error Bad platform #endif bool DEVICE_Connect(void *handle) { #ifdef _WIN32 // Windows connect-to-whatever function #elif __linux // Linux connect-to-whatever function #else return FALSE; #endif } bool DEVICE_Command(uint8_t cmd) { if (!inst) FAIL; #ifdef _WIN32 // Windows write command #elif __linux // Linux write command #else return FALSE; #endif } 

基本上,我所希望的是来自那些曾经处于这种状况的人的一些good-practicebuild议。 用C ++来实现代码是否有什么优点,然后把最终用户的C包装暴露出来? 无论如何,这一切都应该在平面C中完成吗?

最后的问题:

有问题的硬件设备有各种连接选项,从TCP和UDP套接字到USB HID,然后是简单的旧的RS232,所以我需要调用的底层function将是相当多样的。

考虑到这一点,在使用最低级别的函数调用时是否有任何实际的意义(或好处) – 我的意思是说,有没有意图使用fopen来打开文件,而不是Windows中的CreateFile ? 这是否帮助我从跨平台的angular度来看,或者这只是一个愚蠢的路要走,限制我的select,如重叠io等方面的东西? 我可能回答了我自己的问题

感谢任何能够提供任何build议,指导方针或最佳实践的人。

作为一个经常在这个问题的另一边工作的人(使用第三方库来与硬件系统进行交互),我鼓励你远离C ++的API。 虽然它可以看起来提供了一个重要的功能集,但C API对最终用户来说要简单得多。 你甚至可以用C ++来实现后端,并像你所建议的那样将它封装到一个C API中。 如果你愿意,这种方法还可以相对容易地为Python等其他语言创建包装器。

通常情况下,这个问题的实现方式是在一个简单的C头中指定一个API,这个C头有一个最小的包含依赖关系,最好没有。 这个头文件将指定你的库的全部功能,包括用户可能需要使用的所有函数,返回码,状态和数据结构。

后端将为每个操作系统实现此行为。 这个平台相关的代码在理想情况下会根据您的需要编译成静态或共享库,最终用户只需要链接到它。 这个库不一定需要开源(大多数情况下,他们不是,如果你是供应商)。 您可以分发头API和共享对象(.so),DLL,存档(.a)或静态库(.lib),或者要求用户编译整个后端。

我使用过的API的一个例子在我看来是这么做的…

  • Kvaser CAN-lib

它不是开源的后端,但仍然通过C风格的API为最终用户提供了一套完整的功能。 我非常怀疑后端在C中实现,但我不确定。

与之前所说的相反,还有跨平台的C ++ API。 一个想到的是…

  • Pleora电子公共汽车SDK

它有一大堆用户可以访问控制硬件的C ++头文件。 它试图使用大量用户可以访问,拥有和控制的类来建模一个完整的功能集。

如果我是用C ++来做这件事的话,我可能会考虑在API中使用PIMPL惯用法来保护最终用户避免在硬件上造成太多的问题。

总的来说,最重要的设计实践是使API定义明确,简洁,易于使用。

如果难以记录或提供使用实例,在实践中可能会很复杂。

您可能希望将您的实现分为独立于平台和平台的代码,即

 bool DEVICE_Command(uint8_t cmd) { if (!inst) FAIL; if (cmd ==1 ) platform_cmd_1(); else platform_cmd_default(cmd); } 

platform_cmd和platform_cmd_default将被实现在不同的文件夹中,并仅针对目标平台进行编译,即您的文件夹结构可能是

 src\ device.c platform_device.h api\ deviceapi.h platform\ win32\ platform_device.c linux platform_device.c macos platform_device.c