weak_import生成链接器错误

时间:2014-09-27 16:36:55

标签: c++ macos linker clang

为什么在OSX 10.8下编译时,下面的代码没有链接?我怎样才能将它链接起来以便它可以在10.8和10.9之间工作?我正在使用clang ++ 5.1。

// MyFile.cc
// Compile with: clang++ MyFile.cc -framework ApplicationServices

#include <ApplicationServices/ApplicationServices.h>
#include <iostream>

extern "C" CFStringRef kAXTrustedCheckOptionPrompt __attribute__ ((weak_import));
extern "C" Boolean AXIsProcessTrustedWithOptions (CFDictionaryRef options) __attribute__ ((weak_import));

static bool IsSupported (void)
{
    return AXIsProcessTrustedWithOptions ?
        AXIsProcessTrustedWithOptions (NULL):
        AXAPIEnabled() || AXIsProcessTrusted();
}

int main (void)
{
    std::cout << (IsSupported() ? "SUPPORTED\n" : "NOT SUPPORTED\n");
    return 0;
}

注意:一切都在10.9中运行,二进制在10.8中运行。

1 个答案:

答案 0 :(得分:1)

弱链接仍然需要链接。您链接的库或框架仍然必须定义符号。在10.8 SDK中,ApplicationServices框架没有定义AXIsProcessTrustedWithOptions符号。

我至少可以想到这个符号必须由库定义的两个原因。首先,检测错误,例如代码中的符号名称是否有拼写错误。您希望链接器能够通知您该符号永远不可用。第二个(可能更重要),因为链接器和动态加载器的两级命名空间功能。对于动态库或框架提供的符号,链接器不仅记录符号名称,还记录解析它的库或框架。在加载时,符号与两者匹配。这允许两个动态库提供相同的符号,而不存在冲突或不正确绑定的风险。

如果您要针对10.8 SDK构建并仍然有条件地使用AXIsProcessTrustedWithOptions(),则需要使用动态加载。您可以使用dlopen()打开/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices,然后使用dlsym()获取指向该函数的指针。检查指针是否为NULL,将其转换为正确的类型,然后您可以调用它指向的函数。

static bool IsSupported (void)
{
    static Boolean (*pAXIsProcessTrustedWithOptions)(CFDictionaryRef options);

    static dispatch_once_t once;
    dispatch_once(&once, ^{
        void* handle = dlopen("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices", 0);
        if (handle)
            pAXIsProcessTrustedWithOptions = dlsym(handle, "AXIsProcessTrustedWithOptions");
    };

    return pAXIsProcessTrustedWithOptions ?
        pAXIsProcessTrustedWithOptions (NULL):
        AXAPIEnabled() || AXIsProcessTrusted();
}