動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)上 (3)
終端命令補(bǔ)充以及Common Symbol
擴(kuò)展
- 查看符號(hào)命令 man nm
- /[關(guān)鍵字] 去搜索,例:/-p
- n -> 去下一個(gè)搜索的選項(xiàng)
- N -> 去上一個(gè)搜索的選項(xiàng)
- q -> 退出搜索
- /[關(guān)鍵字] 去搜索,例:/-p
- 查看符號(hào)命令 nm --help
//不排序, 符號(hào)表中的順序
nm -pa text.o

- Common Symbol : 未定義的全局符號(hào)
.a與.framework靜態(tài)庫(kù)詳解
常用庫(kù)文件格式
.a靜態(tài) .dylib動(dòng)態(tài) .framework靜態(tài)動(dòng)態(tài) .xcframework2018年推出不同架構(gòu)的庫(kù)
庫(kù) -> 說(shuō)白了就是一段編譯好的二進(jìn)制代碼, 加上頭文件就可以供別人使用.
什么時(shí)候會(huì)用到庫(kù)(Libraty)?
- 某些代碼需要給你別人使用, 但是我們不希望別人看到代碼, 就需要以庫(kù)的形式進(jìn)行封裝, 只暴露出頭文件.
- 對(duì)于某些不會(huì)進(jìn)行大的改動(dòng)的代碼, 我們想減少編譯的時(shí)間, 就可以把它打包成庫(kù), 因?yàn)閹?kù)是已經(jīng)編譯好的二進(jìn)制了, 編譯的時(shí)候只需要Link一下, 不會(huì)浪費(fèi)編譯時(shí)間.
靜態(tài)庫(kù)
- 鏈接靜態(tài)庫(kù)AFNetworking -> 進(jìn)入AFNetworking -> file libAFNetworking.a
- libAFNetworking.a -> archive文檔格式
- man ar 查看ar的意思 -> ar -t libAFNetworking.a -> 顯示.o文件
- 靜態(tài)庫(kù)AFNetworking 鏈接 test.m 生成目標(biāo)文件
- man clang 查看clang定義
- clang -x objective-c \ //指定編譯的語(yǔ)音
-target x86_64-apple-macos11.1 \ //指定編譯的平臺(tái)
-fobjc-arc \ //arc的環(huán)境
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \ //指定SDK的路徑, 此處是使用的內(nèi)置的基礎(chǔ)庫(kù), 需要鏈接的基礎(chǔ)庫(kù)的路徑
-I./AFNetworking \ //指定鏈接的庫(kù)頭文件的路徑
-c test.m -o test.o //生成目標(biāo)文件
- 通過(guò)鏈接器 生成可執(zhí)行文件
- 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文件的路徑, 因?yàn)榉?hào)保存在.o文件里, -L指定庫(kù)文件路徑(.a.dylib庫(kù)文件)
-lAFNetworking \ //指定鏈接的庫(kù)文件名稱(.a.dylib庫(kù)文件)
test.o -o test- -lAFNetworking 鏈接的名稱為libTestExample/TestExample的動(dòng)態(tài)庫(kù)或者靜態(tài)庫(kù),查找規(guī)則:先找lib+<library_name>的動(dòng)態(tài)庫(kù),找不到,再去找lib+<library_name>的靜態(tài)庫(kù),還找不到,就報(bào)錯(cuò)
- clang -target x86_64-apple-macos11.1
鏈接一個(gè)庫(kù)文件的三要素
- -I<directory> 在指定目錄尋找頭文件 -> header search path
- -L<dir> 指定庫(kù)文件路徑(.a.dylib庫(kù)文件)-> library search path
- -l<library_name> 指定鏈接的庫(kù)文件名稱(.a.dylib庫(kù)文件)-> other link flags
靜態(tài)庫(kù),.o文件的合集(鏈接靜態(tài)庫(kù)生成可執(zhí)行文件)
驗(yàn)證靜態(tài)庫(kù)是.o文件合集
- TestExample.m -> TestExample.o
- TestExample.o -> 改名字libTestExample.dylib(目的變成可執(zhí)行文件) -> 改名字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 -> 進(jìn)入lldb的環(huán)境
- file test -> 將test可執(zhí)行文件包裝Target\
- r -> 證明靜態(tài)庫(kù)就是.o文件的合集
- q -> 退出lldb
擴(kuò)展
- man objdump -> 輸出文件信息
- objdump --macho --private-header libTestExample.dylib
靜態(tài)庫(kù)合并
把所有的.o文件拿過(guò)來(lái)放在一個(gè).o文件里面
- man libtool
- libtool -static -o <OUTPUT NAME> <LIBRARY_1> <LIBRARY_2>
- -static \ //合并類(lèi)型
- libtool -static -o libCat.a 庫(kù)A 庫(kù)B -> 庫(kù)A 庫(kù)B分別解壓, 然后合并
- 有關(guān)重復(fù)文件, libtool會(huì)幫助處理
- 頭文件處理,問(wèn)題所在,怎么處理
mudule
mudule 是clang提供, 來(lái)專(zhuān)門(mén)處理頭文件的. mudule的作用, 預(yù)先將.h文件 -> 二進(jìn)制, 然后緩存(那么每個(gè)引入的其他類(lèi)的頭文件,就不用每次都編譯, 可以直接拿來(lái)用)
鏈接器的特性,
Auto-Link。啟用這個(gè)特性后,當(dāng)我們import <模塊>,不需要我們?cè)偃ネ溄悠魅ヅ渲面溄訁?shù)。比如import <framework>我們?cè)诖a里使用這個(gè)是framework格式的庫(kù)文件,那么在生成目標(biāo)文件時(shí),會(huì)自動(dòng)在目標(biāo)文件的Mach-O中,插入一個(gè)load command格式是LC_LINKER_OPTION,存儲(chǔ)這樣一個(gè)鏈接器參數(shù)-framework <framework>。
Framework
Framework 實(shí)際是一種打包方式, 將庫(kù)的二進(jìn)制文件, 頭文件和有關(guān)資源打包到一起, 方便管理.
Framework和系統(tǒng)的UIKit.Framework還是有很大區(qū)別. 系統(tǒng)的Framework不需要拷貝到目標(biāo)程序中, 我們自己做出來(lái)的Framework哪怕是動(dòng)態(tài)的, 最后也還是要拷貝到APP中(APP和Extension的Bundle是共享的), 因此蘋(píng)果又把這種Framework稱為Embedded Framework.
Framework:
- 靜態(tài)庫(kù) -> Header + .a + 簽名 + 資源文件
- 動(dòng)態(tài)庫(kù) -> Header + .dylib + 簽名 + 資源文件
ar命令
ar壓縮目標(biāo)文件,并對(duì)其進(jìn)行編號(hào)和索引,形成靜態(tài)庫(kù)。同時(shí)也可以解壓縮靜態(tài)庫(kù),查看有哪些目標(biāo)文件:
- ar -rc a.a a.o
- -r: 像a.a添加or替換文件(有就替換, 沒(méi)有就添加)
- -c: 不輸出任何信息
- -t: 列出包含的目標(biāo)文件
- ar -rc libTestExample.a libTestExample.o -> 生成.a文件(文中這樣寫(xiě),相當(dāng)于改個(gè)格式)
手動(dòng)創(chuàng)建Framework
- 創(chuàng)建.framework結(jié)尾的文件夾,例TestFramework.framework
- 新建的文件夾TestFramework.framework -> 創(chuàng)建Headers文件夾 -> 將.h頭文件放入
- 將編譯好的庫(kù)文件放入TestFramework.framework,并修改名字,去除lib開(kāi)頭(如果有),去除.后綴
- 測(cè)試
- 將需要鏈接的文件生成目標(biāo).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腳本創(chuàng)建
.sh解釋型語(yǔ)言
build
記得給build.h加可執(zhí)行權(quán)限 -> chmod +x ./build.sh -> 然后執(zhí)行./build.sh
dead_strip與靜態(tài)庫(kù)
如果引入頭文件, 沒(méi)有使用, 那么生成的可執(zhí)行文件, 里面是否包含導(dǎo)入的頭文件?
- objdump --macho -d test
- -d 查看__TEXT字段的
- 發(fā)現(xiàn)沒(méi)有
- 使用一下, 再用腳本再生成一下test, 發(fā)現(xiàn)有了
- clang命令是默認(rèn)dead_strip的
- 分類(lèi)會(huì)有問(wèn)題 -> 運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建的
- 查看是否是靜態(tài)庫(kù)target -> build Setting -> mach
- dead_strip鏈接的時(shí)候生效的
workspace
- 可重用性, 多個(gè)模塊可以在多個(gè)項(xiàng)目中使用, 節(jié)約開(kāi)發(fā)和維護(hù)時(shí)間.
- 節(jié)省測(cè)試時(shí)間. 單獨(dú)模塊意味著每個(gè)模塊都可以添加測(cè)試功能.
- 更好的理解模塊化思想.
創(chuàng)建workspace
- File -> Save As workspace -> TestDeadStrip
- Add File to workspace -> 添加其他project項(xiàng)目到workspace
- 如果選中的有文件, 那么+號(hào)選項(xiàng)沒(méi)有這個(gè)選項(xiàng)
- 重新從新創(chuàng)建的workspace進(jìn)入項(xiàng)目
- 記得先編譯庫(kù), 再使用庫(kù)的編譯項(xiàng)目
- 想編譯項(xiàng)目的時(shí)候,同時(shí)編譯庫(kù)文件, 只需將庫(kù)文件 + 項(xiàng)目的Targets -> General -> Frameworks,Libraries,andEmbedded Content
- Embed & sign -> Embed嵌入的意思, 即編譯的時(shí)候把Framework拷貝到IPA包里
- Do Not Embed -> 不拷貝, 因?yàn)榇颂幨庆o態(tài)庫(kù)(鏈接的過(guò)程已經(jīng)在一起了,不需要)
接上面分類(lèi)流程, 會(huì)報(bào)錯(cuò), 原因就是dead_strip把分類(lèi)的代碼脫離了.
解決辦法:
Config.LGApp.Debug
.o文件的合并與.o文件鏈接靜態(tài)庫(kù)的區(qū)別
上節(jié)遺留問(wèn)題
.o 和 .o 鏈接 : 先合并成一個(gè)大的.o, 再鏈接dead_strip生成可執(zhí)行文件
.o 和 .a 鏈接 : 先dead_strip去掉多余的
解決:
- Targets -> Build Setting -> LTO -> Link-Time Optimization -> Monolithic