Obj-C 有@available.斯威夫特有 #available.我可以在 C/C++ 中使用什么?



如果你的代码需要仅在macOS 10.12或更高版本中可用的功能,但你希望你的代码也部署到早期的系统版本,你可以在Objective-C中使用@available

if (@available(macOS 10.12, *)) {
// Code that requires 10.12 APIs
} else {
// Code that doesn't require 10.12 APIs
}

你可以在 Swift 中使用#available做同样的事情:

if #available(macOS 10.12, *) {
// Code that requires 10.12 APIs
} else {
// Code that doesn't require 10.12 APIs
}

但是,如果您编写 C 或 C++ 代码,您可以使用什么?

在 C 和 C++ 中,您可以使用 Clang 编译器扩展__builtin_available

if (__builtin_available(macOS 10.12, *)) {
// Code that requires 10.12 APIs
} else {
// Code that doesn't require 10.12 APIs
}

也就是说,如果您至少有可用的 Clang 5(Xcode 5.0 或更高版本(。

请记住,您必须设置部署目标才能使此功能正常工作(例如-mmacosx-version-min=10.9(。原因是链接器需要此信息来决定何时执行弱链接。例如,将部署目标设置为 10.9 会告诉链接器,如果代码正在使用 10.9 中尚不可用的任何符号,则必须对这些符号进行弱链接。

通常,可执行文件或库将尝试在加载时解析所有引用的符号,如果找不到任何此类符号,则无法加载。但是,当符号是弱链接时,无法解析符号不会导致加载失败,而是对该符号的任何引用在运行时都将成为NULL引用。不用说,如果您尝试调用弱链接且在加载时未找到的函数,您的应用程序将崩溃(您正在尝试将NULL作为函数调用(。这就是__builtin_available来救援的地方。

if (__builtin_available(macOS 10.12, *)) {
// ...
} else {
// Symbols only available in 10.12 or newer are all NULL when
// you reach this code block but you wouldn't use any of them
// in this code block, would you? So, no problem.
}

如果不使用-mmacosx-version-min__builtin_available构造仍将正常工作,但由于链接器不知道您要针对哪个系统,因此它会假定当前系统并且不会执行任何弱链接。如果随后尝试在较早的系统版本上运行应用,则找不到某些符号,并且应用甚至拒绝加载,尽管它具有该系统的替代代码路径。

相关内容

最新更新