动态库(4)

动态库(4)

dead strip 补充

  1. 跟这些参数没有关系_noall_load,-all_load,-Objc,-force_load<file>
    1. 这些参数控制你链接的库必须是静态库的时候. 死代码删除
  2. dead code stripping
    1. 链接的时候, 链接器提供的代码优化方式

证明步骤

  1. test.m里面没有用静态库的东西
  2. 编译,链接生成可执行文件 (链接器默认_noall_load)
    1. 用build.sh脚本
    2. objdump --macho -d test -> 查看汇编代码 -> 没有静态库方法
    3. 如果想链接进去可执行文件 -> -Xlinker -all_load -> 有静态库方法了

dead strip

  1. dead strip -> man ld -> /dead strip 查看方法说明
    1. 本地没有被入口点或导出符号用到的, 就会被移出
    2. build.sh -> -Xlinker -dead strip -> objdump --macho --syms test查看符号表
    3. 全局符号 global_function()没有使用,就会被干掉
    4. 使用后,导出符号表就会有

总结: -Xlinker -dead strip \ -Xlinker -all_load 同时写上去, 静态库的符号并不会被干掉,因为OC是动态运行的,如果静态库里面的符号被干掉,用的时候就会出问题.

查看一个符号为什么活着
-Xlinker -why_live -Xlinker _global_function
调用脚本查看打印信息
build

动态库.dylib.framework编译链接详解

test.m 链接 AFNetworking

  1. test.m -> test.o
    1. clang -target x86_64-apple-macos11.1
      -fobjc-arc
      -isysroot $SYSROOT
      -I./AFNetworking
      -c text.m -o test.o
    2. 链接动态库
      1. clang -target x86_64-apple-macos11.1
        -fobjc-arc
        -isysroot $SYSROOT
        -L./AFNetworking
        -lAFNetworking
        text.o -o test
    3. -file test
    4. r -> 出错 -> Library not loaded/ image not found
    5. q

动态库原理

  1. 按照静态库链链接的脚本去写, 同样会报上面的错误Library not loaded/ image not found
  2. 不添加-all_load 会报错: ""referenced from, 因为动态库的导出符号表里没有(默认_noall_load的问题)
    1. objdump --macho --exports-trie 动态库路径 -> 查看动态库的导出符号表
  3. 修正-all_load后,还是报错Library not loaded/ image not -> 动态库特性
  4. 静态库.o文件的合集, 而动态库(最终链接产物)是静态库链接后的产物 -> 动态库不能合并,跟可执行文件是同一级别的.

dongtaiBuild

解决Library not loaded

test.o 链接动态的时候, 到底用到了什么东西

  1. LoginApp 使用SYCSSColor动态库
    1. xcconfig -> 告诉程序HEADER_SEARCH_PATHS -> 也就是-I的参数
    2. FRAMEWORK_SEARCH_PATHS -> 去哪个路径下找frameworks -> 也就是-F
    3. OTHER_LDFLAGS -> 要连接库的名称 -> 也就是-framework
    4. 上面参数主要目的是 -> 告诉程序导出符号在哪里
  2. tdb格式的讲解(请看下方tdb格式说明) -> 动态库在链接的时候, 只需要知道你所需符号所在的一个位置就行,不需要知道源码. -> 错误之所以存在就是链接的时候没有问题, 在运行的时候找不到了
  3. 动态库与framework
    1. 根据脚本生成framework,TestExample
    2. test.o 链接framework,test-framework
      1. framework实际是苹果对动静态库多了一层包装, 本质是一个动态库或者静态库.
    3. lldb -file test -> r -> 运行起来报错(Library not loaded)
      1. 其实就是程序运行的时候,根据路径找不到动态库.
      2. otool -l test | grep 'DYLIB' -> 查看动态库路径
        1. otool -l test | grep 'DYLIB' -A 5 -> -A 查找时多显示5行
        2. 发现根据系统动态库的名字 -> 很像一个路径 -> 我们自定义的动态库的名字孤零零的 -> 动态库路径不对
  4. 解决Library not loaded错误
    1. 编译链接生成动态库的时候, 去保存动态库的路径 -> 动态库的Macho文件Load_Command去保存自己的路径
      1. 进入动态库目录 -> otool -l TestExample | grep 'ID' -A 5
        1. A 是向下 B是向下显示
      2. LC_ID_DYLIB -> name -> name的命名规则是包含路径信息的 -> 此处的错误就是因为这里引起的
    2. man install_name_tool -> 改变动态库的install names
    3. install_name_tool -id 路径 动态库 -> 修改成功 -> 查看一下是否修改成功(otool -l) -> 修改成功后, 需要重新链接动态库 -> 再查看是否链接成功
    4. 最好是在生产动态库的时候, 路径就修改好 -> 改动态库的脚本 -> 最后链接生成动态库的时候 -> 添加参数-install_name 相对路径
      1. 查看@rpath定义(下方有做说明) -> 修改路径 -> install_name_tool -id @rpath/Framework/TestExample.framework/TestExample
      2. @rpath -> 由可执行文件的MachO提供
        1. 去查看可执行文件中是否有@rpath -> otool -l test | grep 'RPATH' -A 5 -> 发现没有
          1. 注意此处大小写敏感
        2. 在可执行文件中添加@rpath -> install_name_tool -add_rpath <路径> <添加的可执行文件>
          1. otool -l test | grep 'dylib' -A 3 -i
            1. 如果想大小写不敏感 -> 拼上-i的参数
        3. 添加后可直接运行查看 -> lldb -file test -> r -> q
      3. 修改可执行文件的rpath路径 -> install_name_tool -rpath <旧路径> <新路径> <可执行文件的名字>
        1. 当然也可以重新添加一个@rpath -> 注意:可执行文件的rpath可以有多个
        2. 可以查看cocopods里面的xcconfig文件 -> LD_RUNPATH_SEARCH_PATH 键值对来加深印象

install_name 与 @rpath

  • @rpath -> Runpath search Paths -> dylb搜索路径 -> 谁链接动态库, 就由谁来提供@rpath

  • '@executable_path': 表示可执行程序所在的目录, 解析为可执行文件的绝对路径.

  • '@loader_path': 表示被加载的'Mach-O'所在的目录, 每次加载时, 都可能被设置为不同的路径, 由上层决定

    • @loader_path -> 一句话就是谁链接我的动态库的那个可执行文件的路径

loader_path说明,动动链接

  1. 可执行文件 -> 链接了一个动态库, 但是同时我这个动态库里面 -> 链接的有其他的动态库
    1. 注意: 此时编译应该从后往前编译 -> 即先编译最里面的动态库 (01:45:00)
  2. 最后的动态库-> -Xlinker -install_name -Xlinker @rpath/TestExampleLog.framework/TestExampleLog
    1. -Xlinker -> 正常开发中系统提供的链接器
  3. 前面的可执行文件 -> -Xlinker -rpath -Xlinker @executable_path/Frameworks
  4. 中间的动态库 -> -Xlinker -install_name -Xlinker @rpath/TestExample.framework/TestExample
  5. 中间层的动态库 -> 提供loader_path -> -Xlinker -rpath -Xlinker @executable_path/Frameworks/TestExample.framework/Frameworks -> 是可以运行成功的
    1. 建议-Xlinker -rpath -Xlinker @loader_path/Frameworks
  6. 对应到Xcode -> build setting -> install_name/rpath (搜索查看)

可执行文件使用动态库中的动态库探究

  1. 可执行文件为什么能够使用动态库 -> 因为动态库的暴露了自己的导出符号给可执行文件
  2. 但是最里层的动态库对于最外层的可执行文件,其导出符号是否暴露呢
    1. 查看最里层的导出符号表 -> objdump --macho --exports-trie TestExampleLog
    2. 查看中间层的导出符号表 -> objdump --macho --exports-trie TestExample
      1. 没有最里层的导出符号
  3. 重新导出符号
    1. 去到中间的动态库 -> -Xlinker -reexport_framework -Xlinke TestExampleLog
      1. 意思是重新导出TestExampleLog的符号表
      2. 可通过man ld -> /reexport 去查看命令参数, 上面是有关framework, -l相关的是 -reexport -lx <.a/.dylib>
      3. 查看中间层的导出符号 -> nm -m <动静态库>
      4. 注意: 中间层的 -> LC_REEXPORT_DYLIB -> 通过改参数来链接最外层的可执行文件和最里层的动态库
      5. 只需要引入最里层的头文件就可以了
        1. -I 最里层的头文件 -> -I./Frameworks/TestExample.framework/Frameworks/TestExampleLog.framework/Headers

tdb格式动态库

什么是tdb格式

tdb格式全称(text_based stub libraries),本质上就是一个YAML描述的文本文件,类似于配置文件.
它的作用是用于记录动态库的一些信息, 包括导出的符号, 动态库的架构信息, 动态库的依赖信息.
用于避免在真机开发过程中直接使用传统的dylib.
对于真机来说, 由于动态库都是在设备上, 在Xcode上使用基于tdb格式的伪framework可以大大减少Xcode的大小.

注意点:

  1. 苹果不允许dylib的动态库, 所以我们开发中自己生成的动态库, 基本上都是.framework格式的.原因是单dylib少了签名文件,请参考生成的IPA包中,所有引入的动态库,最后都要进行签名生成签名文件.
  2. 动态库比静态库分发体积要小, 给别人提供SDK的时候,要考虑SDK的体积,虽然别人使用的时候会让别人的IPA包变大.
    1. 可以更好的控制动态库里面符号的可见性
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 什么事动态库?与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运...
    Jax_YD阅读 1,181评论 0 6
  • 什么是动态库? 与静态库相反,动态库在编译时并不会被拷⻉到⽬标程序中,⽬标程序中只会存储指向动态库的引⽤。等到程序...
    帅驼驼阅读 667评论 0 5
  • iOS 开发进阶 文章汇总[https://www.jianshu.com/p/c40b31400816] 目录 ...
    differ_iOSER阅读 3,035评论 0 19
  • 前言: 我们还使用静态库[https://www.jianshu.com/p/71e1684c5b2a]中的案例 ...
    浅墨入画阅读 394评论 0 0
  • 1.动态库原理 1.1自己生成动态库(失败) 我们还是用在静态库[https://www.jianshu.com/...
    MonKey_Money阅读 1,759评论 0 0