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