最近因为项目需要,需要使用 C++ 17 的一些特性,CentOS 自带的 gcc/g++ 版本是 4.8,如果没有安装,可以通过 yum 命令安装,安装命令如下:
# 安装gcc
yum install gcc
#安装 g++
yum install gcc-c++
由于 gcc/g++ 4.8 完全支持 C++ 11,支持部分 C++ 14,不支持 C++ 17,而完全支持 C++ 17 的是 g++ 7 及以上版本:
C++17:
gcc7完全支持,gcc6和gcc5部分支持,gcc6支持度当然比gcc5高,gcc4及以下版本不支持。
C++14:
gcc5就可以完全支持,gcc4部分支持,gcc3及以下版本不支持。
C++11:
gcc4.8.1及以上可以完全支持。gcc4.3部分支持,gcc4.3以下版本不支持。
高版本的gcc向下兼容,支持低版本的C++标准。现在很多服务器yum里的gcc版本是4.8.5,也就是可以完全支持C++11了,部分支持C++14,不支持C++17。
下面就介绍一下如何安装 gcc 7,在众多主版本号为 7 的版本中我选择了 7.3,其下载地址如下:
https://gcc.gnu.org/releases.html
选择 7.3 的链接点进去:
国外的站点下载速度可能比较慢(不过也没关系,7.3 版本也就 103 M),等一会儿也就下载下来了。
或者去国内清华大学的站点去下载:https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/
这是一个非常有用的站点,请记住它的主页:https://mirrors.tuna.tsinghua.edu.cn
下载下来之后,放到你想要放的目录,我这里是 /home/zhangxf/
:
-rw-r--r--. 1 root root 112201917 7月 30 14:03 gcc-7.3.0.tar.gz
解压:
tar zxvf gcc-7.3.0.tar.gz
进入解压后的目录 gcc-7.3.0
,执行:
./configure
这个时候可能会产生如下错误:
configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+.
这是缺少相关的依赖库,解决方法有两种。
方法一:
进入 contrib
目录执行 download_prerequisites
命令,下载相关的依赖库,然后手动编译安装,但是如果网络不通畅会非常的慢,不推荐这种方法,推荐使用方法二。
方法二:
使用 yum 安装相关库:
yum install gmp gmp-devel mpfr mpfr-devel libmpc libmpc-devel
安装成功后,再次执行 configure
可能会提示如下错误:
*** This configuration is not supported in the following subdirectories:
gnattools gotools target-libada target-libhsail-rt target-libgo target-libffi target-liboffloadmic
(Any other directories should still work fine.)
checking for default BUILD_CONFIG... bootstrap-debug
checking for --enable-vtable-verify... no
/usr/bin/ld: cannot find crt1.o: No such file or directory
/usr/bin/ld: cannot find crti.o: No such file or directory
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcc_s.so when searching for -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lc
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcc_s.so when searching for -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find crtn.o: No such file or directory
collect2: error: ld returned 1 exit status
configure: error: I suspect your system does not have 32-bit development libraries (libc and headers). If you have them, rerun configure with --enable-multilib. If you do not have them, and want to build a 64-bit-only compiler, rerun configure with --disable-multilib.
根据错误提示,我们给 configure
命令加上 --disable-multilib
参数再次执行(这样其实也就不再生产 32 位的编译器了)。
./configure --disable-multilib
执行完毕之后,产生一个 Makefile 文件,此时我们就利用这个 Makefile 文件编译得到 gcc/g++ 7.3 版本的编译器了。也就是说,你的机器上必须有旧版本的 gcc/g++ (如前文所述,我这里就是 gcc/g++ 4.8)。
执行:
make -j 4
整个编译过程,根据你的机器配置,可能要等十几分钟到一个小时不等。
在编译的过程中可能会出现如下错误:
xgcc: error trying to exec 'cc1plus': execvp: No such file or directory
这是由于找不到 cc1plus 这个执行命令,在系统 PATH 变量中添加该路径即可,对于 CentOS 机器这个命令一般位于 /usr/local/libexec/gcc/
中,例如我的机器位于 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5
,打开 /etc/profile
将该路径添加到 PATH 中,然后执行 source 命令让设置生效,重新编译即可。
参考网址:https://stackoverflow.com/questions/11912878/gcc-error-gcc-error-trying-to-exec-cc1-execvp-no-such-file-or-directory
如果编译过程中出现错误:
cc: error trying to exec 'cc1obj': execvp: No such file or directory
可以安装下如下工具:
yum install gcc-objc gcc-objc++ libobjc
如果编译过程中出错,一定要记得将 build-x86_64-pc-linux-gnu
目录中的文件都删掉,再重新编译(我的做法是直接将整个父目录都删掉,然后重新解压)。
经过等待后,接着就是安装了,执行:
make install
安装好了之后,我们将老的 gcc/g++ 删掉,执行:
yum remove gcc gcc-c++
然后将新的 gcc/g++ 添加的系统 PATH 环境变量中,我的 7.3 版本位于目录 /usr/local/bin/
,打开 ~/.bash_profile
文件,增加该路径至 PATH 环境变量:
保存,并执行 source 命令让配置生效:
source ~/.bash_profile
至此,我们就可以使用新的编译器了。
但是在我们使用 make 去编译某些程序时会提示如下错误:
cd uSockets && WITH_SSL=0 make
make[1]: 进入目录“/home/zhangyl/uWebSocket/uWebSockets-master/uSockets”
rm -f *.o
cc -DLIBUS_NO_SSL -std=c11 -Isrc -flto -O3 -c src/*.c src/eventing/*.c
/bin/sh: cc: 未找到命令
make[1]: *** [default] 错误 127
make[1]: 离开目录“/home/zhangyl/uWebSocket/uWebSockets-master/uSockets”
make: *** [examples] 错误 2
提示我们 cc 或者 cxx 命令找不到,这是因为老的 gcc/g++ 有两个环境变量,我们移除老的 gcc/g++ 后需要重新配置一下这两个环境变量到新的 gcc/g++ 版本上去,即在刚才说的 ~/.bash_profile
文件中增加两个环境变量:
这里 CC 和 CXX 的具体值设置成你的 gcc 7.3 可执行文件的路径(路径中包括你的可执行文件名,图中 gcc 和 g++ 是 7.3 版本的可执行文件名)。
另外,当我们编译程序完后执行,可能会报以下错误:
/home/zhangyl/market/marketserver: /lib64/libstdc++.so.6: version `CXXABI_1.3.8' not found (required by /home/zhangyl/market/marketserver)
/home/zhangyl/market/marketserver: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by /home/zhangyl/market/marketserver)
/home/zhangyl/market/marketserver: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /home/zhangyl/market/marketserver)
/home/zhangyl/market/marketserver: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by /home/zhangyl/library/lib/linux/librdkafka++.so.1)
/home/zhangyl/market/marketserver: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /home/zhangyl/library/lib/linux/librdkafka++.so.1)
[Inferior 1 (process 30394) exited with code 01]
Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.3.x86_64
(gdb) quit
这是由于我们升级了 gcc/g++ 版本,但是系统的仍然是老的 libstdc++.so 文件。我们可以使用 strings 命令确认一下我们新的libstdc++.so 文件中是否含有这些 CXXABI_1.3.8
信息。那么新的 libstdc++.so 在哪里呢?通过搜索,我们可以发现在我们 7.3 的编译目录:
将这个文件拷贝至 /lib64/
目录下,然后删除旧的链接文件 libstdc++.so.6
,重新创建一个 libstdc++.so.6
链接到这个新的上面去就可以。
我们确认一下这个新的文件是不是真的有 CXXABI_1.3.8
这些信息,使用:
[root@js-dev2 gcc-7.3.0]# cd /lib64
[root@js-dev2 lib64]# strings libstdc++.so.6 | grep CXXABI_1.3.8
CXXABI_1.3.8
CXXABI_1.3.8
对于旧的 libstdc++.so
建议做的备份而不是直接删除。
至此,我们就可以使用 gcc/g++ 7.3 了,然后尝试 C++ 17 了。当然,你也可以同步升级一下 gdb。
需要注意的是:
- 你升级 gcc/g++ 之后,你老的程序依赖的 so 文件可能也要重新编译生成,不然可能会出现一些链接错误。
- 另外,编译 gcc/g++ 7.3 时需要较多的机器内存,如果你的机器内存不大,在编译过程中你的编译进程可能因为“out of memory”被操作系统杀死。如果出现这种情形,不用重新编译,接着执行make命令即可,这样已经编译过的文件就不用重新编译了。