centos7安裝node-v18版本真是難呢

2023-10-26 06:00:42

背景

背景就是上一篇文章提到的,部署gitbook這個檔案中心的話,是需要先安裝node,然後,如果你的node版本過高的話,一般會報錯,此時,網上很多文章就是降node版本解決,但其實用高版本也是有辦法的,只是麻煩點,要改改程式碼;但是,我下載了高版本的node安裝時,發現在centos7上還裝不了,可謂一波未平一波又起。

報錯的nodejs版本:v18,我這邊具體的是node-v18.18.2-linux-x64.tar.xz

伺服器版本是centos 7.6,centos 7.9(兩個都試了)

下面這個問題可以看下:

https://stackoverflow.com/questions/72571235/can-i-install-node-js-18-on-centos-7-and-do-i-need-python-3-install-too#:~:text=Starting v18%2C Node.,due to glibc version incompatibility.

https://github.com/nodejs/node/issues/43246

吵得還是挺厲害。我覺得也是比較坑的是,下載的時候,檔案也沒個提示,比如是否在centos7上可用,等到弄下來搞出一堆問題了上網去找才知道版本不相容。

下面具體說下這個問題。

問題原因分析

tar -xvf node-v18.18.2-linux-x64.tar.xz 
cd node-v18.18.2-linux-x64/

[root@VM-0-6-centos node-v18.18.2-linux-x64]# bin/node 
bin/node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by bin/node)
bin/node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by bin/node)
bin/node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by bin/node)
bin/node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by bin/node)
bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by bin/node)
bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by bin/node)

這個報錯,是這個意思,node在執行的時候,是依賴了一些動態庫的,依賴了哪些呢:

[root@VM-0-6-centos node-v18.18.2-linux-x64]# ldd bin/node 
        linux-vdso.so.1 =>  (0x00007fff34927000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fd57af20000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fd57ac19000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fd57a917000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd57a701000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd57a4e5000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fd57a117000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd57b124000)

在 => 這個符號左側,就是依賴的動態庫名字,右側,就是根據這個名字,在環境變數LD_LIBRARY_PATH指定的路徑下查詢,最終解析到的動態庫全路徑。

那我們再來看第一行報錯:

[root@VM-0-6-centos node-v18.18.2-linux-x64]# bin/node 
bin/node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by bin/node)

/lib64/libm.so.6這個是全路徑,看起來找到了,但是還是報錯,好像說要在GLIBC_2.27這個版本沒找到。

我們可以這樣,在執行ldd時打個詳細紀錄檔:

[root@VM-0-6-centos]# ldd -v bin/node 
Version information:
        bin/node:
                ...
                libm.so.6 (GLIBC_2.27) => not found
                libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6

看起來,它是找libm.so.6(GLIBC_2.27)沒找到,但找到了libm.so.6 (GLIBC_2.2.5)。

這塊其實是這樣,核心提供給使用者的是系統呼叫(system call),但是,在我們編寫c語言程式碼時,一般不是直接去呼叫這些系統呼叫,而是會include一些標頭檔案,如include <stdio.h>,這些標頭檔案算是介面,這些介面包括其實現,最終編譯成二進位制打成一個庫,供使用者使用。最早是標準的libc庫,後來逐漸被glibc這個取代,glibc是GNU釋出的libc庫,官網:https://www.gnu.org/software/libc/libc.html

這個glibc庫,比如在我的centos7.6上,到底在啥位置呢?

我先看了下本機的glibc版本是2.17:

https://lindevs.com/check-glibc-version-in-linux
方法1:
[root@VM-0-6-centos lib64]# ldd --version
ldd (GNU libc) 2.17

方法2:
[root@VM-0-6-centos lib64]# ldd `which cat` | grep libc
        libc.so.6 => /lib64/libc.so.6 (0x00007f27331c8000)
[root@VM-0-6-centos lib64]# /lib64/libc.so.6
GNU C Library (GNU libc) stable release version 2.17, by Roland McGrath et al.

glibc一般也是有rpm包的,我在這個網站上找到了2.17版本的x86-64的glibc的包:

https://rpmfind.net/linux/RPM/centos/updates/7.9.2009/x86_64/Packages/glibc-2.17-326.el7_9.x86_64.html

可以看到,它其實包含了非常多檔案,其中就有/lib64/libm.so.6:

那我意思其實就是,/lib64/libm.so.6就是glibc的一部分,那這個2.17版本的glibc,包含的/lib64/libm.so.6報的這個錯到底啥意思啊?

[root@VM-0-6-centos]# ldd -v bin/node 
Version information:
        bin/node:
                ...
                libm.so.6 (GLIBC_2.27) => not found
                libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6

我找到了一個絕好的回答:

https://unix.stackexchange.com/questions/458659/what-do-the-multiple-glibc-versions-mean-in-the-output-of-ldd

GLIBC_..., GLIBCXX_... etc. are version symbols, which are used in some libraries (including the GNU C library and the GCC libraries) to identify required versions and to manage backward compatibility. A binary (executable or library) will usually end up requiring multiple versions, based on the symbols it really uses from the target library. To satisfy the requirements of a given binary, you need to provide a library which supports all the required versions — i.e. a library matching at least the highest version symbol in the list of requirements.

翻譯過來是,GLIBC_...GLIBCXX_...是版本符號,在某些庫(包括GNU C庫和GCC庫)中使用它們來標識所需的版本並管理向後相容性。二進位制檔案(可執行檔案或庫)通常最終需要多個版本,具體取決於它實際使用的目標庫中的符號。為了滿足給定二進位制檔案的要求,您需要提供一個支援所有所需版本的庫 -至少匹配要求列表中最高版本符號的庫。

The reason multiple versions can end up being required, is that each imported object (function etc.) can have a version, and a given binary can link against multiple versions across all the functions it uses. 

翻譯:最終可能需要多個版本的原因是每個匯入的物件(函數等)都可以有一個版本,並且給定的二進位制檔案可以連結到它使用的所有函數的多個版本。

我這裡也只擷取了一部分,大家還是去看原文吧,反正意思就是,比如node這個程式,它就是會用到/lib64/libm.so.6裡面不同version symbol的函數,你需要做的,就是滿足它,否則,它就報錯。

怎麼滿足它呢,就是把/lib64/libm.so.6的版本升上去,直到包含GLIBC_2.27這個version symbol。

那怎麼才能升/lib64/libm.so.6上去呢,那它既然是glibc的一部分,自然是隻能整體升級glibc到指定版本,比如這裡的GLIBC_2.27

解決-升級GLIBC

這裡參考了文章:

https://mp.weixin.qq.com/s/Xhm_BmMH2EoVWMPRWfCnaw

跟我遇到的坑差不多。文章裡1、安裝編譯環境devtoolset-8那部分應該不需要特別關注,我覺得也不用操作,因為這種偷懶方式安裝的gcc,是解決不了node安裝報錯的問題的,往下看就知道了。

開始升級glibc,值得注意的是,大家最好是虛擬機器器、個人的雲主機先玩一玩,不要拿著有其他人在用的環境搞這些,很容易把機器徹底搞到不能收場的地步;玩之前也記得備份,比如先複製一個虛擬機器器出去

慢的話,可以自己手動下載再上傳
wget https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz --no-check-certificate

tar -xzvf glibc-2.28.tar.gz

cd glibc-2.28

mkdir build && cd build (一定要單獨建個資料夾來build)

在編譯開始前,修改 scripts/test-installation.pl 128行,增加 && $name ne "nss_test2" ,以避免編譯錯誤 nss_test2報錯,反正就是照著加一行。

接下來,是configure命令,尤其注意加--enable-obsolete-nsl,解決undefined reference to '_nsl_default_nss@GLIBC_PRIVATE' ,其他選項用他文章的也行,我的那個命令搞丟了(虛擬機器器後來搞別的搞壞了)

../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --enable-obsolete-nsl

然後就是:

make 或者 make -j4 (4個執行緒並行跑)

我記得我這邊大概耗時半小時或一小時內,忘了,還是虛擬機器器這種效能差的
make install

檢查裡面的version symbol:
strings /lib64/libc.so.6 | grep GLIBC

解決gcc問題--升級gcc

解決上面的問題後,繼續執行node,還是報錯,大概如下:

bin/node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by bin/node)
bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by bin/node)
bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by bin/node)
檢視這個裡面的symbol version,最新到1.3.7,不滿足1.3.9的要求:
[root@VM-0-6-centos node-v18.18.2-linux-x64]# strings /lib64/libstdc++.so.6 |grep CXXABI_
CXXABI_1.3
CXXABI_1.3.1
CXXABI_1.3.2
CXXABI_1.3.3
CXXABI_1.3.4
CXXABI_1.3.5
CXXABI_1.3.6
CXXABI_1.3.7

最新到3.4.19,不滿足3.4.20和3.4.21的要求:
[root@VM-0-6-centos node-v18.18.2-linux-x64]# strings /lib64/libstdc++.so.6 |grep GLIBCXX
...
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19

按照官方檔案來的:

https://gcc.gnu.org/wiki/InstallingGCC

安裝gcc前,需要先安裝依賴的gmp-devel mpfr-devel libmpc-devel,好多文章是說yum安裝,我覺得也可以,但我就怕gcc版本和yum安裝的這些依賴的版本不太匹配,建議還是按照如下方式來安裝:

wget https://ftp.gnu.org/gnu/gcc/gcc-8.5.0/gcc-8.5.0.tar.gz --no-check-certificate

cd gcc-8.5.0
./contrib/download_prerequisites

這一步就會去下載對應的原始碼,需要網際網路:

[root@VM-0-6-centos gcc-8.5.0]# ./contrib/download_prerequisites
2023-10-22 15:40:49 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
2023-10-22 15:42:05 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" [1]
2023-10-22 15:42:42 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2023-10-22 15:44:31 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291] -> "./isl-0.18.tar.bz2" [1]
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.18.tar.bz2: OK
All prerequisites downloaded successfully.

下完後,就儲存到了當前目錄下,幾個tar包。

mkdir build
cd build/

我是不需要gcc支援編譯go,需要的話,可以加上
../configure --disable-multilib --enable-languages=c,c++ --prefix=$HOME/local

接下來就是make,我一開始求快,搞得是:
nohup make -j4 2>&1 &
結果後面等了好久,報錯了。。。抱著試試看心理,改成make,結果成功了
nohup make  2>&1 &
tailf nohup.out 

make install
export LD_LIBRARY_PATH=$HOME/local/lib64

這裡這個make,要執行很久很久,反正我的雲主機是這樣,1核2g,cpu一直是100%,跑了2個半小時:

從4點20:

跑到6點40了:

搞完這些,再去用node,應該就沒啥問題了。哎,你說你官網檔案,就不能好好提示下我,支援centos7的最新版本是哪個,搞到一半報錯,然後一個版本一個版本地往下降,直到不報錯,網上社群也是一堆吐槽,服。