• iOS中的符号抵触(一)- 根底原理

符号其实便是文件里界说的函数或者办法在 Mach-o中的名称

实际上运转app的时分,履行的是机器码

机器码经过反汇编之后,会生成咱们平时见到的汇编代码

app去掉符号之后,能不能运转呢?

继续弥补一些根底知识

xcode 能够理解为一个大号的脚本

  • xcode编译过程中,需求处理编译文件里的头文件

    • 比如编译framework的时分,首先在编译途径里创建一个编译产物途径

    • 生成一个 产物途径 跟 当前真正的符号头文件匹配的 虚拟文件系统 VFS

    • 复制头文件到编译产物途径/headers目录

  • 调起clang (包含汇编器 链接器) 开始编译每一个.m .cpp文件,最终生成可履行文件

  • sign 进行签名

  • strip 进行符号处理

xcconfig 操控build setting, build setting 操控以上整个产物生成流程

如何操控呢

要履行clang的命令,包含脚本的命令,势必要有一个shell环境

clang需求参数才能对.m文件编译 参数传递给clang,经过clang传递给链接器ld

build setting 装备选项怎样在shell环境里生效

shell – 环境变量,shell把build setting每一个装备选项变成 环境变量

xcconfig 每一个装备选项都是 key = value的形式,key会被xcode导成要履行的shell的环境变量 clang用环境变量拼接成需求的参数

咱们常常会在xcode 创建一个 run script,能直接拜访build setting变量,原因便是xcode会把build setting装备变量装备成 shell环境变量

符号类型弥补

  • 上一篇博文中提到了 大局符号、本地符号

    大局符号的效果域为整个进程,本地符号(static)只效果于声明的文件

  • 还有导入、导出符号

    #import <Foundation/Foundation.h> 便是把Foundation动态库里的符号导入到当前工程

    Foundation动态库里露出的符号就称为 导出符号

    NSLog 在Foundation动态库里,归于大局符号,相对于Foundation,归于导出符号,相对于app归于导入符号

    app运转起来之后,除了需求动态库的大局符号,其他符号一概不需求

    动态库也是,除了大局符号,其他符号不需求

    大局符号有导入 导出效果,需求供给给他人

    app里的大局符号能被脱除

    • 由于符号的一个效果便是作为标记汇编代码,假如汇编代码能够直接找到,就不需求符号了,说白了app里的大局符号便是一个地址,直接找地址就OK了,不需求再标记符号,然后依据符号再找了
    • 符号其实大概率是给程序员做调试的

弱界说/弱引证符号

  • Weak Reference Symbol

    表示此未界说符号是弱引证,假如dyld(动态链接器)找不到该符号的界说,则将其设置为0, 静态链接器 找不到 编译就会报错

    • void weak_import_function(void) attribute ((weak_import));

      弱引证符号 xcconfig 设置

      OTHER_LDFLAGS = $(inherited) -Xlinker -U -Xlinker _weak_import_function

      weak_import_function没有完成,直接运用,编译不会报错

      经过xccondig装备 经过编译器告诉链接器忽略 符号 _weak_import_function是否界说,由动态链接器担任 这样 编译正常经过

      iOS中的符号冲突(二)- 理解进阶

      在运用函数时,经过判别进口地址非nil 再履行

      iOS中的符号冲突(二)- 理解进阶

      尽管编译器会提示:

      Address of function ‘weak_import_function’ will always evaluate to ‘true’

      编译器提示 函数进口判别永远不会为空, 这是由于还没有经过动态链接器dyld,还未处理若引证符号 设置为0也便是nil,所以编译器会告警

      运转阶段,动态链接器dyld找不到符号,将符号设置为0,也便是置为nil, 并不会履行,不用担心溃散问题

    • 动态库本身是个大号的符号表,假如想让动态库里的一切符号全为弱引证符号,如何操作

      • 针对动态库有一个专门的参数,-weak_framework 指定为弱引证的动态库,会把动态库里的一切的符号都标记为弱引证

      • spec -> cocoapods 怎样操控framework编译

        cocoapods其实便是经过xccondig 来操控的,就能够传递 恣意参数 像 -weak_framework

    • 扩展知识

      • 动态库 运转的时分,经过途径的方法链接,动态库或许被莫名删掉了,运转时报错

      • 经过 -weak_framework 动态链接器dyld找不到就置nil,不溃散

      • 手动链接framework

      iOS中的符号冲突(二)- 理解进阶

      引进framework头文件

      iOS中的符号冲突(二)- 理解进阶

      编译犯错 – 未界说的符号 _global_home_fun

      iOS中的符号冲突(二)- 理解进阶

      xcconfig 该用链接参数 weak_framework

      iOS中的符号冲突(二)- 理解进阶

      global_home_fun 加上非nil判别

      再次编译success

      运转,希望成功,但是仍然过错

      iOS中的符号冲突(二)- 理解进阶

      过错提示的是 一级命名空间内 符号找不到

      尽管手动链接 framework,-weak_framework 并未能按照ld手册里描述的那样,把链接的framework里一切符号均标记为弱引证符号,但是能够帮助咱们理解 符号的查找过程

      能够自己做个测验,framework均完成同名大局函数,app中调用函数,履行的是app中的函数完成

      假如framework中只声明,未完成的话,app中调用函数 履行的仍然是app中的函数完成

      所以,app中的同名符号 先于 framework被找到,而假如app与framework中均未界说,则该符号不存在比较是否相同,也就没有了两级命名空间,在任何一个framework中都不存在,所以便是flat namespace,报symbol not found过错

      假如在你的app中用到一个framework中未界说的符号,最直接的方法,便是在你的app中界说一个同名的符号

      • -dead_strip_dylibs 告诉链接器,假如dylibs没有供给符号,就停止load此dylib,慎用

  • Weak definition Symbol

    弱界说符号,假如静态链接器或dyld为此符号找到另一个(非弱)界说,则弱界说将被忽略

    假如不确定自己app或framework中的符号在一些其他framework中已界说,最好的方法便是界说为 弱界说符号,没有什么丢失

  • 我正在参加技能社区创作者签约方案招募活动,点击链接报名投稿