目录 1
1. 前言 1
2. 安装日期 1
3. GCC国内镜像下载地址 2
4. GCC的依赖库 2
4.1. gmp库 2
4.2. mpfr库 2
4.3. mpc库 2
4.4. m4编译工具 2
4.5. 安装源代码包 3
5. 编译安装gmp 3
6. 编译安装mpfr 4
7. 编译安装mpc 4
8. 设置LD_LIBRARY_PATH 4
9. 编译安装gcc 4
10. 编译安装m4 6
附1:cmake支持 6
附2:debug STL 7
附3:体验C++14 7
附4:体验C++17 9
附5:C++标准 11
附6:C++标准当前状态 12
1. 前言
为体验C++17和C++20特性,需安装更新版本的GCC编译器。GCC官网为:GCC, the GNU Compiler Collection- GNU Project,从这里可以下载最新版本的GCC。
C++由Bjarne Stroustrup(被誉为C++之父)于1979年在新泽西州美利山贝尔实验室开始设计开发的,最初命名为带类的C,后来在1983年更名为C++。
2. 安装日期
2019/4/27,截至该日期最新版本为GCC-8.3.0,但在本月未或下月初即将发布GCC-9.1(已于2019-05-03发布)。
3. GCC国内镜像下载地址
下载速度不一,请选择速度最快的:
1) NJU Mirror
2) Index of /gnu/gcc/gcc-8.3.0/
3) Index of /gnu/gcc/gcc-8.3.0/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
4. GCC的依赖库
编译之前需先安装好GCC的依赖库:gmp、mpfr和mpc。编译还依赖m4等编译工具,如果没有,则在执行configue时会报相应的错误,这时需要先安装好这些编译工具。
4.1. gmp库
GMP为“GNU MP Bignum Library”的缩写,是一个GNU开源数学运算库。本文选择的是最新版本gmp-6.1.2,国内镜像下载地址:
1) Index of /gnu/gmp/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
2) NJU Mirror
4.2. mpfr库
mpfr是一个GNU开源大数运算库,它依赖gmp。本文选择的是最新版本mpfr-4.0.2,国内镜像下载地址:
1) Index of /gnu/mpfr/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
2) NJU Mirror
4.3. mpc库
mpc是GNU的开源复杂数字算法,它依赖gmp和mpfr。本文选择的是最新版本mpc-1.1.0,国内镜像下载地址:
1) Index of /gnu/mpc/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
2) NJU Mirror
4.4. m4编译工具
本文选择的是最新版本m4-1.4.16,下载地址:
1) Index of /gnu/m4/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
2) NJU Mirror
如果使用“--prefix”指定了安装目录,则在编译gmp等之前还需先设置好环境变量PATH,以便configure时能找到m4。
4.5. 安装源代码包
涉及到的所有安装源代码包:
gcc-8.3.0.tar.gz mpfr-4.0.2.tar.gz gmp-6.1.2.tar.xz mpc-1.0.3.tar.gz |
GCC的依赖库间还互有依赖:mpfr依赖gmp、mpc依赖gmp和mpfr,所以GCC的编译安装顺序为:
1) m4(如果需要)
2) gmp
3) mpfr
4) mpc
5) GCC
为了不污染已有的编译和运行环境,将GCC及依赖库均安装到/usr/local目录,并且最好以root用户完成下述所有操作。
5. 编译安装gmp
执行configure生成Makefile时,需要用到m4,一般路径为/usr/bin/m4,如果没有则需要先安装,否则报错“no usable m4”错误,手工安装m4从“GNU M4 - GNU Project - Free Software Foundation”下载。
具体安装步骤如下:
xz -d gmp-6.1.2.tar.xz tar xf gmp-6.1.2.tar cd gmp-6.1.2 ./configure --prefix=/usr/local/gmp-6.1.2 make make install ln -s /usr/local/gmp-6.1.2 /usr/local/gmp |
6. 编译安装mpfr
详细安装步骤如下:
tar xzf mpfr-4.0.2.tar.gz cd mpfr-4.0.2 ./configure --prefix=/usr/local/mpfr-4.0.2 --with-gmp=/usr/local/gmp make make install ln -s /usr/local/mpfr-4.0.2 /usr/local/mpfr |
7. 编译安装mpc
tar xzf mpc-1.1.0.tar.gz cd mpc-1.1.0 ./configure --prefix=/usr/local/mpc-1.1.0 --with-gmp=/usr/local/gmp --with-mpfr=/usr/local/mpfr make make install ln -s /usr/local/mpc-1.1.0 /usr/local/mpc |
8. 设置LD_LIBRARY_PATH
在编译GCC之前,如果不设置LD_LIBRARY_PATH(如果编译gmp时没有指定“--prefix”时安装,一般不用再显示设置),则可能编译时报“error while loading shared libraries: libmpfr.so.6: cannot open shared object file: No such file or directory”等错误。
export LD_LIBRARY_PATH=/usr/local/gmp/lib:/usr/local/mpfr/lib:/usr/local/mpc/lib:$LD_LIBRARY_PATH |
9. 编译安装gcc
在执行make编译GCC时,有些费时,请耐心等待。在一台Intel Xeon 2.30GHz的48核128GB内存机器上花费228分钟(将近4个小时,同台机器编译9.1.0花费190分钟),编译GCC-8.3.0的GCC版本为4.8.5(64位)。
tar xzf gcc-8.3.0.tar.gz cd gcc-8.3.0 ./configure --prefix=/usr/local/gcc-8.3.0 --with-mpfr=/usr/local/mpfr --with-gmp=/usr/local/gmp --with-mpc=/usr/local/mpc date;time make;date make install ln -s /usr/local/gcc-8.3.0 /usr/local/gcc export PATH=/usr/local/gcc/bin:$PATH export LD_LIBRARY_PATH=/usr/local/gcc/lib64:$LD_LIBRARY_PATH export MANPATH=/usr/local/gcc/share/man:$MANPATH gcc --version |
在执行configure时,如果遇到错误“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”,表示系统不支持32位程序,这样在执行configure时需为它支持参数“--disable-multilib”,如:
./configure --prefix=/usr/local/gcc-8.3.0 --with-gmp=/usr/local/gmp --with-mpfr=/usr/local/mpfr --with-mpc=/usr/local/mpc --disable-multilib |
如果make时遇到错误“internal compiler error”,可能是因为内存不足,请换台内存更大的机器,或者更换GCC版本试试。
如果遇到错误“C compiler cannot create executables”、“error while loading shared libraries: libmpfr.so.6: cannot open shared object file: No such file or directory”或“cannot compute suffix of object files”,可尝试设置LD_LIBRARY_PATH后再试试:
export LD_LIBRARY_PATH=/usr/local/gmp/lib:/usr/local/mpfr/lib:/usr/local/mpc/lib:$LD_LIBRARY_PATH |
make成功结束时的输出:
make[8]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/32/libatomic” make[7]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/32/libatomic” make[6]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/32/libatomic” make[5]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/libatomic” make[4]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/libatomic” make[3]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/libatomic” make[2]: 离开目录“/data/GCC/gcc-8.3.0/x86_64-pc-linux-gnu/libatomic” make[1]: 离开目录“/data/GCC/gcc-8.3.0 |
在完成上列步骤后,检查新安装的GCC-8.3.0是否可用:
# gcc --version gcc (GCC) 8.3.0 Copyright © 2018 Free Software Foundation, Inc. 本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保; 包括没有适销性和某一专用目的下的适用性担保。 # man gcc|col -b|grep c++17 c++17 GNU dialect of -std=c++17. The name gnu++1z is deprecated. This flag is enabled by default for -std=c++17. arguments as an argument for a template template parameter with fewer template parameters. This flag is enabled by default for -std=c++17. adopted for C++17. Enabled by default with -std=c++17. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and is the default without -std=c++17. -Wc++17-compat. "register" keyword as storage class specifier has been deprecated in C++11 and removed in C++17. Enabled by default with -std=c++17. -Wc++17-compat (C++ and Objective-C++ only) |
已经支持C++20标准,但因为标准还未正式发布,所以正式发布后大概率发生变化:
# man gcc|col -b|grep c++2a c++2a GNU dialect of -std=c++2a. Support is highly experimental, and will almost certainly change in incompatible ways in future releases (支持是高度实验性的,并且在将来的版本中几乎肯定会以不兼容的方式发生变化). |
10. 编译安装m4
只有m4不可用或版本过低时才需安装m4(一般路径为/usr/bin/m4),如果configure时不指定prefix,则可省去export和ln两步:
tar xzf m4-1.4.16 cd m4-1.4.16 ./configure --prefix=/usr/local/m4-1.4.16 make make install ln -s /usr/local/m4-1.4.16 /usr/local/m4 export PATH=/usr/local/m4/bin:$PATH |
附1:cmake支持
在使用cmake前,需设置好下列所环境变量,否则cmake仍将使用默认目录下的gcc和g++,在CMakeFiles.txt文件中设置CMAKE_C_COMPILER和CMAKE_CXX_COMPILER不能解决这个问题。如果在此之前已经执行过cmake,则得先删除CMakeFiles目录和文件CMakeCache.txt,然后再重新执行cmake生成Makefile文件。
export CC=/usr/local/gcc/bin/gcc export CXX=/usr/local/gcc/bin/g++ export PATH=/usr/local/gcc/bin:$PATH export LD_LIBRARY_PATH=/usr/local/gcc/lib64:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=/usr/local/gmp/lib:/usr/local/mpfr/lib:/usr/local/mpc/lib:$LD_LIBRARY_PATH |
附2:debug STL
有时需要debug STL中的容器等,正常情况下没法跟踪STL中的代码,只需要加上编译宏“_GLIBCXX_DEBUG”即可开启对STL的debug。注意这个并不是GCC编译器定义的,而是直接在STL源代码中定义的。细心点可发现在STL库头文件目录中有一个debug子目录,以4.8.5为例:
$ ls /usr/include/c++/4.8.5/debug array deque functions.h map multiset.h safe_iterator.tcc safe_sequence.h safe_unordered_container.h set.h unordered_set bitset formatter.h list map.h safe_base.h safe_local_iterator.h safe_sequence.tcc safe_unordered_container.tcc string vector debug.h forward_list macros.h multimap.h safe_iterator.h safe_local_iterator.tcc safe_unordered_base.h set unordered_map |
查看正常的文件,即可看到“_GLIBCXX_DEBUG”:
$ vi /usr/include/c++/4.8.5/map #ifdef _GLIBCXX_DEBUG # include <debug/map> #endif #ifdef _GLIBCXX_PROFILE # include <profile/map> #endif |
附3:体验C++14
// C++14 #include <iostream> [[deprecated]] auto foo1() { int m = 2019; return m; } [[deprecated("foo2 is deprecated")]] auto foo2() { int m = 2020; return m; } int main() { const auto n1 = foo1(); const auto n2 = foo2(); std::cout << "n1: " << n1 << std::endl << "n2: " << n2 << std::endl; return 0; } |
编译运行结果如下:
$g++ -o main *.cpp main.cpp: In function ‘int main()’: main.cpp:17:24: warning: ‘auto foo1()’ is deprecated [-Wdeprecated-declarations] const auto n1 = foo1(); ^ main.cpp:5:6: note: declared here auto foo1() { ^~~~ main.cpp:18:24: warning: ‘auto foo2()’ is deprecated: foo2 is deprecated [-Wdeprecated-declarations] const auto n2 = foo2(); ^ main.cpp:11:6: note: declared here auto foo2() { ^~~~ $main n1: 2019 n2: 2020 |
如果在C++11上编译,会报语法错误:
main.cpp:5:11: error: 'foo1' function uses 'auto' type specifier without trailing return type auto foo1() { ^ main.cpp:5:11: note: deduced return type only available with -std=c++14 or -std=gnu++14 main.cpp:11:11: error: 'foo2' function uses 'auto' type specifier without trailing return type auto foo2() { ^ main.cpp:11:11: note: deduced return type only available with -std=c++14 or -std=gnu++14 main.cpp: In function 'int main()': main.cpp:17:24: warning: 'auto foo1()' is deprecated [-Wdeprecated-declarations] const auto n1 = foo1(); ^ main.cpp:5:6: note: declared here auto foo1() { ^~~~ main.cpp:17:24: warning: 'auto foo1()' is deprecated [-Wdeprecated-declarations] const auto n1 = foo1(); ^ main.cpp:5:6: note: declared here auto foo1() { ^~~~ main.cpp:18:24: warning: 'auto foo2()' is deprecated: foo2 is deprecated [-Wdeprecated-declarations] const auto n2 = foo2(); ^ main.cpp:11:6: note: declared here auto foo2() { ^~~~ main.cpp:18:24: warning: 'auto foo2()' is deprecated: foo2 is deprecated [-Wdeprecated-declarations] const auto n2 = foo2(); ^ main.cpp:11:6: note: declared here auto foo2() { ^~~~ |
附4:体验C++17
// C++17 #include <iostream> template <auto v> auto foo() { return v; } int main() { std::cout << "foo return: " << foo<2019>() << std::endl; for (int i=0; i<10; ++i) { if (int m=i%2;0==m) std::cout << "i: " << i << std::endl; } return 0; } |
编译运行结果如下:
foo return: 2019 i: 0 i: 2 i: 4 i: 6 i: 8 |
再体验一段来源于Functional in C++17 and C++20 – MC++ BLOG的C++17代码:
// foldExpression.cpp #include <iostream> template<typename... Args> bool all(Args... args) { return (... && args); } template<typename... Args> bool any(Args... args) { return (... || args); } template<typename... Args> bool none(Args... args) { return not(... || args); } int main(){ std::cout << std::endl; std::cout << std::boolalpha; std::cout << "all(true): " << all(true) << std::endl; std::cout << "any(true): " << any(true) << std::endl; std::cout << "none(true): " << none(true) << std::endl; std::cout << std::endl; std::cout << "all(true, true, true, false): " << all(true, true, true, false) << std::endl; std::cout << "any(true, true, true, false): " << any(true, true, true, false) << std::endl; std::cout << "none(true, true, true, false): " << none(true, true, true, false) << std::endl; std::cout << std::endl; std::cout << "all(false, false, false, false): " << all(false, false, false, false) << std::endl; std::cout << "any(false, false, false, false): " << any(false, false, false, false) << std::endl; std::cout << "none(false, false, false, false): " << none(false, false, false, false) << std::endl; std::cout << std::endl; } |
编译运行结果如下:
all(true): true any(true): true none(true): false all(true, true, true, false): false any(true, true, true, false): true none(true, true, true, false): false all(false, false, false, false): false any(false, false, false, false): false none(false, false, false, false): true |
附5:C++标准
可浏览C++ compiler support - cppreference.com了解各编译器对C++标准的支持详情。C++标准官网:Standard C++。
年份 | C++标准 | 名称 | __cplusplus值 | 重大新特性 |
1998 | ISO/IEC 14882:1998 | C++98 | 199711L | 第一个C++标准 |
2003 | ISO/IEC 14882:2003 | C++03 | 199711L | 第二个C++标准 |
2011 | ISO/IEC 14882:2011 | C++11 | 201103L | 第三个C++标准 1) auto关键字 2) 右值引用 3) nullptr关键字 4) shared_ptr/unique_ptr/weak_ptr 5) long long 6) lambda(类似JS的闭包) 7) decltype 8) constexpr 9) delete/default 10) final/override 11) noexcept 12) std::tuple 13) std::move 14) 变长参数的模板 15) 模板“>>”(两个“>”间不再需空格) 16) 多线程并发支持:thread_local、std::atomic、std::thread等 |
2014 | ISO/IEC 14882:2014 | C++14 | 201402L | 第四个C++标准 1) 函数可返回auto(返回值类型推导) 2) 泛型lambda 3) deprecated属性 4) std::optional 5) 二进制常量和数字分隔符 |
2017 | ISO/IEC 14882:2017 | C++17 | 201703L | 第五个C++标准 1) 删除三字符词(如“??=”、“??-”等) 2) if/switch语句内可定义和初始化变量 3) std::any/std::variant 4) 内联变量(可在头文件中定义变量) 5) __has_include 6) 并行STL 7) 折叠表达式(fold expression) 8) 构造函数的模板推导(class template deduction) 9) 结构化绑定(structured bindings) |
2020 | 暂未定 | C++20 | 第六个C++标准(暂未正式发布): 1) 协程(coroutines) 2) 模块化(modules) 3) Concepts(编译期模板) 4) Ranges | |
未定 | C++23 | |||
C++26 |
附6:C++标准当前状态
注:TS为“Technical Specifications”的缩写,IS为“International Standard”的缩写,TR为“Technical Report”的缩写。
转: