動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)上 (3)

動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)上 (3)

終端命令補(bǔ)充以及Common Symbol

擴(kuò)展

  1. 查看符號(hào)命令 man nm
    1. /[關(guān)鍵字] 去搜索,例:/-p
      1. n -> 去下一個(gè)搜索的選項(xiàng)
      2. N -> 去上一個(gè)搜索的選項(xiàng)
      3. q -> 退出搜索
  2. 查看符號(hào)命令 nm --help

//不排序, 符號(hào)表中的順序
nm -pa text.o


image.png
  • 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)?

  1. 某些代碼需要給你別人使用, 但是我們不希望別人看到代碼, 就需要以庫(kù)的形式進(jìn)行封裝, 只暴露出頭文件.
  2. 對(duì)于某些不會(huì)進(jìn)行大的改動(dòng)的代碼, 我們想減少編譯的時(shí)間, 就可以把它打包成庫(kù), 因?yàn)閹?kù)是已經(jīng)編譯好的二進(jìn)制了, 編譯的時(shí)候只需要Link一下, 不會(huì)浪費(fèi)編譯時(shí)間.

靜態(tài)庫(kù)

  1. 鏈接靜態(tài)庫(kù)AFNetworking -> 進(jìn)入AFNetworking -> file libAFNetworking.a
    1. libAFNetworking.a -> archive文檔格式
    2. man ar 查看ar的意思 -> ar -t libAFNetworking.a -> 顯示.o文件
  2. 靜態(tài)庫(kù)AFNetworking 鏈接 test.m 生成目標(biāo)文件
    1. man clang 查看clang定義
    2. 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)文件
  3. 通過(guò)鏈接器 生成可執(zhí)行文件
    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文件的路徑, 因?yàn)榉?hào)保存在.o文件里, -L指定庫(kù)文件路徑(.a.dylib庫(kù)文件)
      -lAFNetworking \ //指定鏈接的庫(kù)文件名稱(.a.dylib庫(kù)文件)
      test.o -o test
      1. -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ò)
鏈接一個(gè)庫(kù)文件的三要素
  1. -I<directory> 在指定目錄尋找頭文件 -> header search path
  2. -L<dir> 指定庫(kù)文件路徑(.a.dylib庫(kù)文件)-> library search path
  3. -l<library_name> 指定鏈接的庫(kù)文件名稱(.a.dylib庫(kù)文件)-> other link flags

鏈接靜態(tài)庫(kù)AFNetworking命令

命令詳解

靜態(tài)庫(kù),.o文件的合集(鏈接靜態(tài)庫(kù)生成可執(zhí)行文件)

驗(yàn)證靜態(tài)庫(kù)是.o文件合集

  1. TestExample.m -> TestExample.o
  2. TestExample.o -> 改名字libTestExample.dylib(目的變成可執(zhí)行文件) -> 改名字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 -> 進(jìn)入lldb的環(huán)境
  5. file test -> 將test可執(zhí)行文件包裝Target\
  6. r -> 證明靜態(tài)庫(kù)就是.o文件的合集
  7. q -> 退出lldb

擴(kuò)展

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

靜態(tài)庫(kù)合并

把所有的.o文件拿過(guò)來(lái)放在一個(gè).o文件里面

  1. man libtool
  2. libtool -static -o <OUTPUT NAME> <LIBRARY_1> <LIBRARY_2>
    1. -static \ //合并類(lèi)型
    2. libtool -static -o libCat.a 庫(kù)A 庫(kù)B -> 庫(kù)A 庫(kù)B分別解壓, 然后合并
      1. 有關(guān)重復(fù)文件, libtool會(huì)幫助處理
      2. 頭文件處理,問(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:

  1. 靜態(tài)庫(kù) -> Header + .a + 簽名 + 資源文件
  2. 動(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
  1. 創(chuàng)建.framework結(jié)尾的文件夾,例TestFramework.framework
  2. 新建的文件夾TestFramework.framework -> 創(chuàng)建Headers文件夾 -> 將.h頭文件放入
  3. 將編譯好的庫(kù)文件放入TestFramework.framework,并修改名字,去除lib開(kāi)頭(如果有),去除.后綴
  4. 測(cè)試
    1. 將需要鏈接的文件生成目標(biāo).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<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)入的頭文件?

  1. objdump --macho -d test
    1. -d 查看__TEXT字段的
    2. 發(fā)現(xiàn)沒(méi)有
  2. 使用一下, 再用腳本再生成一下test, 發(fā)現(xiàn)有了
  3. clang命令是默認(rèn)dead_strip的
  4. 分類(lèi)會(huì)有問(wèn)題 -> 運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建的
    1. 查看是否是靜態(tài)庫(kù)target -> build Setting -> mach
    2. dead_strip鏈接的時(shí)候生效的

workspace

  1. 可重用性, 多個(gè)模塊可以在多個(gè)項(xiàng)目中使用, 節(jié)約開(kāi)發(fā)和維護(hù)時(shí)間.
  2. 節(jié)省測(cè)試時(shí)間. 單獨(dú)模塊意味著每個(gè)模塊都可以添加測(cè)試功能.
  3. 更好的理解模塊化思想.

創(chuàng)建workspace

  1. File -> Save As workspace -> TestDeadStrip
  2. Add File to workspace -> 添加其他project項(xiàng)目到workspace
    1. 如果選中的有文件, 那么+號(hào)選項(xiàng)沒(méi)有這個(gè)選項(xiàng)
    2. 重新從新創(chuàng)建的workspace進(jìn)入項(xiàng)目
  3. 記得先編譯庫(kù), 再使用庫(kù)的編譯項(xiàng)目
  4. 想編譯項(xiàng)目的時(shí)候,同時(shí)編譯庫(kù)文件, 只需將庫(kù)文件 + 項(xiàng)目的Targets -> General -> Frameworks,Libraries,andEmbedded Content
    1. Embed & sign -> Embed嵌入的意思, 即編譯的時(shí)候把Framework拷貝到IPA包里
    2. 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去掉多余的

解決:

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

編譯命令

編譯命令

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容