考虑以下情况:我正在使用导出到用户空间的Linux标头中的某些功能,例如<linux/perf_event.h>
中的perf_event_open
。
由于成员已添加到perf_event_attr
,例如perf_event_attr.cap_user_time
,因此该API提供的功能已随着时间而改变。
如果这些新功能在本地可用,那么如何编写可编译和使用这些新功能的源代码,如果不使用和不使用它们,则如何优雅地回退呢?
尤其是如何在预处理器中检测这些东西是否可用?
我以这个perf_event_attr
为例,但是我的问题很笼统,因为结构成员,新结构,定义和函数一直都在添加。
请注意,这里我仅考虑在同一进程上运行该进程的情况:如果要在一个主机上编译而在另一个主机上运行,则需要不同的技巧。
答案 0 :(得分:2)
使用/usr/include/linux/version.h
中的宏:
#include <linux/version.h>
int main() {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
// ^^^^^^ change for the proper version when `perf_event_attr.cap_user_time` was introduced
// use old interface
#else
// use new interface
// use perf_event_attr.cap_user_time
#endif
}
答案 1 :(得分:1)
您可能会遵循以下假设
头文件中的可用功能对应于特定Linux版本所记录的功能。
在执行期间运行的内核对应于编译期间的<linux/version.h>
理想情况下,我建议不要完全依靠这两个假设。
第一个假设失败主要是由于反向移植,例如在基于古老内核的企业Linux版本中。如果您关心不同的版本,那么您可能会关心它们。
相反,我建议使用检查结构成员的方法,并将文件包含在构建系统中,例如对于CMake:
CHECK_STRUCT_HAS_MEMBER("struct perf_event_attr" cap_user_time linux/perf_event.h HAVE_PERF_CAP_USER_TIME)
CHECK_INCLUDE_FILES
也可能有用。
第二个假设可能由于许多原因而失败,即使二进制文件未在系统之间移动也是如此;例如。更新内核但不重新编译二进制文件或仅引导另一个内核。特别是如果设置了保留位,perf_event_open
就会失败,并且EINVAL
失败。这样,您就可以不使用请求的功能来尝试其他实现。
简而言之,请静态检查功能而不是版本。如果失败,请动态尝试重试传统实现。
答案 2 :(得分:1)
除了其他答案之外。
如果您希望同时支持跨版本和跨发行版代码,则还应记住,有发行版(Centos / RHEL)将最近的更改从新内核转移到旧内核。因此,您可能会遇到LINUX_VERSION_CODE
等于某个旧内核版本的情况,但是与最近的内核会有一些变化(数据结构中的新字段,新函数等)。在这种情况下,此宏不足。
您可以添加类似的内容(以免发生预处理器错误(如果它不是Centos发行版):
#ifndef RHEL_RELEASE_CODE
#define RHEL_RELEASE_CODE 0
#endif
#ifndef RHEL_RELEASE_VERSION
#define RHEL_RELEASE_VERSION(x,y) 1
#endif
并在需要的地方与>
或>=
一起使用:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) || RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)
...
获得Centos / RHEL自定义内核支持。
P.S。当然,有必要检查适当版本的Centos / RHEL,并了解何时以及在影响您的代码部分中到底发生了什么更改。