我已经完成了为我们的硬件传感器构建跨平台API的任务,以使第三方开发人员更容易使用它们。目前,我们有许多遗留应用程序,其中硬件层是在GUI内部和周围构建的。
我想要做的是删除硬件层并实现一个可靠但设计良好的跨平台API,然后可以将其提供给第三方开发人员,以帮助将我们的硬件集成到他们的平台中。
我意识到在Stack Overflow术语中,这可能是一个红旗问题,但无论如何我都会问它。
我们现有的代码库是多语言(C#,C ++ / Qt,Delphi等),但只能在Windows上运行。我想进一步推进这项工作,至少包括Linux,可能还有一些Mac / OSX支持。
从更大的角度来看,我对未来任务的理解是创造一个"黑盒子"说到API。诸如connect
之类的函数将接受一些参数并传递某种设备handle
,其中底层连接代码对用户是隐藏的。然后可以将此句柄传递到各种control
函数中,以使设备执行特定功能 - callbacks
可用于异步通知。
现在这引出了我的问题:
使用connect
,read
或write
等函数需要了解操作系统的底层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-practice
建议。使用C ++实现代码是否有任何优点,然后为最终用户公开C包装器?这一切都应该用扁平的C来完成吗?
最后一个问题:
有问题的硬件设备有各种连接选项,从TCP和UDP套接字到USB HID,然后是简单的旧RS232,因此我需要调用的基础功能将是多种多样的。
考虑到这一点,使用最低级别的函数调用是否有任何实际意义(或好处) - 我的意思是,有意使用fopen
来打开文件,而不是Windows中的CreateFile
?从跨平台的角度来看,这对我有帮助吗?这只是一种愚蠢的方式,限制我在重叠io等方面的选择?我可能回答了我自己的问题......
感谢任何能提供任何建议,指导或最佳实践的人。
答案 0 :(得分:3)
作为定期处理此问题另一方的人(使用第三方库与硬件系统连接),我建议您远离C ++以获取API。虽然它似乎可以提供重要的功能集,但对于最终用户来说C API更加简单。您甚至可以在C ++中实现后端并将其包装到您建议的C API中。如果您愿意,这种方法还允许您相对容易地为其他语言(如Python)创建包装器。
通常实现此问题的方法是在简单的C头中严格指定API,该头具有最小的包含依赖性,最佳无。此标头将指定库的完整功能,包括用户可能需要使用的所有函数,返回码,状态和数据结构。
然后,后端将为每个操作系统实现此行为。理想情况下,此平台相关代码将根据您的需要编译为静态或共享库,最终用户只需链接到它。该库不一定需要是开源的(大多数情况下,如果您是供应商,它们不是)。您可以分发标头API和共享对象(.so),DLL,存档(.a)或静态库(.lib),或者要求用户编译整个后端。
在我看来,我所使用的API的一个例子就是......
它不是开源后端,但仍然通过C样式API为最终用户提供了一整套功能。我非常怀疑后端是用C实现的,但我不确定。
与我之前所说的相反还有跨平台的C ++ API。想到的是...
它有一大组C ++标头,用户可以访问它们来控制硬件。它尝试使用用户可以访问,拥有和控制的大量类来建模完整的功能集。
如果我在C ++中这样做,我可能会考虑在API中使用PIMPL惯用法来保护最终用户免于在硬件上造成太多问题。
总的来说,最重要的设计实践是使API定义明确,简洁易用。
如果难以记录或提供使用示例,则在实践中使用可能会很复杂。
答案 1 :(得分:1)
您可能希望将您的实现划分为独立于平台且依赖于平台的代码,即
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