利用ldd打造Linux下的綠色軟體包

查志強發表於2014-06-20

【原文:http://www.kongch.com/2010/06/ldd-linux-green-software/

題記:其實這個想法來源於一個同事在之前公司的經驗,感覺不錯,記下來以免忘記。在雲氾濫的今天,如何在雲上快速部署應用其實是一個很有意思的話題。這種方法在我看來除了安裝包比較大坨這一缺點之外,非常適合用來部署雲應用。

眾所周知綠色軟體是windows下的一個概念,指的是僅僅一個資料夾硬copy過來就可以執行的軟體,解除安裝時也同理:刪除這個資料夾即可。說白了就是不會向系統資料夾、登錄檔這些地方亂丟東西的軟體。

Linux下安裝軟體通常是編譯安裝,不同發行版本也有自己的二進位制安裝包,例如RedHat的rpm、Ubuntu的deb等。安裝的最終結果往往也是向/usr/bin, /usr/lib, /usr/sbin…等諸如此類的資料夾下放上自己需要的東東。二進位制包安裝的話,解除安裝起來倒是不麻煩,但如果你是編譯安裝,而想解除安裝時又搞丟了當時的Makefile檔案,那就比較討厭了。有方法可以製作類似於Winodws下的綠色軟體包嗎?

答案是肯定的。我們可以利用ldd來實現這樣的功能。ldd會告訴我們對應二進位制可執行程式所用到的共享庫檔案,我們要做的第一步是在已安裝好完整應用的機器上把這些共享庫檔案拿到。第二步便可以在其他乾淨的機器上利用LD_LIBRARY_PATH指定執行軟體時的動態庫檔案地址,執行對應的二進位制程式。

這裡我寫了一個實現第一步的指令碼:

1 #!/bin/sh
2  
3 if [ $# -ne 1 ]; then
4         echo "You should specify a dynamically executable file"
5         exit 1
6 fi
7  
8 if [ ! -x $1 ]; then
9         echo "You should specify a executable file"
10         exit 1;
11 fi
12  
13 path=$1
14  
15 ############# check file type #############
16 result=$(ldd $path)
17  
18 filter=$(file $path|grep dynamically|grep executable)
19  
20 if [ -z "$filter" ]; then
21         echo "$path is not a dynamically executable file!"
22         file $path
23         exit 1
24 fi
25  
26 ########### mkdir for .so files ############
27 packagename=$(basename $path)-pack
28 mkdir -p $packagename
29  
30 IFS="
31 "
32  
33 ######### copy .so files ############
34 for line in $result; do
35         sofile=notexitsfile
36         if [ -z "$(echo $line | grep =)" ]; then
37                 sofile=$(echo $line | awk '{print $1}')
38         else
39                 # has soft link
40                 sofile=$(echo $line | awk '{print $3}')
41         fi
42  
43         if [ ! -f $sofile ]; then
44                 echo "ERROR FILE: $sofile"
45         else
46                 echo "copying $sofile now..."
47                 cp $sofile $packagename
48         fi
49 done
50  
51 cp $path $packagename
52  
53 echo DONE

這個指令碼的接收二進位制可執行程式的路徑作為引數,利用ldd找到對應的so位置,並將它們連同二進位制可執行程式本身拷貝到一個資料夾中。指令碼正確執行完畢後,這個資料夾就可以拿到其他的乾淨的機器上執行了。

舉個在CentOS5.3上的例子吧,例如我在A機器上已經編譯安裝(或者rpm 安裝)好了ffmpeg。於是乎我就可以執行我的指令碼fetchsofiles.sh,以/usr/bin/ffmpeg作為引數:

1 [root@CT53-64-BASE ~]# ./fetchsofiles.sh /usr/bin/ffmpeg
2 copying /usr/lib64/libpostproc.so.51 now...
3 copying /usr/lib64/libswscale.so.0 now...
4 copying /usr/lib/libavdevice.so.52 now...
5 copying /usr/lib/libavformat.so.52 now...
6 copying /usr/lib/libavcodec.so.52 now...
7 copying /usr/lib/libavutil.so.49 now...
8 copying /lib64/libm.so.6 now...
9 copying /lib64/libpthread.so.0 now...
10 copying /lib64/libc.so.6 now...
11 copying /usr/lib64/libz.so.1 now...
12 copying /lib64/libdl.so.2 now...
13 copying /lib64/ld-linux-x86-64.so.2 now...
14 DONE

看來是正確執行了,現在當前目錄的ffmpeg-pack下就有了:

1 [root@CT53-64-BASE ~]# ls -lh ffmpeg-pack/
2 total 24M
3 -rwx------ 1 root root  85K Jun  7 05:52 ffmpeg
4 -rwx------ 1 root root 137K Jun  7 05:52 ld-linux-x86-64.so.2
5 -rwx------ 1 root root 506K May 19 09:17 libamrnb.so.3
6 -rwx------ 1 root root 392K May 19 09:17 libamrwb.so.3
7 -rwx------ 1 root root 887K May 19 09:17 libasound.so.2
8 -rwx------ 1 root root 4.5M Jun  7 05:52 libavcodec.so.52
9 -rwx------ 1 root root  25K Jun  7 05:52 libavdevice.so.52
10 -rwx------ 1 root root 647K Jun  7 05:52 libavformat.so.52
11 -rwx------ 1 root root  45K Jun  7 05:52 libavutil.so.49
12 -rwx------ 1 root root  67K May 19 09:17 libbz2.so.1
13 -rwx------ 1 root root 1.7M Jun  7 05:52 libc.so.6<strong></strong>
14 -rwx------ 1 root root 3.2M May 19 09:17 libdirac_decoder.so.0
15 -rwx------ 1 root root 4.5M May 19 09:17 libdirac_encoder.so.0
16 -rwx------ 1 root root  23K Jun  7 05:52 libdl.so.2
17 -rwx------ 1 root root 232K May 19 09:17 libfaac.so.0
18 -rwx------ 1 root root 729K May 19 09:17 libfaad.so.2
19 -rwx------ 1 root root  58K May 19 09:17 libgcc_s.so.1
20 -rwx------ 1 root root 955K May 19 09:17 libmp3lame.so.0
21 -rwx------ 1 root root 601K Jun  7 05:52 libm.so.6
22 -rwx------ 1 root root  22K May 19 09:17 libogg.so.0
23 -rwx------ 1 root root  51K Jun  7 05:52 libpostproc.so.51
24 -rwx------ 1 root root 143K Jun  7 05:52 libpthread.so.0
25 -rwx------ 1 root root  53K May 19 09:17 librt.so.1
26 -rwx------ 1 root root 954K May 19 09:17 libstdc++.so.6
27 -rwx------ 1 root root 161K Jun  7 05:52 libswscale.so.0
28 -rwx------ 1 root root 208K May 19 09:17 libtheora.so.0
29 -rwx------ 1 root root 1.1M May 19 09:17 libX11.so.6
30 -rwx------ 1 root root 1.8M May 19 09:17 libx264.so.68
31 -rwx------ 1 root root  12K May 19 09:17 libXau.so.6
32 -rwx------ 1 root root  22K May 19 09:17 libXdmcp.so.6
33 -rwx------ 1 root root  71K May 19 09:17 libXext.so.6
34 -rwx------ 1 root root  84K Jun  7 05:52 libz.so.1

24M,確實不小。我們現在就可以把這個24M的資料夾隨處(*注1)拷貝了,例如我們現在將其拷貝到從來沒有安裝過ffmpeg及其相關依賴的機器B上,執行LD_LIBRARY_PATH=/your_pack_path /your_pack_path/ffmpeg:

1 [root@CT53-64-BASE ~]# cd ffmpeg-pack/
2 [root@CT53-64-BASE ffmpeg-pack]# LD_LIBRARY_PATH=. ./ffmpeg
3 FFmpeg version 0.5, Copyright (c) 2000-2009 Fabrice Bellard, et al.
4   configuration: --prefix=/usr --libdir=/usr/lib64 --shlibdir=/usr/lib64 --mandir=/usr/share/man --incdir=/usr/include --extra-cflags=-fPIC --enable-libamr-nb --enable-libamr-wb --enable-libdirac --enable-libfaac --enable-libfaad --enable-libmp3lame --enable-libtheora --enable-libx264 --enable-gpl --enable-nonfree --enable-postproc --enable-pthreads --enable-shared --enable-swscale --enable-x11grab
5   libavutil     49.15. 0 / 49.15. 0
6   libavcodec    52.20. 0 / 52.20. 1
7   libavformat   52.31. 0 / 52.31. 0
8   libavdevice   52. 1. 0 / 52. 1. 0
9   libswscale     0. 7. 1 /  0. 7. 1
10   libpostproc   51. 2. 0 / 51. 2. 0
11   built on Nov  6 2009 19:11:04, gcc: 4.1.2 20080704 (Red Hat 4.1.2-46)
12 At least one output file must be specified

很幸運,執行成功了!

  • 注1:所謂隨處,並非任意的隨處。必須是相同架構(arch),相同核心版本的機器之間才行。因為注意到這些被拷貝的so有的是架構相關,有的直接就是核心自己的so。

相關文章