靜態(tài)庫

常見庫文件格式:.a.dylib.framework.xcframework.tdb

什么是庫(Library)?

庫(Library)本質(zhì)上就是一段編譯好的二進制代碼,加上頭文件就可以供別人使用。

應用場景?

  1. 某些代碼需要給別人使用,但是不希望別人看到源碼,就需要以庫的形式進行封裝,只暴露出頭文件。
  2. 對于某些不會進行大的改動的代碼,我們想減少編譯的時間,就可以把它打包成庫,因為庫是已經(jīng)編譯好的二進制了,編譯的時候只需要 Link 一下,不會浪費編譯時間。

什么是鏈接(Link)?

庫在使用的時候需要鏈接(Link),鏈接 的方式有兩種:

  1. 靜態(tài)
  2. 動態(tài)

靜態(tài)庫

靜態(tài)庫即靜態(tài)鏈接庫:可以簡單的看成一組目標文件的集合,即很多目標文件經(jīng)過壓縮打包后形成的文件。Windows 下的 .libLinuxMac 下的 .aMac獨有的.framework

缺點: 浪費內(nèi)存和磁盤空間,模塊更新困難。

靜態(tài)庫鏈接

將一份AFNetworking靜態(tài)庫文件(.h頭文件和.a組成)和test.m放到統(tǒng)一目錄。test.m如下:

#import <Foundation/Foundation.h>
#import <AFNetworking.h>

int main(){
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    NSLog(@"test----%@", manager);
    return 0;
}

直接終端查看下.a靜態(tài)庫究竟是什么。

?  AFNetworking file libAFNetworking.a
libAFNetworking.a: current ar archive

可以看到.a實際上是一個文檔格式。也就是.o文件的合集。可以通過ar命令驗證下。

ar -- create and maintain library archives

?  AFNetworking ar -t libAFNetworking.a
__.SYMDEF
AFAutoPurgingImageCache.o
AFHTTPSessionManager.o
AFImageDownloader.o
AFNetworkActivityIndicatorManager.o
AFNetworking-dummy.o
AFNetworkReachabilityManager.o
AFSecurityPolicy.o
AFURLRequestSerialization.o
AFURLResponseSerialization.o
AFURLSessionManager.o
UIActivityIndicatorView+AFNetworking.o
UIButton+AFNetworking.o
UIImageView+AFNetworking.o
UIProgressView+AFNetworking.o
UIRefreshControl+AFNetworking.o
WKWebView+AFNetworking.o

確認.a確實是.o文件的合集。清楚了.a后將AFNetworking鏈接到test.m文件。
1.通過clangtest.m編譯成目標文件.o

clang - the Clang C, C++, and Objective-C compiler
DESCRIPTION
clang is a C, C++, and Objective-C compiler which encompasses prepro-
cessing, parsing, optimization, code generation, assembly, and linking.
Depending on which high-level mode setting is passed, Clang will stop
before doing a full link. While Clang is highly integrated, it is
important to understand the stages of compilation, to understand how to
invoke it. These stages are:
Driver The clang executable is actually a small driver which controls
the overall execution of other tools such as the compiler,
assembler and linker. Typically you do not need to interact
with the driver, but you transparently use it to run the other
tools.
通過man命令我們看到clangCC++OC編譯器,是一個集合包含了預處理解析優(yōu)化代碼生成匯編化鏈接

clang -x objective-c \
-target x86_64-apple-ios14-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk \
-I ./AFNetworking \
-c test.m -o test.o

回車后就生成了test.o目標文件。

\為了轉(zhuǎn)譯回車,讓命令換行更易讀。-x制定編譯語言,-target指定編譯平臺,-fobjc-arc編譯成ARC-isysroot指定用到的Foundation的路徑,-I<directory>在指定目錄尋找頭文件 header search path

為什么生成目標文件只需要告訴頭文件的路徑就可以了?
因為在生成目標文件的時候,重定位符號表只需要記錄哪個地方的符號需要重定位。在連接的時候鏈接器會自動重定位。(上面的例子中只需要保留AFHTTPSessionManager的符號。)
2..o生成可執(zhí)行文件

clang -target x86_64-apple-ios14-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk \
-L./AFNetworking \
-lAFNetworking \
test.o -o test

這個時候test可執(zhí)行程序就生成了。

-L要鏈接的庫文件(libAFNetworking.a)目錄,-l要鏈接的庫文件(libAFNetworking.a)這里只寫AFNetworking是有查找規(guī)則的:先找lib+<library_name>的動態(tài)庫,找不到,再去找lib+<library_name>的靜態(tài)庫,還找不到,就報錯。會自動去找libAFNetworking

經(jīng)過上面的編譯和鏈接清楚了其它參數(shù)都是固定的,那么鏈接成功一個庫文件有3個要素:
1. -I<directory> 在指定目錄尋找頭文件 header search path頭文件
2. -L<dir> 指定庫文件路徑(.a\.dylib庫文件) library search path庫文件路徑
3. -l<library_name> 指定鏈接的庫文件名稱(.a\.dylib庫文件)other link flags -lAFNetworking (庫文件名稱

生成靜態(tài)庫

將自己的一個工程編譯成.a靜態(tài)庫。工程只有一個文件HPExample``.h.m

#import <Foundation/Foundation.h>

@interface HPExample : NSObject

- (void)hp_test:(_Nullable id)e;

@end

#import "HPExample.h"

@implementation HPExample

- (void)hp_test:(_Nullable id)e {
    NSLog(@"hp_test----");
}

@end

HPExample.m編譯成.o文件:

clang -x objective-c \
-target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I./StaticLibrary \
-c HPExample.m -o HPExample.o

這個時候生成了HPExample.o文件,由于工程只有一個.o文件,直接將文件修改為libExample.dylib或者libHPExample.a
然后創(chuàng)建一個test.m文件調(diào)用HPExample:

#import <Foundation/Foundation.h>
#import "HPExample.h"

int main(){
    NSLog(@"testApp----");
    HPExample *manager = [HPExample new];
    [manager hp_test: nil];
    return 0;
}

test.m編譯成test.o

clang -x objective-c \
-target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I./StaticLibrary \
> -c test.m -o test.o

test.o鏈接HPExample

clang -target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-L./StaticLibrary \
-lHPExample \
test.o -o test

現(xiàn)在就已經(jīng)生成了可執(zhí)行文件test
終端lldb執(zhí)行test:

?  staticLibraryCreat lldb
(lldb) file test
Current executable set to '/Users/binxiao/projects/library/staticLibraryCreat/test' (x86_64).
(lldb) r
Process 2148 launched: '/Users/binxiao/projects/library/staticLibraryCreat/test' (x86_64)
2021-02-13 13:22:49.150091+0800 test[2148:13026772] testApp----
2021-02-13 13:22:49.150352+0800 test[2148:13026772] hp_test----
Process 2148 exited with status = 0 (0x00000000)
image.png

這也從側面印證了.a就是.o的合集。file test是創(chuàng)建一個targetr是運行的意思。
接著再看下libHPExample.a文件。

objdump --macho --private-header libHPExample.a
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00      OBJECT     4       1160 SUBSECTIONS_VIA_SYMBOLS

確認還是一個目標文件。

靜態(tài)庫的合并

根據(jù)上面的分析,那么靜態(tài)庫的合并也就是將所有的.o放到一個文件中。
有兩個.a庫:
靜態(tài)庫的合并有兩種方式:libAFNetworking.a,libSDWebImage.a
1.ar -rc libAFNetworking.a libSDWebImage.a

ar -rc libAFNetworking.a  libSDWebImage.a

就相當于將后面的libSDWebImage.a合并到libAFNetworking.a

2.libtool -static -o <OUTPUT NAME> <LIBRARY_1> <LIBRARY_2>
libtool合并靜態(tài)庫。

libtool -static \
-o \
libMerge.a \ 
libAFNetworking.a \
libSDWebImage.a
//libAFNetworking.a要為目標文件路徑,libMerge.a為輸出文件

image.png

這樣就合并了libAFNetworking.alibSDWebImage.alibMerge.a了。在這個過程中libtool會先解壓兩個目標文件,然后合并。在合并的過程中有兩個問題:
1.沖突問題。
2..h文件。

clang提供了mudule可以預先把頭文件(.h)預先編譯成二進制緩存到系統(tǒng)目錄中, 再去編譯.m的時候就不需要再去編譯.h了。

LC_LINKER_OPTION鏈接器的特性,Auto-Link。啟用這個特性后,當我們import <模塊>,不需要我們再去往鏈接器去配置鏈接參數(shù)。比如import <framework>我們在代碼里使用這個framework格式的庫文件,那么在生成目標文件時,會自動在目標文件的Mach-O中,插入一個 load command格式是LC_LINKER_OPTION,存儲這樣一個鏈接器參數(shù)-framework <framework>

動態(tài)庫

與靜態(tài)庫相反,動態(tài)庫在編譯時并不會被拷?到目標程序中,目標程序中只會存儲指向動態(tài)庫的引用。等到程序運行時,動態(tài)庫才會被真正加載進來。格式有:.framework.dylib.tdb

缺點:會導致一些性能損失。但是可以優(yōu)化,比如延遲綁定(Lazy Binding)技術。

.tdb

tbd全稱是text-based stub libraries本質(zhì)上就是一個YAML描述的文本文件。他的作用是用于記錄動態(tài)庫的一些信息,包括導出的符號、動態(tài)庫的架構信息、動態(tài)庫的依賴信息。用于避免在真機開發(fā)過程中直接使用傳統(tǒng)的dylib。對于真機來說,由于動態(tài)庫都是在設備上,在Xcode上使用基于tbd格式的偽framework可以大大減少Xcode的大小。

framework

Mac OS/iOS 平臺還可以使用 FrameworkFramework 實際上是一種打包方式,將庫的二進制文件、頭文件和有關的資源文件打包到一起方便管理和分發(fā)。

Framework 和系統(tǒng)的 UIKit.Framework 還是有很大區(qū)別。系統(tǒng)的 Framework 不需要拷?到目標程序中,我們自己做出來的 Framework 哪怕是動態(tài)的,最后也還是要拷?到 App 中(AppExtensionBundle 是共享的),因此蘋果又把這種 Framework 稱為 Embedded Framework

Embedded Framework

開發(fā)中使用的動態(tài)庫會被放入到ipa下的framework目錄下,基于沙盒運行。
不同的App使用相同的動態(tài)庫,并不會只在系統(tǒng)中存在一份。而是會在多個App中各自打包、簽名、加載一份。

image.png

framework即可以代表動態(tài)庫也可以代表靜態(tài)庫。

生成framework

一般framework格式:

image.png

接著HPExample的例子構建一個framework

image.png

編譯test.m

clang -x objective-c \
-target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I ./Frameworks/HPExample.framework/Headers \
-c test.m -o test.o

鏈接.o生成test可執(zhí)行文件:

clang -target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-F./Frameworks \
-framework HPExample \
test.o  -o  test

執(zhí)行:

image.png

那么鏈接一個framework也就需要三個條件:
1. -I<directory>:在指定目錄尋找頭文件 header search path(頭文件)
2. -F<directory>:在指定目錄尋找framework framework search path
3. -framework <framework_name>:指定鏈接的framework名稱 other link flags -framework AFNetworking

腳本執(zhí)行命令

上面都是通過命令行來進行編譯連接的,每次輸入都很麻煩(即使粘貼復制),我們可以將命令保存在腳本中,通過執(zhí)行腳本來執(zhí)行命令。
還是以HPExample為例,整理后腳本如下(可以加一些日志觀察執(zhí)行問題):

echo "test.m -> test.o"
clang -x objective-c \
-target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I ./StaticLibrary \
-c test.m -o test.o

echo "pushd -> StaticLibrary"
#cd可以進入到一個目錄不推薦使用,cd會修改目錄棧上層,推薦使用 pushd,pushd是往目錄棧中push一個目錄。
pushd ./StaticLibrary

echo "HPExample.m -> HPExample.o"
clang -x objective-c \
-target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I./StaticLibrary \
-c HPExample.m -o HPExample.o

echo "HPExample.o -> libHPExample.a"
#打包.o成靜態(tài)庫
ar -rc libHPExample.a HPExample.o
echo "popd -> StaticLibrary"
popd

echo "test.o -> test"
#鏈接
clang -target x86_64-apple-macos11.0 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-L./StaticLibrary \
-lHPExample \
test.o -o test

執(zhí)行腳本(記的加可執(zhí)行權限x):

image.png

這個時候就已經(jīng)自動編譯鏈接完成了,其中路徑是pushdpopd自動生成的。
可以簡單優(yōu)化下腳本:

SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk
#${SYSROOT}和$SYSROOT都行,如果要匹配比如${SYSROOT}.mm則用{}
FILE_NAME=test
HEADER_SEARCH_PATH=./StaticLibrary

function MToOOrExec {
  if [[ $2 == ".m" ]]; then
    clang -x objective-c \
    -target x86_64-apple-macos11.0 \
    -fobjc-arc \
    -isysroot ${SYSROOT} \
    -I${HEADER_SEARCH_PATH} \
    -c $1.m -o $1.o
  else
    clang -target x86_64-apple-macos11.0 \
    -fobjc-arc \
    -isysroot ${SYSROOT} \
    -L${HEADER_SEARCH_PATH} \
    -l$1 \
    ${FILE_NAME}.o -o ${FILE_NAME}
  fi
  return 0
}

echo "test.m -> test.o"
MToOOrExec ${FILE_NAME} ".m"
echo "pushd -> StaticLibrary"
#cd可以進入到一個目錄不推薦使用,cd會修改目錄棧上層,推薦使用 pushd,pushd是往目錄棧中push一個目錄。
pushd ${HEADER_SEARCH_PATH}
echo "HPExample.m -> HPExample.o"
MToOOrExec HPExample ".m"
echo "HPExample.o -> libHPExample.a"
#打包.o成靜態(tài)庫
ar -rc libHPExample.a HPExample.o
echo "popd -> StaticLibrary"
popd
echo "test.o -> test"
#鏈接
MToOOrExec HPExample ".o"

dead code strip

對于上面的例子,如果我們在test.m中不使用HPExample只是導入。

#import <Foundation/Foundation.h>
#import "HPExample.h"

int main(){
    NSLog(@"test----");
//    HPExample *manager = [HPExample new];
//    [manager hp_test: nil];
    return 0;
}

那么生成的test執(zhí)行文件包含了HPExample么?
objdump --macho --d test看一下:

image.png

只有一個mainNSLog
打開注釋的代碼在看下:
image.png

默認clangdead code strip是生效的。
在有分類的情況下
看另外一個例子,我們直接用Xcode創(chuàng)建一個framework,設置為靜態(tài)庫。(Targets -> Build Settings -> Linking -> Macho-type)
image.png

這個庫有一個HPTestObject以及HPTestObject+HPAdditions。實現(xiàn)如下:
HPTestObject

//.h
#import <Foundation/Foundation.h>

@interface HPTestObject : NSObject

- (void)hp_test;

@end

//.m
#import "HPTestObject.h"
#import "HPTestObject+HPAdditions.h"

@implementation HPTestObject

- (void)hp_test {
    [self hp_test_additions];
}

@end

HPTestObject+HPAdditions

//.h
#import "HPTestObject.h"

@interface HPTestObject (HPAdditions)

- (void)hp_test_additions;

@end

//.m
#import "HPTestObject+HPAdditions.h"

@implementation HPTestObject (HPAdditions)

- (void)hp_test_additions {
    NSLog(@"log: hp_test_additions");
}

@end

HPTestObject設置為public

image.png

我們知道分類是在運行時動態(tài)創(chuàng)建的,dead code strip是在鏈接的過程中生效的。那么應該在鏈接的時候會strip掉分類。
我們創(chuàng)建一個workspace驗證下

workspace
A. 可重用性。多個模塊可以在多個項目中使用。節(jié)約開發(fā)和維護時間。
B. 節(jié)省測試時間。單獨模塊意味著每個模塊中都可以添加測試功能。
C. 更好的理解模塊化思想。

1.File -> save as workspace

image.png

2.創(chuàng)建一個project(TestApp)。

image.png

3.打開workspace,添加一個project(創(chuàng)建的TestApp)(??需要關閉打開的文件才會出現(xiàn)Add Files to TestDeadCodeStrip):

image.png

image.png

4.ViewController.m中使用HPTestObject

#import <HPStaticFramework/HPTestObject.h>

- (void)viewDidLoad {
    [super viewDidLoad];
    HPTestObject *hpObject = [HPTestObject new];
    [hpObject hp_test];
}

5.運行

libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[HPTestObject hp_test_additions]: unrecognized selector sent to instance 0x600001048020'
terminating with uncaught exception of type NSException

和預想的一樣直接報錯了,原因是dead code strip脫掉了分類。要解決問題還是要告訴編譯器不要脫。
6.配置XCConfig告訴編譯器不要脫。

//-Xlinker 告訴 clang -all_load 參數(shù)是傳給 ld 的。
OTHER_LDFLAGS=-Xlinker -all_load

再次運行App:

 TestApp[8958:13347736] log: hp_test_additions

??
-Xlinker 告訴 clang -all_load 參數(shù)是傳給ld的。
-all_load:全部鏈接

OTHER_LDFLAGS=-Xlinker -all_load

-ObjC: OC相關的代碼不要剝離

//OTHER_LDFLAGS=-Xlinker -ObjC

-force_load:指定哪些靜態(tài)庫不要 dead strip

HPSTATIC_FRAMEWORK_PATH=${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/HPStaticFramework.framework/HPStaticFramework
OTHER_LDFLAGS=-Xlinker -force_load $HPSTATIC_FRAMEWORK_PATH

-noall_load: 默認,沒有使用靜態(tài)庫代碼則不往可執(zhí)行文件添加。This is the default. This option is obsolete.

以上4種參數(shù)僅針對靜態(tài)庫。dead code strip是在鏈接過程中連接器提供的優(yōu)化方式。

-dead_strip
Remove functions and data that are unreachable by the entry point or exported symbols.
移除沒有被入口點(也就是main)和導出符號用到的代碼。

接著libraryDeadCodeStrip工程驗證下:
修改test.m如下:

#import <Foundation/Foundation.h>
//#import "HPExample.h"

//全局函數(shù)
void global_function() {
    
}

//entry point
int main(){
//    global_function();
    NSLog(@"test----");
//    HPExample *manager = [HPExample new];
//    [manager hp_test: nil];
    return 0;
}

//本地
static void static_function(){
    
}

運行build.sh
objdump --macho --syms test查看符號表:

image.png

可以看到?jīng)]有靜態(tài)庫libHPExample.a相關的代碼,加上all_load再查看下:
build.sh修改增加

-Xlinker -all_load \

再次運行上面的步驟:

image.png

可以看到hp_test方法已經(jīng)有了。
修改-Xlinker -all_load-Xlinker -dead_strip 再查看下:
image.png

global_functionhp_test都沒有了。
打開mainglobal_function()的注釋再看下:
image.png

所以dead code strip-all_load-ObjC-force_load-noall_load不是一個東西,他有一定規(guī)則:

  1. 入口點沒有使用->干掉
  2. 沒有被導出符號使用->干掉

接著-Xlinker -dead_strip-Xlinker -all_load一起添加:

image.png

鏈接器有一個參數(shù)-why_live可以查看某一個符號為什么沒有被干掉,比如我們要知道global_function為什么沒有被干掉:

    -Xlinker -why_live -Xlinker _global_function
image.png

.o -> .o.o -> .a

.o -> .o是合并成一個大的.o再去鏈接生成可執(zhí)行文件。先組合再鏈接。所以這里dead code strip干不掉,可以通過LTO(Link-Time Optimization)去優(yōu)化。
.o鏈接靜態(tài)庫是.o是去使用靜態(tài)庫。先dead code strip再使用。

image.png

Embed

image.png
  1. Do Not Embed
    用于靜態(tài)庫
  2. Embed & Sign
    嵌入,用于動態(tài)庫,動態(tài)庫在運行時鏈接,所以它們編譯的時候需要被打進bundle里面。靜態(tài)庫鏈接的時候代碼就已經(jīng)在一起了,所以不需要拷貝,直接Do Not Embed就可以了。可以通過file命令驗證:
file HPStaticFramework.framework/HPStaticFramework
HPStaticFramework.framework/HPStaticFramework: current ar archive random library

current ar archive:說明是靜態(tài)庫,選擇Do not embed
Mach-0 dynamically:說明是動態(tài)庫,選擇Embed

  1. Embed Without Signing
    Signing:只用于動態(tài)庫,如果已經(jīng)有簽名了就不需要再簽名。終端執(zhí)行codesign -dv判斷:
codesign -dv HPStaticFramework.framework
Executable=/Users/***/Library/Developer/Xcode/DerivedData/TestDeadCodeStrip-fhbiunbplvqefkftfystdixdxmkq/Build/Products/Debug-iphonesimulator/HPStaticFramework.framework/HPStaticFramework
Identifier=HotpotCat.HPStaticFramework
Format=bundle with generic
CodeDirectory v=20100 size=204 flags=0x2(adhoc) hashes=1+3 location=embedded
Signature=adhoc
Info.plist entries=20
TeamIdentifier=not set
Sealed Resources version=2 rules=10 files=2
Internal requirements count=0 size=12

Signature
code object is not signed at all 或者 adhoc:選擇Embed and sign
其它:表示已經(jīng)正確簽名,選擇Embed Without Signing

命令總結

clang命令參數(shù)

-x: 指定編譯文件語言類型
-g: 生成調(diào)試信息
-c: 生成目標文件,只運行preprocesscompileassemble不鏈接
-o: 輸出文件
-isysroot: 使用的SDK路徑
-I<directory>: 在指定目錄尋找頭文件 header search path
-L<directory> :指定庫文件路徑(.a.dylib庫文件)library search path
-l<library_name>: 指定鏈接的庫文件名稱(.a.dylib庫文件)other link flags -lAFNetworking。鏈接的名稱為libAFNetworking/AFNetworking的動態(tài)庫或者靜態(tài)庫,查找規(guī)則:先找lib+<library_name>的動態(tài)庫,找不到,再去找lib+<library_name>的靜態(tài)庫,還找不到,就報錯。
-F<directory>: 在指定目錄尋找framework,framework search path
-framework <framework_name>: 指定鏈接的framework名稱,other link flags -framework AFNetworking

test.m編譯成test.o過程

  1. 使用OC
  2. 生成指定架構的代碼,Big Sur是:x86_64-apple-macos11.1,之前是:x86_64-apple-macos10.15。iOS模擬器是:x86_64-apple-ios14-simulator。更多內(nèi)容可以參考target部分。
  3. 使用ARC
  4. 使用的SDK的路徑在:
    Big Sur是:/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
    之前是:/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
    模擬器是:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk \
    更多內(nèi)容可以參考sdk部分。
  5. 用到的其他庫的頭文件地址在./Frameworks
    命令示例:
clang -x objective-c \
-target x86_64-apple-ios14-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk \
-I ./AFNetworking \
-c test.m -o test.o

test.o鏈接生成test可執(zhí)行文件

clang鏈接.a靜態(tài)庫

順序和生成.o差不多,不需要指定語言。
命令示例:

clang -target x86_64-apple-ios14-simulator \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk \
-L./AFNetworking \
-lAFNetworking \
test.o -o test

ld鏈接.framework靜態(tài)庫

ld -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk \
-lsystem -framework Foundation \
-lAFNetworking \
-L.AFNetworking \
test.o -o test

XCFrameworks
demo

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容