先假設(shè)我有3個(gè)源文件:A、B、C,如果3個(gè)源文件分別編譯成3個(gè)靜態(tài)庫(kù),那么就會(huì)得到3個(gè).a文件,分別是A.a、B.a和C.a;這樣子在別人引用的時(shí)候需要導(dǎo)入的文件過(guò)多,那我們有沒有什么辦法可以將這些文件合并為一個(gè)lib.a文件呢?
注意,我這里說(shuō)的合并多個(gè)庫(kù)并不是指真機(jī)和模擬器版本的合并。
思路誤區(qū)
很多人覺得既然.a就是一個(gè)靜態(tài)庫(kù)文件,那么是不是把多個(gè)靜態(tài)庫(kù)文件直接合成一個(gè)文件不就OK了?
但是,事實(shí)上這是不行的。因?yàn)殪o態(tài)庫(kù)的模塊是.o文件,你合并.a進(jìn)去會(huì)導(dǎo)致無(wú)法找到符號(hào),那么這個(gè)庫(kù)就沒用了。
所以,我們需要的是把.a里的.o提取出來(lái),然后再把所有.o合并在一起,再打包成.a文件。
原理
首先,我們先認(rèn)識(shí)下gcc的幾個(gè)選項(xiàng):
- -c表示只編譯(compile)源文件但不鏈接,會(huì)把.c或.cc的c源程序編譯成目標(biāo)文件(二進(jìn)制文件),一般是.o文件。
- -o用于指定輸出(out)文件名。不用-o的話,一般會(huì)在當(dāng)前文件夾下生成默認(rèn)的a.out文件作為可執(zhí)行程序。
- 在命令行中使用
ar rc lib.a lib.o生成.a文件。
從這里可以看出,真正帶符號(hào)的是.o文件,而.a文件是.o文件加層殼。
其實(shí).a文件的結(jié)構(gòu)和.tar文件沒啥區(qū)別。我們可以用ar命令去做操作:
-
x命令解出來(lái)。 -
r命令將文件插入庫(kù)文件中。 -
c命令建立庫(kù)文件。 -
a命令添加。 -
u命令只將日期較新文件插入庫(kù)文件中。
更多
rc命令內(nèi)容請(qǐng)參考該文章:linux ar命令用法
但是,單單使用ar命令還是不夠的。因?yàn)?code>ar命令只是把.o文件插入進(jìn)去,并沒有更新符號(hào)表,所以我們需要使用ranlib命令更新符號(hào)表。
用法很簡(jiǎn)單,ranlib 庫(kù)文件名即可,如:ranlib lib.a。
更多關(guān)于
ranlib命令請(qǐng)參考文章:ranlib的作用
示例
假設(shè)我有上百個(gè).a文件需要合并,如果在命令行自己敲,那不知道需要敲到什么時(shí)候了,所以我用shell來(lái)進(jìn)行批處理。代碼如下:
#!/bin/sh
#
# 批量合并多個(gè).a文件
dir_path="${HOME}/Documents/library" # ${HOME}是登錄用戶的目錄;這里先設(shè)置好需要解壓的.a文件所在的絕對(duì)路徑;根據(jù)實(shí)際情況修改
lib_path="${dir_path}/lib_folder" # 解壓.a和合成.a絕對(duì)路徑;根據(jù)實(shí)際情況修改
file_name="libxx.a" # 合成.a的名字;根據(jù)實(shí)際情況修改
#創(chuàng)建庫(kù)文件目錄
if [[ ! -d "${lib_path}" ]]
then
mkdir -p "${lib_path}" # 使用雙引號(hào)防止存在空格導(dǎo)致錯(cuò)誤
fi
cd "${lib_path}"
# 查找文件并解壓
for file in $(ls "${dir_path}"|tr " " "?") # 解決名字帶空格的問(wèn)題
do
if [[ "${file}" =~ ".a" ]]
then
ar x "${dir_path}/${file}" #解壓文件所在的路徑 如果是在上級(jí)目錄,可以用../${file}
fi
done
# 合并文件
ar cru "${file_name}" *.o
ranlib "${file_name}"
# 刪除解壓出來(lái)的文件
for file in $(ls|tr " " "?")
do
if [ "${file}" != "${file_name}" ] # 不是我們最終的.a文件,就刪掉
then
rm -f "${file}"
fi
done
# 打開文件夾
open "${lib_path}"
在這里,我假設(shè)我的.a文件都放在dir_path里,生成新的.a文件放在lib_path里,新生成的.a名字叫file_name。當(dāng)然,這3個(gè)變量都需要你根據(jù)自己的實(shí)際情況去改。
lib_path并不需要事先創(chuàng)建,我在腳本做了判斷,如果沒有該文件夾則會(huì)創(chuàng)建,并且包括其父文件夾也會(huì)創(chuàng)建。
如果腳本文件報(bào)沒權(quán)限的錯(cuò)誤,需要使用命令行來(lái)打開權(quán)限。
打開命令行,cd到腳本所在的目錄,然后執(zhí)行sudo chmod +x 腳本名即可。
腳本我做了文件名帶空格時(shí)的處理,所以無(wú)須擔(dān)心文件名有空格會(huì)導(dǎo)致錯(cuò)誤的問(wèn)題。
iOS OC Swift Flutter開發(fā)群 139322447