
正文共:10830 字 4 圖 預(yù)計(jì)閱讀時(shí)間: 28 分鐘 如果你擁有最高權(quán)限,如果你只管理一臺(tái)服務(wù)器,那么系統(tǒng)自帶的包管理工具就幫你解決了所有問題。但是真實(shí)世界沒有那么美好,所以我花了那么久時(shí)間去學(xué)習(xí)如何從源碼開始編譯一個(gè)軟件。 環(huán)境為CentOS Linux release 7.4.1708 (Core), Linux內(nèi)核version 3.10.0-693.el7.x86_64, GCC版本為4.8.5 20150623 (Red Hat 4.8.5-16) (GCC), GCC安裝 首先讓我們利用系統(tǒng)原來老舊的GCC編譯器編譯出最新版本的gcc吧,畢竟安裝軟件的時(shí)候,GCC的版本一定要過最低要求。 第一步: 下載gcc源碼 mkdir -p ~/src && cd ~/src
wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-7.2.0/gcc-7.2.0.tar.gz
tar -zxvf gcc-7.2.0.tar.gz && cd gcc-7.2.0
ls
 第二步, 檢查系統(tǒng)是否已經(jīng)具備前置軟件, 主要是GMP,MPFR, MPC。這些軟件可以到ftp://gcc./pub/gcc/infrastructure/找到,然后下載后解壓縮,并移動(dòng)到gcc源碼文件夾下。 可以在配置的時(shí)候用 --with-gmp, --with-mpfr --with-mpc 指定具體所在路徑。 cd src
# GNU Multiple precision Library
wget ftp://gcc./pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 \
&& tar -jxvf gmp-6.1.0.tar.bz2 && mv gmp-6.1.0 gcc-7.2.0/gmp
# isl library
wget ftp://gcc./pub/gcc/infrastructure/isl-0.18.tar.bz2 \
&& tar -jxvf isl-0.18.tar.bz2 && mv isl-0.18 gcc-7.2.0/isl
# MPFR Library
wget ftp://gcc./pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 \
&& tar -jxvf mpfr-3.1.4.tar.bz2 && mv mpfr-3.1.4 gcc-7.2.0/mpfr
# MPC Library
wget ftp://gcc./pub/gcc/infrastructure/mpc-1.0.3.tar.gz \
&& tar -zxvf mpc-1.0.3.tar.gz && mv mpc-1.0.3 gcc-7.2.0/mpc
不過更加人性化的方法是在GCC源碼根目錄下運(yùn)行 ./contrib/download_prerequisites ,可以自動(dòng)搞定。 第三步:使用 ./configure 進(jìn)行配置。官方強(qiáng)烈建議, 配置所在文件夾一定要和源碼所在文件夾區(qū)分開,此外configure還可以配置很多參數(shù),我的代碼如下: mkdir build && cd build
../configure\
--prefix=$HOME/usr \ # 指定安裝路徑
--disable-multilib \ # 取消32位庫(kù)編譯
--enable-threads=posix \ # 使用POSIX/Unix98作為線程支持庫(kù)
基本上這一步不會(huì)出現(xiàn)太多的報(bào)錯(cuò),都能夠順利生成Makefile. 第四步: 編譯. 這步有一個(gè)小技巧就是利用多核處理器進(jìn)行加速,例如 make -j2 就是雙核。 這一部分很慢很慢,因?yàn)槟J(rèn)設(shè)置下是3個(gè)階段的引導(dǎo)(3-stage bootstrap), 以保證能夠編譯出完整的GCC系統(tǒng)并且還不會(huì)出錯(cuò),你可以在配置的時(shí)候用 --disable-bootstrap 進(jìn)行關(guān)閉。 第五步: 安裝。如果你編譯都成功了,那么安裝也不會(huì)存在問題了, make install . 那么我們編譯的GCC和系統(tǒng)自帶的有什么區(qū)別嗎? # 從頭編譯
$ $HOME/usr/bin/gcc -v
Using built-in specs.
COLLECT_GCC=/home/zgxu/usr/bin/gcc
COLLECT_LTO_WRAPPER=/home/zgxu/usr/libexec/gcc/x86_64-pc-linux-gnu/7.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/home/zgxu/usr --disable-multilib --enable-threads=posix
Thread model: posix
gcc version 7.2.0 (GCC)
# 系統(tǒng)自帶
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
不談安裝路徑和版本,基本上差別就是在配置這一步,而這些參數(shù)就需要仔細(xì)研究了。 一個(gè)錯(cuò)誤: 'Link tests are not allowed after GCC_NO_EXECUTABLES.' 后來發(fā)現(xiàn)是第三步?jīng)]有在獨(dú)立的文件下構(gòu)建Makefile. 參考資料: Linux的編譯體系無管理員權(quán)限編譯的常規(guī)三部曲是 ./configure --prefix=$HOME/usr && make && make install ,其中最重要的一步就是 configure ,它所做的任務(wù)如下 檢查GCC版本以及是否安裝了編譯所需工具 如果需要頭文件,則默認(rèn)去 /usr/include 查找 如果涉及到動(dòng)態(tài)編譯庫(kù),則默認(rèn)去 /usr/lib 和 /usr/lib64 查找. 注: lib 的函數(shù)庫(kù)僅用于開機(jī)時(shí)用,提供給/bin和/sbin.
那為何需要配置?配置主要解決軟件開發(fā)和軟件實(shí)際安裝時(shí)平臺(tái)不同所導(dǎo)致的問題。 首先,一個(gè)C/C++工程不可能只用到標(biāo)準(zhǔn)庫(kù),很多已有的輪子就不需要重復(fù)制造。其次,由于很多軟件都重復(fù)用到相同的依賴庫(kù),那么如果把這些依賴庫(kù)獨(dú)立成單獨(dú)的模塊,在調(diào)用的時(shí)候加載,也能節(jié)省空間。早期為了適配多個(gè)平臺(tái),開發(fā)人員需要手寫條件語句來檢查環(huán)境依賴,后來GNU專門開發(fā)了Autotools輔助構(gòu)建源碼編譯所需要的關(guān)鍵文件。  編譯環(huán)境變量用 ./configure -h 查看幫助文檔的時(shí)候,會(huì)提示幾個(gè)和編譯相關(guān)非常重要的環(huán)境變量。 # 編譯器
CC 指定C編譯器(compiler command)路徑
CXX 指定C++編譯器
# 編譯器選項(xiàng)
CFLAGS 用于C編譯器的選項(xiàng)
CXXFLAGS 用于C++編譯器的選項(xiàng)
LDFLAGS 鏈接相關(guān)選項(xiàng),如果你有自定義的函數(shù)庫(kù)(lib dir),即可以用 -L<lib dir>指定
# 預(yù)編譯器
CXXCPP C++ 預(yù)處理器(preprocessor)
CPP C 預(yù)處理器(preprocessor)
# 預(yù)編譯器選項(xiàng)
CPPFLAGS C/C++預(yù)處理器選項(xiàng), 如果你自定義的頭文件,可以用-I<include dir>
Makfile規(guī)則中的編譯命令通常遵守如下規(guī)范: 1,首先從源代碼生成目標(biāo)文件(預(yù)處理,編譯,匯編),"-c"選項(xiàng)表示不執(zhí)行鏈接步驟; $(CC) $(CPPFLAGS) $(CFLAGS) example.c -c -o example.o
2,然后將目標(biāo)文件鏈接為最終的結(jié)果(鏈接),"-o"選項(xiàng)用于指定輸出文件的名字。 $(CC) $(LDFLAGS) example.o -o example
這些只是約定俗成的慣例,所以有些人會(huì)“隨性而為”,你也拿他沒有辦法。盡管將源代碼編譯為二進(jìn)制文件的四個(gè)步驟由不同的程序(cpp,gcc/g++,as,ld)完成,但是事實(shí)上 cpp, as, ld 都是由 gcc/g++ 進(jìn)行間接調(diào)用的。換句話說,控制了 gcc/g++ 就等于控制了所有四個(gè)步驟。從 Makefile 規(guī)則中的編譯命令可以看出,編譯工具的行為全靠 CC/CXX CPPFLAGS CFLAGS/CXXFLAGS LDFLAGS 這幾個(gè)變量在控制。所以控制這些變量最簡(jiǎn)單的做法是首先設(shè)置與這些 Makefile 變量同名的環(huán)境變量并將它們 export 為環(huán)境變量(全局),然后運(yùn)行 configure 腳本,大多數(shù) configure 腳本會(huì)使用這同名的環(huán)境變量代替 Makefile 中的值 CC/CXX: 指定C/C++編譯所在路徑,即可以選擇不同的版本的編譯器進(jìn)行編譯。 CPPFLAGS: 這是用于預(yù)處理階段的選項(xiàng)。用于添加不在標(biāo)準(zhǔn)路徑 /usr/include 下的頭文件。如 CPPFLAGS="-I$HOME/usr/include -I$HOME/usr/include/ncurses" CFLAGS/CXXFLAGS: 指定頭文件(.h文件)的路徑,如: CFLAGS=-I/usr/include -I/path/include 。同樣地,安裝一個(gè)包時(shí)會(huì)在安裝路徑下建立一個(gè)include目錄,當(dāng)安裝過程中出現(xiàn)問題時(shí),試著把以前安裝的包的include目錄加入到該變量中來。
CPPFLAG和CFLAGS/CXXFLAGS這兩個(gè)變量可以認(rèn)為是等價(jià)關(guān)系,都用在預(yù)處理階段,也就是都能用于指定頭文件所在位置。
有時(shí)候LDFLAGS指定-L雖然能讓鏈接器找到庫(kù)進(jìn)行鏈接,但是運(yùn)行時(shí)鏈接器卻找不到這個(gè)庫(kù),如果要讓軟件運(yùn)行時(shí)庫(kù)文件的路徑也得到擴(kuò)展,那么我們需要增加這兩個(gè)庫(kù)給"-Wl,R": LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib
如在執(zhí)行./configure以前設(shè)置環(huán)境變量 export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意設(shè)置環(huán)境變量等號(hào)兩邊不可以有空格,而且要加上引號(hào)(shell的用法)。那么執(zhí)行configure以后,Makefile將會(huì)設(shè)置這個(gè)選項(xiàng),鏈接時(shí)會(huì)有這個(gè)參數(shù),編譯出來的可執(zhí)行程序的庫(kù)文件搜索路徑就得到擴(kuò)展了 除了通過以上幾種環(huán)境變量為編譯器提供頭文件和靜態(tài)和動(dòng)態(tài)庫(kù)文件的位置信息外,還有一種變量叫做PKG_CONFIG_PATH, 它從 xx.pc 文件獲取讀取相應(yīng)的環(huán)境環(huán)境。 注意:Linux下編譯共享庫(kù)時(shí),必須加上-fPIC參數(shù),即 export CFLAGS=" -fPIC" CXXFLAGS=" -fPIC" 否則在鏈接時(shí)會(huì)有錯(cuò)誤提示.這是在編譯zsh時(shí)候發(fā)現(xiàn)明明裝了ncurse卻還是不能用的共享庫(kù)的坑。 fPIC的目的是什么?共享對(duì)象可能會(huì)被不同的進(jìn)程加載到不同的位置上,如果共享對(duì)象中的指令使用了絕對(duì)地址、外部模塊地址,那么在共享對(duì)象被加載時(shí)就必須根據(jù)相關(guān)模塊的加載位置對(duì)這個(gè)地址做調(diào)整,也就是修改這些地址,讓它在對(duì)應(yīng)進(jìn)程中能正確訪問,而被修改到的段就不能實(shí)現(xiàn)多進(jìn)程共享一份物理內(nèi)存,它們?cè)诿總€(gè)進(jìn)程中都必須有一份物理內(nèi)存的拷貝。fPIC指令就是為了讓使用到同一個(gè)共享對(duì)象的多個(gè)進(jìn)程能盡可能多的共享物理內(nèi)存,它背后把那些涉及到絕對(duì)地址、外部模塊地址訪問的地方都抽離出來,保證代碼段的內(nèi)容可以多進(jìn)程相同,實(shí)現(xiàn)共享。
參考資料: 幾個(gè)必須要裝的函數(shù)庫(kù)在安裝之前需要先聲明幾個(gè)環(huán)境變量,可以直接添加在配置文件中。這都是后面遇到共享庫(kù)的問題得到的經(jīng)驗(yàn)教訓(xùn)。 export CFLAGS=" -fPIC"
export CXXFLAGS=" -fPIC"
export CPPFLAGS="-I$HOME/usr/include -I$HOME/usr/include/ncurses -I$HOME/usr/include/X11"
export LDFLAGS="-L$HOME/usr/lib -L$HOME/usr/lib64"
export LD_LIBRARY_PATH=$HOME/usr/lib:$HOME/usr/lib64
export PKG_CONFIG_PATH=$HOME/usr/lib/pkgconfig:$HOME/usr/share/pkgconfig
ncurses提供了一系列的函數(shù)以便使用者調(diào)用它們?nèi)ド苫谖谋镜挠脩艚缑妫S多大名鼎鼎的軟件都用到了ncurses,例如vim, screen,tmux,zsh等。并且samtools如果需要tview可視化BAM文件,也需要這個(gè)庫(kù)做支持。 wget ftp://ftp.invisible-island.net/ncurses/ncurses.tar.gz && tar -zxvf ncurses.tar.gz
./configure --enable-shared --prefix=$HOME/usr
make && make install
Libevent是一個(gè)用C語言編寫的、輕量級(jí)的開源高性能事件通知庫(kù), 后續(xù)安裝tmux時(shí)候需要這個(gè)依賴庫(kù)。 # libevent
cd src
wget https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz
tar -zxvf libevent-2.1.8-stable.tar.gz && cd libevent-2.1.8
./configure prefix=$HOME/usr && make && make install
bzip2, xz, zlib: 文件壓縮相關(guān)函數(shù)庫(kù),后續(xù)samtools編譯時(shí)需要。 wget http://www.zlib.net/zlib-1.2.11.tar.gz
tar -zxvf zlib-1.2.11.tar.gz && cd zlib-1.2.11 && ./configure --prefix=$HOME/usr && make && make install
wget http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
tar -zxvf bzip2-1.0.6.tar.gz && cd bzip2-1.0.6 && ./configure --prefix=$HOME/usr && make && make install
wget https://tukaani.org/xz/xz-5.2.3.tar.gz
tar -zxvf xz-5.2.3.tar.gz && cd xz-5.2.3 && ./configure --prefix=$HOME/usr && make && make install
openssl, libssh2, libcurl: 計(jì)算機(jī)之間文件傳輸訪問相關(guān)庫(kù)。其中OpenSSL是一個(gè)安全套接字層密碼庫(kù),囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL協(xié)議,并提供豐富的應(yīng)用程序供測(cè)試或其它目的使用。libssh2是一個(gè)C 函數(shù)庫(kù),用來實(shí)現(xiàn)SSH2協(xié)議。libcurl主要功能就是用不同的協(xié)議連接和溝通不同的服務(wù)器. # 安裝有先后
# openssl
wget https://www.openssl.org/source/openssl-1.0.2m.tar.gz
tar -zxvf openssl-1.0.2m.tar.gz && cd openssl-1.0.2m
# 這里非常神奇的居然是config,添加shared生成動(dòng)態(tài)庫(kù)
./config prefix=$HOME/usr shared
make && make install
# 卸載使用 make clean
# libssh2
wget https://www.libssh2.org/download/libssh2-1.8.0.tar.gz
tar -zxvf libssh2-1.8.0.tar.gz && cd libssh2-1.8.0
./configure --with-libssl-prefix=$HOME/usr/ssl --prefix=$HOME/usr
# libcurl
wget https://curl.haxx.se/download/curl-7.56.1.tar.gz
tar -zxvf curl-7.56.1.tar.gz && cd curl-7.56.1
./configure --prefix=$HOME/usr --enable-http --enable-ftp --enable-file --enable-proxy --enable-telnet --enable-libcurl-option --enable-ipv6 --with-lib --with-ssl
readline: GNU提供用于這些命令補(bǔ)全、搜索歷史命令、行編輯快捷鍵等等這些人性化的交互方式的函數(shù)庫(kù),缺少這個(gè)標(biāo)準(zhǔn)庫(kù),編譯的R就缺少自動(dòng)補(bǔ)全的功能。 wget http://ftp./gnu/readline/readline-7.0.tar.gz
tar -zxvf readline-7.0.tar.gz && cd readline-7.0
./configure --prefix=$HOME/usr && make && make install
PCRE: 提供和Perl5相同語法和語義正則表達(dá)式的函數(shù)庫(kù),后續(xù)安裝R用到。 wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.41.tar.gz
tar -zxvf pcre-8.41.tar.gz && cd pcre-8.41
./configure --enable-utf --enable-pcregrep-libz --enable-pcregrep-libbz2 --prefix=$HOME/usr
x11:X11也叫做X Window系統(tǒng),X Window系統(tǒng) (X11或X)是一種位圖顯示的視窗系統(tǒng),是在 Unix 和 類Unix 操作系統(tǒng),以及OpenVMS上建立圖形用戶界面的標(biāo)準(zhǔn)工具包和協(xié)議,并可用于幾乎所有已有的現(xiàn)代操作系統(tǒng)。主要是R編譯的時(shí)候要用,具體用途有待開發(fā)。 x11安裝比較復(fù)雜,有很多的依賴庫(kù),因此需要先安裝xtrans, xextproto, xcb(lib,xcb-proto, libpthread-subs), kbproto,xproto,inputproto。但是編譯很容易,僅提供下載鏈接 https://www.x.org/releases/X11R7.7/src/lib/xtrans-1.2.7.tar.gz
https://www.x.org/releases/X11R7.7/src/proto/xextproto-7.2.1.tar.gz
https://www.x.org/releases/X11R7.7/src/proto/kbproto-1.0.6.tar.gz
https://www.x.org/releases/X11R7.7/src/proto/xproto-7.0.23.tar.gz
https://www.x.org/releases/X11R7.7/src/proto/inputproto-2.2.tar.gz
https://www.x.org/releases/X11R7.7/src/xcb/libpthread-stubs-0.3.tar.gz
https://www.x.org/releases/X11R7.7/src/xcb/xcb-proto-1.7.1.tar.gz
https://www.x.org/releases/X11R7.7/src/xcb/libxcb-1.8.1.tar.gz
https://www.x.org/releases/X11R7.7/src/lib/libSM-1.2.1.tar.gz
https://www.x.org/releases/X11R7.7/src/lib/libICE-1.0.8.tar.gz
https://www.x.org/releases/X11R7.7/src/lib/libXt-1.1.3.tar.gz
相當(dāng)于人工檢查依賴環(huán)境,僅僅是繁瑣而已,并不困難 # 安裝X11
wget -4 https://www.x.org/releases/X11R7.7/src/lib/libX11-1.5.0.tar.gz
tar -zxvf libX11-1.5.0.tar.gz && cd libX11-1.5.0
./configure --prefix=$HOME/usr && make && make install
zsh或許可以認(rèn)為是最好的shell,用過zsh的人都不會(huì)想著bash了。不過zsh自定義配置,可供選擇的插件以及主題實(shí)在是太多,因此一定要搭配oh-my-zsh。zsh依賴ncurses. wget -O zsh.tar.gz https://sourceforge.net/projects/zsh/files/latest/download
tar -zxvf zsh.tar.gz && cd zsh
export CPPFLAGS="-I$HOME/usr/include/" LDFLAGS="-L$HOME/usr/lib"
../configure --prefix=$HOME/usr --enable-shared
make && make install
由于沒有root權(quán)限,無法使用 chsh ,只能通過在 ~/.bashrc 添加 exec $HOME/usr/bin/zsh -l 保證登陸的時(shí)候自動(dòng)切換成zsh。其次, zsh搭配oh-my-zsh才完整, 只不過這里只能手動(dòng)安裝了。 # 從github上克隆oh-my-zsh
git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
# 用oh-my-zsh的zsh配置文件替代
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zhsrc
# 安裝一些字體, 不然一些主題會(huì)顯示異常
cd src
git clone https://github.com/powerline/fonts.git --depth=1
cd fonts && ./install.sh
重啟一下終端,后面根據(jù)需要調(diào)整配置文件里的參數(shù)。 tmux和screen類似,也是文本終端神器, 依賴于libevent和ncurses. export CPPFLAGS="-I$HOME/usr/include -I$HOME/usr/include/ncurses"
export LDFLAGS="-L$HOME/usr/lib -L$HOME/usr/lib64"
mkdir -p src && cd src
git clone https://github.com/tmux/tmux.git
cd tmux
sh autogen.sh
./configure --prefix=$HOME/usr
make && make install
由于我自己編譯完全版的GCC套餐,很多之前的gfortran不存在的問題也就不存在了(管理員安裝了Java)。此外,R還需要gnu readline, pcre > 8.2, x11。當(dāng)然這些函數(shù)包都在之前安裝好了。 wget https://cran.r-project.org/src/base/R-3/R-3.4.2.tar.gz
tar -zxvf R-3.4.2.tar.gz && cd R-3.4.2/
./configure --prefix=$HOME/R
make && make install
R configure到此,我可以說Linux平臺(tái)下即便我沒有root權(quán)限,也沒有多少軟件包是我所不能手工編譯。 如果你用過conda,你可能會(huì)好奇為啥我不用conda安裝這些軟件?
|