天天學五分鐘 Liunx 1000 | 軟件篇:源碼安裝


軟件安裝流程

前面軟件篇提到了經過 RPM 和 YUM 在線安裝的機制安裝軟件,除了這兩種方式以外還有一種經過源碼來安裝軟件的方式。
 
如上流程圖所示,程序員使用特定語言(c/c++/...)編寫源文件,經過編譯器翻譯成機器能夠執行的可執行文件,也就是二進制文件。其中,若是源文件依賴函數庫的話,在編譯的時候還須要將相應的函數庫給連接上。
 
 
走一遍操做的流程看看程序是怎麼從源文件到可執行文件的。
編寫源文件 hello.cpp 和 thanks.cpp,其中 hello.cpp 引用 thanks.cpp 的函數:
[root@lianhua tarball]$ cat hello.cpp
#include <stdio.h>
#include "thanks.h"
 
int main(void)
{
    printf("Hello World\n");
    thanks();
 
    return 0;
}
[root@lianhua tarball]$ cat thanks.cpp
#include <stdio.h>
 
int thanks(void)
{
    printf("thanks lianhua, I love you\n");
 
    return 0;
}
[root@lianhua tarball]$ cat thanks.h
int thanks();
 
源文件有了,使用 Liunx 自帶的 c/c++ 編譯器 gcc 編譯源文件:
[root@lianhua tarball]$ gcc -c hello.cpp
[root@lianhua tarball]$ ll
total 16
-rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
-rw-r--r-- 1 root root 1560 May 10 22:45 hello.o
-rw-r--r-- 1 root root   80 May 10 22:45 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
[root@lianhua tarball]$ gcc -o hello hello.o
hello.o: In function `main':
hello.cpp:(.text+0xf): undefined reference to `thanks()'
collect2: error: ld returned 1 exit status
 
報錯,顯示函數 thanks 沒定義。出錯緣由是由於 hello.cpp 引用到了該函數,可是編譯的時候沒有連接,因此對症下藥:
[root@lianhua tarball]$ gcc -c hello.cpp thanks.cpp
[root@lianhua tarball]$ ll
total 20
-rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
-rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
-rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
-rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
[root@lianhua tarball]$ gcc -o hello hello.o thanks.o
[root@lianhua tarball]$ ll
total 32
-rwxr-xr-x 1 root root 8552 May 10 22:47 hello
-rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
-rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
-rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
-rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
[root@lianhua tarball]$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=1801febeffa3328a578dac21ee994dd50893ed3f, not stripped
[root@lianhua tarball]$ ./hello
Hello World
thanks lianhua, I love you
 
能夠看到,將 thanks.cpp 編譯成目標文件 thanks.o,而後連接到該目標文件生成了可執行的二進制文件 hello。其中,file 命令能夠判斷文件是二進制文件或通常文本文件。
 
 
這是一種生成可執行文件的方式,還有一種提供函數庫給編譯器編譯的方式。
函數庫分兩種靜態函數庫和動態函數庫,靜態函數庫在編譯的時候被放到可執行文件中,動態函數庫在編譯的時候會建立「指針」指向該動態函數庫。因此,使用靜態函數庫的可執行文件要比使用動態函數庫的可執行文件大。可是基於靜態函數庫的可執行文件在編譯完以後就不依賴於庫,放到哪均可以執行,基於動態函數庫的可執行文件則不行,它須要能引用到該動態函數庫。

靜態函數庫的可執行文件

[root@lianhua tarball]$ ar rcs liblianhua.a thanks.o
[root@lianhua tarball]$ ll
total 36
...
-rw-r--r-- 1 root root 1668 May 10 23:09 liblianhua.a
[root@lianhua tarball]$ gcc hello.cpp -llianhua -L/root/hxia/tarball
[root@lianhua tarball]$ gcc hello.cpp -llianhua -L/root/hxia/tarball -o lianhua
[root@lianhua tarball]$ ll
total 60
-rwxr-xr-x 1 root root 8552 May 10 22:47 hello
-rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
-rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
-rwxr-xr-x 1 root root 8552 May 10 23:11 lianhua
-rw-r--r-- 1 root root 1668 May 10 23:09 liblianhua.a
-rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
-rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
[root@lianhua tarball]$ ./lianhua
Hello World
thanks lianhua, I love you
 
經過 ar 命令將 thanks.o 生成爲 lianhua 的靜態函數庫,編譯器連接該靜態函數庫生成可執行的二進制文件 lianhua。其中,靜態函數庫以 .a 結尾,動態函數庫以 .so 結尾。

動態函數庫的可執行文件

[root@lianhua shared]$ gcc -fPIC -shared thanks.cpp -o liblianhua.so
[root@lianhua shared]$ ll
total 20
-rw-r--r-- 1 root root  117 May 10 23:18 hello.cpp
-rwxr-xr-x 1 root root 8112 May 10 23:20 liblianhua.so
-rw-r--r-- 1 root root  100 May 10 23:18 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 23:18 thanks.h
[root@lianhua shared]$ gcc hello.cpp -L. -llianhua -o hello
[root@lianhua shared]$ ll
total 32
-rwxr-xr-x 1 root root 8528 May 10 23:21 hello
-rw-r--r-- 1 root root  117 May 10 23:18 hello.cpp
-rwxr-xr-x 1 root root 8112 May 10 23:20 liblianhua.so
-rw-r--r-- 1 root root  100 May 10 23:18 thanks.cpp
-rw-r--r-- 1 root root   14 May 10 23:18 thanks.h
[root@lianhua shared]$ ./hello
./hello: error while loading shared libraries: liblianhua.so: cannot open shared object file: No such file or directory
 
命令 gcc -fPIC -shared 將 thanks.cpp 編譯成動態函數庫 lianhua,生成可執行文件 hello。可是,在執行 hello 的時候報錯了,提示找不到 lianhua 這個動態函數庫。錯誤緣由是動態連接時默認從 /usr/lib 目錄下找動態函數庫,將 lianhua 拷到該目錄下,更新配置:
[root@lianhua shared]$ cp libthanks.so /usr/lib/
[root@lianhua shared]$ vi /etc/ld.so.conf
[root@lianhua shared]$ ldconfig
[root@lianhua shared]$ ./hello
Hello World
thanks lianhua, I love you
 
ldconfig 命令將動態函數庫從硬盤加載到內存中,這樣執行可執行文件的時候執行引用內存中的動態函數庫,速度會快不少。
 
Liunx 的 ldd 命令能夠查看可執行文件引用了哪些動態函數庫:
[root@lianhua tarball]$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffcc9bec000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f4175126000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f41754f3000)
[root@lianhua tarball]$ ldd ./shared/hello
        linux-vdso.so.1 =>  (0x00007fff7d9da000)
        libthanks.so => /lib/libthanks.so (0x00007f6896b53000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f6896786000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6896d55000)
能夠發現基於動態函數庫的 hello 指向了 thanks 這個庫。同時,比較兩個可執行文件大小也會發現基於靜態函數庫的可執行文件 hello 要比基於動態函數庫的可執行文件要大。
 
 
想象下,這是隻有一個函數的編譯狀況,在實際項目中有成百上千上萬個函數,各個函數分佈在不一樣的目錄這時候在用這種 gcc 指定函數庫編譯的方式就特別不適用了。
在這種狀況下,會寫 cmake 文件定義編譯規則,每一個目錄下都有 cmake 文件。再執行 cmake 命令生成 makefile 文件,而後經過 make 命令就能根據 makefile 中的規則編譯生成可執行文件。
 
具體這個流程實操不介紹了,有興趣的看看這個文檔
 
 
 
(完)
相關文章
相關標籤/搜索