1. 程式人生 > >Linux系統程式從編譯到二進位制安裝

Linux系統程式從編譯到二進位制安裝

很長一段時間以來,安裝 LAMP 時都是編譯安裝其資料庫(MySQL,MariaDB,Percona Server)的。這是一個非常耗時的過程,而且編譯安裝的版本,很多外掛預設是不會被編譯安裝的。

偶然間在 MariaDB 的下載列表裡,看到有適用於 Linux 下的二進位制安裝包。於是就研究了一下,發現其二進位制包分為 2 個版本:GLIBC_2.14 及 GLIBC_2.14+,解壓其安裝包後,稍微設定一下就可以直接使用了。
這大大提高了安裝效率,安裝速度只取決於從伺服器下載二進位制包的速度。
於是我在腳本里先做判斷系統裡安裝的 GNU_LIBC_VERSION 是多少,2.14 是一道分界線,這也決定著下載連結是怎樣的。
 
一、


 
MariaDB 5.5, MariaDB 10.0, MariaDB 10.1 一直都是這麼安裝的,直到 MariaDB 10.2 的出現,讓我頭疼的一件事出現了。
本來以為只要安裝好了 MariaDB 10.2,後面編譯 PHP 會非常順利,結果一開始 configure 的時候就出錯了。

checking for mysql_set_server_option in -lmysqlclient... no
configure: error: wrong mysql library version or lib not found. Check config.log for more information.

這個錯誤提示太熟悉了,缺少了 libmysqlclient.so, libmysqlclient.a,於是我就去 MariaDB 安裝目錄下的 lib 裡一看,發現果然跟Percona Server 一樣改名了。
看起來 libmariadbclient.a, libmariadb.so.3 這兩個檔案最相似。
做了 symbolic link 後,將 libmysqlclient.a 指向為 libmariadbclient.a,libmysqlclient.so 指向為 libmariadb.so.3,繼續編譯 PHP。
果然 configure 沒問題了,喜滋滋地等待編譯完成。當編譯到 mysqli 模組時,異常退出。

mysqli.c: In function 'zm_info_mysqli':
mysqli.c:990: error: 'MYSQL_SERVER_VERSION' undeclared (first use in this function)
mysqli.c:990: error: (Each undeclared identifier is reported only once
mysqli.c:990: error: for each function it appears in.)

What?這難道是 MariaDB 的標頭檔案裡未定義 MYSQL_SERVER_VERSION 變數?
去 MariaDB 安裝目錄下的 include/mysql 裡 grep 一下所有的 .h 檔案,發現 MYSQL_SERVER_VERSION 被定義在 mysql_version.h 裡。
扒了一下 PHP 原始碼裡的 ext/mysqli 下的 mysqli.c,一路找到 php_mysqli_structs.h 檔案裡 include 了 my_global.h,又在 my_global.h 裡看到 include 了 my_config.h。
最後我在 my_config.h 裡確實沒有看到 MYSQL_SERVER_VERSION 變數被定義。
然後,我手動修改了一下 my_global.h,在原來 #include <my_config.h> 後面加了一行 #include <mysql_version.h>。然後繼續編譯 PHP。
果然,不再出現 MYSQL_SERVER_VERSION 變數的問題,然而,結果還是 boom,錯誤提示如下:

mysqli_nonapi.c: In function 'mysqli_common_connect':
mysqli_nonapi.c:266: error: 'MYSQL' has no member named 'reconnect'
mysqli_nonapi.c: In function 'zif_mysqli_error_list':
mysqli_nonapi.c:448: warning: passing argument 4 of 'add_assoc_string_ex' discards qualifiers from pointer target type

然後,我就發現我搞不定這個問題。
於是我從 LAMP 腳本里去掉了安裝 MariaDB 10.2 這個選項。

2017 年 7 月 18 日更新
MariaDB 10.2.7 恢復了 libmysqlclient.so,與 Percona 一樣是 symbolic link,同時也在標頭檔案里加入了 MYSQL_VERSION_ID 定義。然而我測試了一下,還是會出現 configure: error: wrong mysql library version or lib not found. Check config.log for more information.
PHP 的編譯選項只能從

--with-mysqli=/usr/local/mariadb/bin/mysql_config --with-pdo-mysql=/usr/local/mariadb

改為

--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd

即 MySQL native driver。
 
二、
 
有了二進位制安裝 MariaDB 的經驗,直覺告訴我 MySQL 肯定也有二進位制包,去官網一看,果然有的。
Oracle 將 MySQL 的二進位制安裝包命名為 Linux – Generic。對於 GNU_LIBC_VERSION,只要求 GLIBC_2.5 即可安裝(正在開發的 MySQL 8.0 則需 GLIBC_2.12)
安裝過程與 MariaDB 類似,唯一的區別是 MySQL 5.7 開始,不再使用 mysql_install_db 來初始化安裝資料庫,而是使用 mysqld –initialize-insecure 來安裝。
與此同時,MySQL 5.7 的預設資料庫 mysql 中的 user 表結構也發生了若干變化,去掉了 Password 列,將密碼 hash 儲存在 authentication_string 列等等。而這又導致了低版本的 phpMyAdmin 如 4.4 無法正確識別資料庫裡的所有使用者。

基本上,Percona Server 遵循著和 MySQL 一樣的節奏,比如 5.7 開始使用 mysqld –initialize-insecure 來初始化,除了版本號。
Percona Server 有著自己獨特的版本號。在主版本號之外,還有個 rel 版本號。5.5 和 5.6 使用的 rel 版本號帶小數點,比如 5.6.36-82.0。而 5.7 則沒有,比如 5.7.18-15。
沒錯,Percona Server 也提供了二進位制安裝包。但是它也有自己的風格,是不一樣的煙火。
Percona Server 對二進位制包的 openssl 版本作了嚴格的區分。比如檔名含 ssl100 適用於所有的 Debian/Ubuntu 版本,而 ssl101 只適用於 CentOS 6 和 CentOS 7。
Percona Server 的個性遠不止於此。
你以為解壓了這個二進位制包就萬事大吉了嗎?它的安裝目錄和壓縮包名一樣長!
安裝目錄下的 bin/mysqld_safe 和 bin/mysql_config 裡也包含了和檔名一樣的路徑名,而且是 hard path,這就意味著如果直接解壓到某個安裝資料夾下,是無法初始化和啟動的。
必須要先將這兩個檔案裡的路徑替換為實際安裝路徑才可以。
與此同時,安裝目錄的 lib 目錄下,並沒有 libmysqlclient.so 和 libmysqlclient.a,而是叫 libperconaserverclient.so 和 libperconaserverclient.a。
因此需要建立 symbolic link 後才能被 PHP 識別和編譯。
 
三、
 
通過二進位制安裝資料庫後,再通過 phpMyAdmin 登入,你會發現多了一個 Plugins Tab,點進去會顯示很多外掛,大體上分為 3 類:AUTHENTICATION, INFORMATION SCHEMA, STORAGE ENGINE。而通過編譯安裝的資料庫就沒有這些。
這讓我想起了一個比喻:微軟的 Windows 會直接給你一個蛋糕,你直接吃就好了,沒得挑;而 Linux 會給你麵粉,雞蛋,黃油,水,蘇打粉等,好了,你去編譯一個自定義的蛋糕吧。
事實上,為什麼不多提供一個選項,讓喜歡吃蛋糕的人,既可以選成品,也可以選用原材料來自己做一個?
二進位制包就是這樣的一個成品。如果可以的話,其實我也想選擇 Apache, PHP 最新版的二進位制包,然而並沒有,所以只好自己編譯了。各個作業系統發行版自帶的版本往往都是其中的某個大版本,然後不斷更新也不會變,少了很多選擇的樂趣。