动态库与静态库上 (3)

动态库与静态库上 (3)

终端命令补充以及Common Symbol

扩展

  1. 查看符号命令 man nm
    1. /[关键字] 去搜索,例:/-p
      1. n -> 去下一个搜索的选项
      2. N -> 去上一个搜索的选项
      3. q -> 退出搜索
  2. 查看符号命令 nm --help

//不排序, 符号表中的顺序
nm -pa text.o


image.png
  • Common Symbol : 未定义的全局符号

.a与.framework静态库详解

终端快捷键

常用库文件格式
.a静态 .dylib动态 .framework静态动态 .xcframework2018年推出不同架构的库

库 -> 说白了就是一段编译好的二进制代码, 加上头文件就可以供别人使用.

什么时候会用到库(Libraty)?

  1. 某些代码需要给你别人使用, 但是我们不希望别人看到代码, 就需要以库的形式进行封装, 只暴露出头文件.
  2. 对于某些不会进行大的改动的代码, 我们想减少编译的时间, 就可以把它打包成库, 因为库是已经编译好的二进制了, 编译的时候只需要Link一下, 不会浪费编译时间.

静态库

  1. 链接静态库AFNetworking -> 进入AFNetworking -> file libAFNetworking.a
    1. libAFNetworking.a -> archive文档格式
    2. man ar 查看ar的意思 -> ar -t libAFNetworking.a -> 显示.o文件
  2. 静态库AFNetworking 链接 test.m 生成目标文件
    1. man clang 查看clang定义
    2. clang -x objective-c \ //指定编译的语音
      -target x86_64-apple-macos11.1 \ //指定编译的平台
      -fobjc-arc \ //arc的环境
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \ //指定SDK的路径, 此处是使用的内置的基础库, 需要链接的基础库的路径
      -I./AFNetworking \ //指定链接的库头文件的路径
      -c test.m -o test.o //生成目标文件
  3. 通过链接器 生成可执行文件
    1. clang -target x86_64-apple-macos11.1
      -fobjc-arc
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      -L./AFNetworking \ //.o文件的路径, 因为符号保存在.o文件里, -L指定库文件路径(.a.dylib库文件)
      -lAFNetworking \ //指定链接的库文件名称(.a.dylib库文件)
      test.o -o test
      1. -lAFNetworking 链接的名称为libTestExample/TestExample的动态库或者静态库,查找规则:先找lib+的动态库,找不到,再去找lib+的静态库,还找不到,就报错
链接一个库文件的三要素
  1. -I 在指定目录寻找头文件 -> header search path
  2. -L 指定库文件路径(.a.dylib库文件)-> library search path
  3. -l 指定链接的库文件名称(.a.dylib库文件)-> other link flags

链接静态库AFNetworking命令

命令详解

静态库,.o文件的合集(链接静态库生成可执行文件)

验证静态库是.o文件合集

  1. TestExample.m -> TestExample.o
  2. TestExample.o -> 改名字libTestExample.dylib(目的变成可执行文件) -> 改名字libTestExample
  3. test.m 链接 libTestExample
    1. clang -target x86_64-apple-macos11.1
      -fobjc-arc
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      -L./StaticLibrary
      -lTestExample
      test.o -o test
  4. lldb -> 进入lldb的环境
  5. file test -> 将test可执行文件包装Target\
  6. r -> 证明静态库就是.o文件的合集
  7. q -> 退出lldb

扩展

  1. man objdump -> 输出文件信息
  2. objdump --macho --private-header libTestExample.dylib

静态库合并

把所有的.o文件拿过来放在一个.o文件里面

  1. man libtool
  2. libtool -static -o
    1. -static \ //合并类型
    2. libtool -static -o libCat.a 库A 库B -> 库A 库B分别解压, 然后合并
      1. 有关重复文件, libtool会帮助处理
      2. 头文件处理,问题所在,怎么处理

mudule

mudule 是clang提供, 来专门处理头文件的. mudule的作用, 预先将.h文件 -> 二进制, 然后缓存(那么每个引入的其他类的头文件,就不用每次都编译, 可以直接拿来用)

链接器的特性,Auto-Link。启用这个特性后,当我们import <模块>,不需要我们再去往链接器去配置链接参数。比如import 我们在代码里使用这个是framework格式的库文件,那么在生成目标文件时,会自动在目标文件的Mach-O中,插入一个 load command格式是LC_LINKER_OPTION,存储这样一个链接器参数-framework

Framework

Framework 实际是一种打包方式, 将库的二进制文件, 头文件和有关资源打包到一起, 方便管理.
Framework和系统的UIKit.Framework还是有很大区别. 系统的Framework不需要拷贝到目标程序中, 我们自己做出来的Framework哪怕是动态的, 最后也还是要拷贝到APP中(APP和Extension的Bundle是共享的), 因此苹果又把这种Framework称为Embedded Framework.

Framework:

  1. 静态库 -> Header + .a + 签名 + 资源文件
  2. 动态库 -> Header + .dylib + 签名 + 资源文件
ar命令

ar压缩目标文件,并对其进行编号和索引,形成静态库。同时也可以解压缩静态库,查看有哪些目标文件:

  • ar -rc a.a a.o
    • -r: 像a.a添加or替换文件(有就替换, 没有就添加)
    • -c: 不输出任何信息
    • -t: 列出包含的目标文件
  • ar -rc libTestExample.a libTestExample.o -> 生成.a文件(文中这样写,相当于改个格式)
手动创建Framework
  1. 创建.framework结尾的文件夹,例TestFramework.framework
  2. 新建的文件夹TestFramework.framework -> 创建Headers文件夹 -> 将.h头文件放入
  3. 将编译好的库文件放入TestFramework.framework,并修改名字,去除lib开头(如果有),去除.后缀
  4. 测试
    1. 将需要链接的文件生成目标.o文件
    2. clang -x objective-c -fmodules
      -target x86_64-apple-macos11.1
      -fobjc-arc
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      -I./Frameworks/TestExample.framework/Headers
      -c test.m -o test.o
    3. 链接Framework
    4. clang -target x86_64-apple-macos11.1
      -fobjc-arc
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      -F./Frameworks \ //-F+Frameworks所在的目录
      -framework TestExample \ //要链接的Frameworks的名字
      test.o -o test
    5. lldb
    6. file test
    7. r
    8. q
  • -F 在指定目录寻找framework framework search path
  • -framework 指定链接的framework名称 other link flags -framework AFNetworking

shell初探

.sh脚本创建
.sh解释型语言

build
记得给build.h加可执行权限 -> chmod +x ./build.sh -> 然后执行./build.sh

dead_strip与静态库

如果引入头文件, 没有使用, 那么生成的可执行文件, 里面是否包含导入的头文件?

  1. objdump --macho -d test
    1. -d 查看__TEXT字段的
    2. 发现没有
  2. 使用一下, 再用脚本再生成一下test, 发现有了
  3. clang命令是默认dead_strip的
  4. 分类会有问题 -> 运行时动态创建的
    1. 查看是否是静态库target -> build Setting -> mach
    2. dead_strip链接的时候生效的

workspace

  1. 可重用性, 多个模块可以在多个项目中使用, 节约开发和维护时间.
  2. 节省测试时间. 单独模块意味着每个模块都可以添加测试功能.
  3. 更好的理解模块化思想.

创建workspace

  1. File -> Save As workspace -> TestDeadStrip
  2. Add File to workspace -> 添加其他project项目到workspace
    1. 如果选中的有文件, 那么+号选项没有这个选项
    2. 重新从新创建的workspace进入项目
  3. 记得先编译库, 再使用库的编译项目
  4. 想编译项目的时候,同时编译库文件, 只需将库文件 + 项目的Targets -> General -> Frameworks,Libraries,andEmbedded Content
    1. Embed & sign -> Embed嵌入的意思, 即编译的时候把Framework拷贝到IPA包里
    2. Do Not Embed -> 不拷贝, 因为此处是静态库(链接的过程已经在一起了,不需要)

接上面分类流程, 会报错, 原因就是dead_strip把分类的代码脱离了.
解决办法:
Config.LGApp.Debug

.o文件的合并与.o文件链接静态库的区别

上节遗留问题
.o 和 .o 链接 : 先合并成一个大的.o, 再链接dead_strip生成可执行文件
.o 和 .a 链接 : 先dead_strip去掉多余的

解决:

  1. Targets -> Build Setting -> LTO -> Link-Time Optimization -> Monolithic

编译命令

编译命令

你可能感兴趣的:(动态库与静态库上 (3))