文件結構
data # 待打包的文件夾
├── DEBIAN # 這裏放着各種安裝包的描述、配置文件,還有安裝前後執行的腳本等
│ ├── control
│ ├── copyright
│ └── postinst
├── opt # 安裝目錄下的相對內容
├── etc # 安裝目錄下的相對內容
└── usr # 安裝目錄下的相對內容
打包
在data
的上一級目錄執行
dpkg-deb -Z xz -z 9 --build ./data test.deb
這個命令會在當前目錄生成一個 test.deb
就是打包好的安裝包
多線程打包
在上述命令上多添加一個參數:--compress-program=pixz
dpkg-deb --compress-program=pixz -Z xz -z 9 --build ./data test.deb
- pixz是一個多線程xz壓縮工具, 需要提前安裝
sudo apt-get install pixz
dpkg-deb
當然,默認的dpkg-deb是沒有上面那個參數的,這個dpkg-deb是我修改源碼後重新編譯的版本。如果你也有多線程打包的需求,可以使用這樣兩個方案:
- 下載使用我的dpkg-deb:https://download.csdn.net/download/Three_dog/12027997
- 下載dpkg源碼,修改代碼內容。編譯生成dpkg-deb使用。
方案二中,如何下載編譯dpkg請參見:https://blog.csdn.net/Three_dog/article/details/103418141
下載後修改的內容不多,我懶得一個一個文件改動寫那麼詳細了,這裏直接貼個diff,有需要的小夥伴對照着看下應該知道該改哪裏。
diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
index 3317b51..0fc7e96 100644
--- a/dpkg-deb/build.c
+++ b/dpkg-deb/build.c
@@ -582,6 +582,7 @@ do_build(const char *const *argv)
control_compress_params.type = COMPRESSOR_TYPE_GZIP;
control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE;
control_compress_params.level = -1;
+ control_compress_params.program = NULL;
if (!compressor_check_params(&control_compress_params, &err))
internerr("invalid control member compressor params: %s", err.str);
}
diff --git a/dpkg-deb/main.c b/dpkg-deb/main.c
index 3420e44..4405a24 100644
--- a/dpkg-deb/main.c
+++ b/dpkg-deb/main.c
@@ -112,6 +112,8 @@ usage(const struct cmdinfo *cip, const char *value)
" -S<strategy> Set the compression strategy when building.\n"
" Allowed values: none; extreme (xz);\n"
" filtered, huffman, rle, fixed (gzip).\n"
+" --compress-program=<PROG> Use PROG for compression instead of builtin\n"
+" implementation. (must accept level: -0..-9)\n"
"\n"));
printf(_(
@@ -200,6 +202,14 @@ set_compress_type(const struct cmdinfo *cip, const char *value)
badusage(_("obsolete compression type '%s'; use xz or gzip instead"), value);
}
+static void
+set_compress_program(const struct cmdinfo *cip, const char *value)
+{
+ free(compress_params.program);
+ compress_params.program = m_strdup(value);
+}
+
+
static const struct cmdinfo cmdinfos[]= {
ACTION("build", 'b', 0, do_build),
ACTION("contents", 'c', 0, do_contents),
@@ -223,6 +233,7 @@ static const struct cmdinfo cmdinfos[]= {
{ NULL, 'z', 1, NULL, NULL, set_compress_level },
{ NULL, 'Z', 1, NULL, NULL, set_compress_type },
{ NULL, 'S', 1, NULL, NULL, set_compress_strategy },
+ { "compress-program", 0, 1, NULL, NULL, set_compress_program },
{ "showformat", 0, 1, NULL, &showformat, NULL },
{ "help", '?', 0, NULL, NULL, usage },
{ "version", 0, 0, NULL, NULL, printversion },
diff --git a/lib/dpkg/compress.c b/lib/dpkg/compress.c
index 44075cd..7a76a87 100644
--- a/lib/dpkg/compress.c
+++ b/lib/dpkg/compress.c
@@ -20,6 +20,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+
+
+
+
#include <config.h>
#include <compat.h>
@@ -882,6 +886,21 @@ compress_filter(struct compress_params *params, int fd_in, int fd_out,
{
va_list args;
struct varbuf desc = VARBUF_INIT;
+ if (params->program) {
+ struct command cmd;
+ char level[] = "-0";
+
+ command_init(&cmd, params->program, "compress program");
+ command_add_arg(&cmd, params->program);
+
+ level[1] += params->level;
+ command_add_arg(&cmd, level);
+
+ m_dup2(fd_in, STDIN_FILENO);
+ m_dup2(fd_out, STDOUT_FILENO);
+ command_exec(&cmd);
+ }
+
va_start(args, desc_fmt);
varbuf_vprintf(&desc, desc_fmt, args);
diff --git a/lib/dpkg/compress.h b/lib/dpkg/compress.h
index 08aaf25..a629501 100644
--- a/lib/dpkg/compress.h
+++ b/lib/dpkg/compress.h
@@ -57,6 +57,7 @@ enum compressor_strategy {
struct compress_params {
enum compressor_type type;
enum compressor_strategy strategy;
+ char * program ;
int level;
};
實現原理
打包dpkg-deb的時候,壓縮過程它使用的是內置的算法,這個算法是單線程的,無法發揮多核CPU的優勢。
而這個改動,給dpkg-deb加了一個參數。這個參數可以指定一個應用程序,在打包進行到壓縮步驟的時候,調用這個指定的程序進行壓縮。當然,這個程序打包的類型,必須和-Z
指定的類型一致。
我這裏使用的是壓縮率最高的xz格式,這裏指定的外部程序叫做pixz, 這個程序默認會使用最大線程數進行全量壓縮,通過這種辦法曲線救國,實現了dpkg-deb的多線程打包。
一些多線程的壓縮工具pigz/pbzip2/pxz/pixz等等都可以在這裏使用以提高效率。
參考鏈接
這個方案當然也不是我拍腦袋想出來的,還是下載了一個外國人針對舊版本的diff,對着現在的代碼改的,他原文也提到了這種方案最好打打平時的構建包和測試包,如果發佈的話,最好還是老老實實用原版的dpkg-deb。
鏈接1:https://askubuntu.com/questions/841784/any-way-to-multithread-dpkg-deb
鏈接2:https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=501456#27
有能力的小夥伴可以看看這倆鏈接,着實給我打開了新世界的大門。
另外,網上說的什麼fpm
debuild
dpkg-buildpackage
說這個支持多線程打包, 然而這些全都是對dpkg-deb和rpm的封裝,最後還是調用這些工具實現。多線程僅僅在編譯階段是多線程,對於打包可以說卵用沒有。
rpm
deb的這個方案大概折騰了一禮拜。而rpm的方案,折騰了兩個禮拜結論是不可行。。。。
rpm的代碼耦合性比較大,沒有辦法指定第三方的壓縮工具壓縮,底層依賴的cpio的算法進行壓縮,外部工具插不上手。
雖然官方在後續版本,也說實現了多線程打包的功能:https://github.com/rpm-software-management/rpm/issues/211
在4.14版本之後的代碼裏應該就已經帶上了,ubuntu源裏默認安裝的是4.12版本。我下載了最新的源碼編譯安裝後仍然不可行。
最終在github上也得到了rpm項目維護者的確認,這個暫時。。。無法實現。
https://github.com/rpm-software-management/rpm/issues/970
更新一下rpm的解決方案,當時得出無法實現的結論後,同事的大佬找到了另一個issuse,讓我看看這個人說的方法能搞不:https://github.com/rpm-software-management/rpm/issues/113。
我看了一下,還真能。大概意思就是,如果你的本機xz版本是5.2以上的話,可以在執行rpmbuild
命令時指定binary_payload
爲w9T12.xzdio
這樣的方式,這樣它就會使用新版xz的多線程壓縮進行打包。
所以首先:編譯安裝新版xz,ubuntu16.04自帶的是5.1版本的。
wget https://tukaani.org/xz/xz-5.2.4.tar.gz
tar zxvf xz-5.2.4.tar.gz
cd xz-5.2.4
./autogen.sh
./configure
make
sudo make install
報錯我沒記錄,大家遇到啥自行解決一下,都不復雜。
但是替換了xz之後並沒有生效,還需要把rpm重新編譯一下。編譯的時候,必須指定鏈接新的liblzma.so
的庫,這樣打包出來的rpm才能多線程壓縮。修改rpm源碼裏的autogen.sh
成這樣:
#!/bin/sh
export CPPFLAGS="/usr/local/lib/liblzma.so"
export CFLAGS="-I/usr/include/lua5.2 -I/usr/include/nspr -I/usr/include/nss /usr/local/lib/liblzma.so"
export LDFLAGS="-llua5.2"
export LUA_LIBS="-I/usr/lib64"
export LUA_CFLAGS="-I/usr/bin"
autoreconf -i
sed -i "s/sysconfdir='\${prefix}\/etc'/sysconfdir='\/etc'/g" ./configure # 自動生成的configure文件中,sysconfdir的路徑指定的是{$prefix}/etc,打包的時候會有問題,應該改爲/etc
case "$1" in
"--noconfigure")
exit 0;
;;
"--rpmconfigure")
shift
eval "`rpm --eval %configure`" "$@"
;;
*)
./configure "$@" --prefix="/usr"
;;
esac
編譯安裝後,現在的rpmbuild
就支持多線程壓縮了。編譯命令要記得指定w9T12.xzdio
,w後面是壓縮等級,0到9,9最高,T後面是最大線程數,最好和CPU線程數一致,xz是壓縮類型,這裏必須是xz,lzdio
也就是lzma還是隻能單線程。
我在實踐過程中仍然有小問題:
- 在我使用w9T12的時候,CPU最高佔用只有600%,也就是用了6個線程。可我的CPU最高支持12個。
一開始我以爲是它獲取CPU核數錯了,但是後來發現不是。當我使用w6T12的時候,CPU佔用可以達到1200%,w7T12最高1000%,w8T12最高800% 。
經過調查發現這個限制是因爲xz,在xz多線程壓縮的時候,會預先給文件進行分塊,分成幾部分,每一部分一個線程,而壓縮等級爲9的時候,我的原文件只被分成了6個部分,因此最多隻有6個線程同時工作。
xz的文件分塊,和源文件的大小以及壓縮等級有關,最終在我的環境下只分成了6各部分。嘗試分析了xz代碼的這部分邏輯,但是對我而言實在是有點複雜,看了一圈不覺明歷,所以暫時也不會改這個地方。
最終雖然rpm的多線程打包方案不算是一個很完美的解決,但是至少會比以前快出來不少。