美文网首页iOS 开发随笔iOS Developer
关于duplicate symbol的思考

关于duplicate symbol的思考

作者: JamesYu | 来源:发表于2017-02-20 23:05 被阅读553次

    关于duplicate symbol的思考

    iOS 开发中经常会遇到duplicate symbol这个问题,在编译链接的时候就会出现。相信有经验的开发都知道是怎么回事。那今天要讲的就是编译器在link时的一个坑!

    讲个故事

    最近在我们在发布SDK的时候,测试和预发,以及灰度都做完了。在正式发布的时候直接闪退了。看到这个问题直接一脸懵逼!

    在SDK中,我们接入了人脸识别的SDK,在APP里面接入的时候,出现了闪退。挂在了RSA验签上,为什么同样的SDK会在正式发布的时候必闪退呢?由于涉及些公司安全东西,本篇是个阉割版,就不说解决过程了,我直接告诉结果了!

    iOS系统API中并没有提供RSA公钥验签的算法API。既然挂在了这里,怀疑是扣了openssl的部分代码,进行了修改。APP里面也接入了openssl,然后在编译链接的时候,实际的RSA调用函数是外面的openssl的RSA,导致了crash。

    探索

    既然是两个库里面同时存在同样的symbol,为什么不报duplicate symbol的错误?我们下面写个demo进行测试下。

    一、建立两个测试Library(LinkLibraryA和LinkLibraryB)和一个demo工程。

    • LinkLibraryA
    //.h
    #ifndef LinkLibraryA_h
    #define LinkLibraryA_h
    
    #include <stdio.h>
    
    void sameMethod();
    
    #endif /* LinkLibraryA_h */
    
    //.c
    void sameMethod()
    {
        printf("==== Library A ====");
    }
    
    
    • LinkLibraryB
    //.h
    #ifndef LinkLibraryB_h
    #define LinkLibraryB_h
    
    #include <stdio.h>
    
    void sameMethod();
    
    #endif /* LinkLibraryB_h */
    
    //.c
    void sameMethod()
    {
        printf("==== Library B ====");
    }
    
    
    • demo
    //mian.c
    #include <stdio.h>
    
    #include "LinkLibraryA.h"
    
    int main(int argc, const char * argv[]) {
        
        sameMethod();
        return 0;
    }
    
    

    二、测试过程

    直接编译发现xcode并没有报duplicate symbol错误。

    测试1——先链接LinkLibraryA再链接LinkLibraryB

    运行结果:==== Library A ====

    测试2——先链接LinkLibraryB再链接LinkLibraryA

    运行结果:==== Library B ====

    通过以上两个测试,我们可以发现,存在同样的symbol,link的时候是不报错的!而且执行结果是依赖于静态库ld的顺序的!

    进一步测试

    • 修改下LinkLibraryB
    //.h
    #ifndef LinkLibraryB_h
    #define LinkLibraryB_h
    
    #include <stdio.h>
    
    int sameMethod();
    
    void testMethod(int a);
    
    #endif /* LinkLibraryB_h */
    
    //.c
    int sameMethod()
    {
        printf("==== Library B ====");
        return 1;
    }
    
    void testMethod(int a)
    {
        printf("==== test link===");
    }
    
    

    sameMethod增加一个返回值,增加另个一入参是int的testMethod的函数。

    • 修改下demo测试代码
    //main.c
    #include <stdio.h>
    
    #include "LinkLibraryB.h"
    
    int main(int argc, const char * argv[]) {
        
        testMethod(sameMethod());
        
        return 0;
    }
    

    在main函数里面,我们在testMethod方法中,将sameMethod当入参传入。

    测试1——先链接LinkLibraryA再链接LinkLibraryB

    运行结果:编译不通过!报duplicate symbol _sameMethod

    测试2——先链接LinkLibraryB再链接LinkLibraryA

    运行结果:=== Library B ======== test link===

    总结

    通过以上测试可以发现,如果linker解决unresolved symbols时,如果已经找到symbol,那么将不再去其他静态库里面寻找。

    后面两组测试,第一组报错了,是因为ld LinkLibraryA的时候已经发现sameMethod,但是需要解决testMethod的symbol,接着ld LinkLibraryB的时候,LinkLibraryB里面的LinkLibraryB.o中找到了testMethod,但是,又一次发现了sameMethod,所以报错了!(后来,我把testMethod换成单独的文件去写,无论先链接谁,都是编译不报错的,但是逻辑和上面说的一样,从侧面也说明了linker优先寻找本静态库的符号,如果找到将不再去其他静态库进行寻找)

    如果在other linker flags里面添加-all_load那么也就正常报错了,也就是我们所说的linker不允许存在重复的符号!

    思考

    通过以上测试,我们发现了在接入静态库的时候,容易出现此类问题。所以,我觉得以下几个点,大家还是需要关注下:

    • C没有函数重载,哪怕你参数多一个,编译链接的时候,也不会报错。因此,命名应有一套规范,防止和外面的C函数进行冲突

    这点我觉得可以参考OC的方法,加上前缀。

    • C函数不对外开放的函数,尽量加上static,限制它的作用域
    • 对于接入的多个SDK依赖共同的SDK,请一定要仔细确认版本。

    以上问题,大家注意下,希望大家别再踩了这个坑!

    相关文章

      网友评论

        本文标题:关于duplicate symbol的思考

        本文链接:https://www.haomeiwen.com/subject/iacywttx.html