动态库与静态库上 (3)
终端命令补充以及Common Symbol
扩展
- 查看符号命令 man nm
- /[关键字] 去搜索,例:/-p
- n -> 去下一个搜索的选项
- N -> 去上一个搜索的选项
- q -> 退出搜索
- /[关键字] 去搜索,例:/-p
- 查看符号命令 nm --help
//不排序, 符号表中的顺序
nm -pa text.o

- Common Symbol : 未定义的全局符号
.a与.framework静态库详解
常用库文件格式
.a静态 .dylib动态 .framework静态动态 .xcframework2018年推出不同架构的库
库 -> 说白了就是一段编译好的二进制代码, 加上头文件就可以供别人使用.
什么时候会用到库(Libraty)?
- 某些代码需要给你别人使用, 但是我们不希望别人看到代码, 就需要以库的形式进行封装, 只暴露出头文件.
- 对于某些不会进行大的改动的代码, 我们想减少编译的时间, 就可以把它打包成库, 因为库是已经编译好的二进制了, 编译的时候只需要Link一下, 不会浪费编译时间.
静态库
- 链接静态库AFNetworking -> 进入AFNetworking -> file libAFNetworking.a
- libAFNetworking.a -> archive文档格式
- man ar 查看ar的意思 -> ar -t libAFNetworking.a -> 显示.o文件
- 静态库AFNetworking 链接 test.m 生成目标文件
- man clang 查看clang定义
- 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 //生成目标文件
- 通过链接器 生成可执行文件
- 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- -lAFNetworking 链接的名称为libTestExample/TestExample的动态库或者静态库,查找规则:先找lib+<library_name>的动态库,找不到,再去找lib+<library_name>的静态库,还找不到,就报错
- clang -target x86_64-apple-macos11.1
链接一个库文件的三要素
- -I<directory> 在指定目录寻找头文件 -> header search path
- -L<dir> 指定库文件路径(.a.dylib库文件)-> library search path
- -l<library_name> 指定链接的库文件名称(.a.dylib库文件)-> other link flags
静态库,.o文件的合集(链接静态库生成可执行文件)
验证静态库是.o文件合集
- TestExample.m -> TestExample.o
- TestExample.o -> 改名字libTestExample.dylib(目的变成可执行文件) -> 改名字libTestExample
- test.m 链接 libTestExample
- 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
- clang -target x86_64-apple-macos11.1
- lldb -> 进入lldb的环境
- file test -> 将test可执行文件包装Target\
- r -> 证明静态库就是.o文件的合集
- q -> 退出lldb
扩展
- man objdump -> 输出文件信息
- objdump --macho --private-header libTestExample.dylib
静态库合并
把所有的.o文件拿过来放在一个.o文件里面
- man libtool
- libtool -static -o <OUTPUT NAME> <LIBRARY_1> <LIBRARY_2>
- -static \ //合并类型
- libtool -static -o libCat.a 库A 库B -> 库A 库B分别解压, 然后合并
- 有关重复文件, libtool会帮助处理
- 头文件处理,问题所在,怎么处理
mudule
mudule 是clang提供, 来专门处理头文件的. mudule的作用, 预先将.h文件 -> 二进制, 然后缓存(那么每个引入的其他类的头文件,就不用每次都编译, 可以直接拿来用)
链接器的特性,
Auto-Link
。启用这个特性后,当我们import <模块>
,不需要我们再去往链接器去配置链接参数。比如import <framework>
我们在代码里使用这个是framework格式的库文件,那么在生成目标文件时,会自动在目标文件的Mach-O
中,插入一个load command
格式是LC_LINKER_OPTION
,存储这样一个链接器参数-framework <framework>
。
Framework
Framework 实际是一种打包方式, 将库的二进制文件, 头文件和有关资源打包到一起, 方便管理.
Framework和系统的UIKit.Framework还是有很大区别. 系统的Framework不需要拷贝到目标程序中, 我们自己做出来的Framework哪怕是动态的, 最后也还是要拷贝到APP中(APP和Extension的Bundle是共享的), 因此苹果又把这种Framework称为Embedded Framework.
Framework:
- 静态库 -> Header + .a + 签名 + 资源文件
- 动态库 -> Header + .dylib + 签名 + 资源文件
ar命令
ar
压缩目标文件,并对其进行编号和索引,形成静态库。同时也可以解压缩静态库,查看有哪些目标文件:
- ar -rc a.a a.o
- -r: 像a.a添加or替换文件(有就替换, 没有就添加)
- -c: 不输出任何信息
- -t: 列出包含的目标文件
- ar -rc libTestExample.a libTestExample.o -> 生成.a文件(文中这样写,相当于改个格式)
手动创建Framework
- 创建.framework结尾的文件夹,例TestFramework.framework
- 新建的文件夹TestFramework.framework -> 创建Headers文件夹 -> 将.h头文件放入
- 将编译好的库文件放入TestFramework.framework,并修改名字,去除lib开头(如果有),去除.后缀
- 测试
- 将需要链接的文件生成目标.o文件
- 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 - 链接Framework
- 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 - lldb
- file test
- r
- q
- -F<directory> 在指定目录寻找framework framework search path
- -framework <framework_name> 指定链接的framework名称 other link flags -framework AFNetworking
shell初探
.sh脚本创建
.sh解释型语言
build
记得给build.h加可执行权限 -> chmod +x ./build.sh -> 然后执行./build.sh
dead_strip与静态库
如果引入头文件, 没有使用, 那么生成的可执行文件, 里面是否包含导入的头文件?
- objdump --macho -d test
- -d 查看__TEXT字段的
- 发现没有
- 使用一下, 再用脚本再生成一下test, 发现有了
- clang命令是默认dead_strip的
- 分类会有问题 -> 运行时动态创建的
- 查看是否是静态库target -> build Setting -> mach
- dead_strip链接的时候生效的
workspace
- 可重用性, 多个模块可以在多个项目中使用, 节约开发和维护时间.
- 节省测试时间. 单独模块意味着每个模块都可以添加测试功能.
- 更好的理解模块化思想.
创建workspace
- File -> Save As workspace -> TestDeadStrip
- Add File to workspace -> 添加其他project项目到workspace
- 如果选中的有文件, 那么+号选项没有这个选项
- 重新从新创建的workspace进入项目
- 记得先编译库, 再使用库的编译项目
- 想编译项目的时候,同时编译库文件, 只需将库文件 + 项目的Targets -> General -> Frameworks,Libraries,andEmbedded Content
- Embed & sign -> Embed嵌入的意思, 即编译的时候把Framework拷贝到IPA包里
- Do Not Embed -> 不拷贝, 因为此处是静态库(链接的过程已经在一起了,不需要)
接上面分类流程, 会报错, 原因就是dead_strip把分类的代码脱离了.
解决办法:
Config.LGApp.Debug
.o文件的合并与.o文件链接静态库的区别
上节遗留问题
.o 和 .o 链接 : 先合并成一个大的.o, 再链接dead_strip生成可执行文件
.o 和 .a 链接 : 先dead_strip去掉多余的
解决:
- Targets -> Build Setting -> LTO -> Link-Time Optimization -> Monolithic
网友评论