objc_sendMsg函数原型修改了

本文探讨了在将Mac系统升级到10.15.1后遇到的objc_sendMsg函数原型更改问题,详细解释了ABI的概念及其与C/C++标准的关系,并提供了修改代码以适应新函数原型的方法。

升级Mac系统到10.15.1之后,发现有一处代码编译不过。发现是使用了objc_sendMsg,但是在2019.10左右,Mac OS X系统中把这个方法原型修改了。原本是带参数的,现在直接改为void objc_sendMsg(void)了。但是,仍然可以传参数。具体参考 :

objc_msgSend’s New Prototype 这篇文章介绍了为什么能改变函数原型,这里面提到函数调用的实现细节,以及ABI方面的东西。

ABI在理解的时候可以借助我们熟悉的API。

API是源码级别的约定,比如参数,返回值,以及一些属性,比如是否可以继承。这个是由编译器定义约束的。

而ABI是二进制文件之间的约定。定义了一种机制,定义了数据类型,长度,对齐方式,函数调用转化,调用时参数如何在调用者和被调用者之间传递,返回值如何传回给调用者,库文件如何实现,程序如何被加载进内存,多进程如何共存。所以ABI由链接器约束。一般标准是由CPU厂商定义,比如Intel(卷3 Intel® 64 and IA-32 Architectures Software Developer Manuals)、AMD(System V Application Binary Interface AMD64 Architecture Processor Supplement,居然不在AMD官网上维护,而是放在了GitHub上,不解,参考这个问题)。

但是C/C++标准中都没有定义ABI,参考Quora上一个问题 Why is C++ ABI not as good as C ABI? Dan Allen的一个回答,注意别被标题误导,C/C++都没有定义ABI。之前在研究如何让自定义C++类型成为atomic的时候,发现为了满足这一条件,C++做了很多看起来很别扭的约定,而且还在不同版本的标准中变化,比如:一个C++类是否是standard layout,是否是trivial class,是否是POD(而且还不同于C中的POD,真让人头晕)。估计(猜测,不想深究了)跟ABI也有一定的关系。

不过,也有厂商公布了自己的ABI标准。比如libstdc++库定义了C++ Standard Library ABI,虽然版本老一些了。

Casting Objective-C Message Sends,这篇文章介绍了如何修改较好。

objctive-c run-time库可以在这里看objc4,有各种版本。

#if defined(Q_OS_OSX)
#include <objc/objc.h>
#include <objc/message.h>

// ref: https://www.mikeash.com/pyblog/objc_msgsends-new-prototype.html
bool dockClickHandler(id self,SEL _cmd,...);
void setupDockClickHandler() {
    Class cls = objc_getClass("NSApplication");
    objc_object* (*OBJC_CALL)(id, SEL) = (objc_object* (*)(id, SEL)) objc_msgSend;
    objc_object* appInst = OBJC_CALL((objc_object*)cls, sel_registerName("sharedApplication"));

    if(appInst != NULL) {
        objc_object* delegate = OBJC_CALL(appInst, sel_registerName("delegate"));
        Class delClass = (Class)OBJC_CALL(delegate,  sel_registerName("class"));
        SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
        if (class_getInstanceMethod(delClass, shouldHandle)) {
            if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:")) {
               // qDebug() << "Registered dock click handler (replaced original method)";
            } else {
              //qWarning() << "Failed to replace method for dock click handler";
            }
        }
        else {
            if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:")) {
                //qDebug() << "Registered dock click handler";
            } else {
                //qWarning() << "Failed to register dock click handler";
            }
        }
    }
}
bool dockClickHandler(id self,SEL _cmd,...) {
    if (IM::getInstance()) {
        IM::getInstance()->showMainForm();
    }
    return false;
}
#endif
xcode手动导入包报错:Undefined symbol: _APMAnalyticsConfiguration Undefined symbol: _APMAppMeasurementOriginFirebase Undefined symbol: _APMConsentSettings3P Undefined symbol: _APMFormattedEventName Undefined symbol: _APMFormattedUserPropertyName Undefined symbol: _APMIsAnalyticsCollectionDeactivated Undefined symbol: _APMIsAnalyticsCollectionEnabled Undefined symbol: _APMIsValidTransactionDeviceVerification Undefined symbol: _APMMonitorLogTagOptionKey Undefined symbol: _APMUserDataFieldEmailAddress Undefined symbol: _APMUserDataFieldHashedEmailAddress Undefined symbol: _APMUserDataFieldHashedPhoneNumber Undefined symbol: _APMUserDataFieldPhoneNumber Undefined symbol: _OBJC_CLASS_$_APMAdExposureReporter Undefined symbol: _OBJC_CLASS_$_APMAnalytics Undefined symbol: _OBJC_CLASS_$_APMConditionalUserProperty Undefined symbol: _OBJC_CLASS_$_APMConditionalUserPropertyController Undefined symbol: _OBJC_CLASS_$_APMEvent Undefined symbol: _OBJC_CLASS_$_APMIdentifiers Undefined symbol: _OBJC_CLASS_$_APMIdentity Undefined symbol: _OBJC_CLASS_$_APMMeasurement Undefined symbol: _OBJC_CLASS_$_APMScreenViewReporter Undefined symbol: _OBJC_CLASS_$_APMUserAttribute Undefined symbol: _OBJC_CLASS_$_APMValue Undefined symbol: _OBJC_CLASS_$_MTGAdChoicesView Undefined symbol: _OBJC_CLASS_$_MTGBannerAdView Undefined symbol: _OBJC_CLASS_$_MTGBidNativeAdManager Undefined symbol: _OBJC_CLASS_$_MTGBidRewardAdManager Undefined symbol: _OBJC_CLASS_$_MTGBiddingSDK Undefined symbol: _OBJC_CLASS_$_MTGMediaView Undefined symbol: _OBJC_CLASS_$_MTGNewInterstitialAdManager Undefined symbol: _OBJC_CLASS_$_MTGNewInterstitialBidAdManager Undefined symbol: _OBJC_CLASS_$_MTGRewardAdManager Undefined symbol: _OBJC_CLASS_$_MTGSDK Undefined symbol: _OBJC_CLASS_$_MTGSplashAD Undefined symbol: _OBJC_METACLASS_$_APMAdExposureReporter Undefined symbol: _OBJC_METACLASS_$_APMConditionalUserProperty Undefined symbol: _OBJC_METACLASS_$_APMConditionalUserPropertyController Undefined symbol: _OBJC_METACLASS_$_APMEvent Undefined symbol: _OBJC_METACLASS_$_APMIdentifiers Undefined symbol: _OBJC_METACLASS_$_APMMeasurement Undefined symbol: _OBJC_METACLASS_$_APMScreenViewReporter Undefined symbol: _OBJC_METACLASS_$_APMUserAttribute Undefined symbol: _OBJC_METACLASS_$_APMValue
最新发布
07-27
在Xcode手动导入SDK后,若出现`Undefined symbol: _APMAnalyticsConfiguration`和`_OBJC_CLASS_$_MTGSDK`等错误,通常意味着链接器无法找到某些类或符号的定义。这类问题通常出现在接入第三方SDK、静态库或进行多项目联编时,特别是在架构适配、依赖管理或构建配置设置不当的情况下。 ### 检查依赖库是否正确引入 若使用的是手动导入方式(非CocoaPods),需要确保APM和MTG相关的`.a`、`.framework`或`.xcframework`文件已正确添加到项目中,并在`Build Phases > Link Binary With Libraries`中显式链接这些库。遗漏或路径错误会导致符号未定义错误[^1]。 ### 构建配置与架构设置 确保构建配置(Build Configuration)中的`Other Linker Flags`包含必要的标志,如`-ObjC`和`-framework "APM"`或`-framework "MTGSDK"`。此外,检查`Build Settings > Architectures`是否与SDK支持的架构一致。若APM或MTG SDK不支持`arm64`或模拟器架构(如`x86_64`),应在`Excluded Architectures`中排除。 ### Bitcode设置 部分第三方SDK可能不支持Bitcode。若项目启用了Bitcode(默认为`YES`),而APM或MTG SDK未提供Bitcode支持,则会导致链接失败。此时应将`Build Settings > Enable Bitcode`设置为`NO`,尤其是Archive构建配置中。 ### 静态库依赖问题 若APM或MTG SDK是静态库形式提供,还需确保其依赖的系统框架(如`CoreTelephony`、`SystemConfiguration`等)也被正确链接。否则即使主库被正确引入,其内部依赖的符号仍然可能报错[^1]。 ### 桥接与模块设置(适用于Swift项目) 若项目使用Swift语言,并且APM或MTG SDK是Objective-C编写的,需确保在桥接头文件(Bridging Header)中正确导入SDK头文件。此外,检查主项目与Pod项目的`Defines Module`和`Product Module Name`设置是否一致,以确保Swift能够识别Objective-C模块[^1]。 ### 示例:Other Linker Flags设置 ```bash OTHER_LDFLAGS = ( "-framework \"APM\"", "-framework \"MTGSDK\"", "-ObjC", ); ``` ### 示例:排除不支持的架构 在`Build Settings > Excluded Architectures`中添加: ``` x86_64 ``` 适用于Release和Archive构建配置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值