安裝GCC-9.3.0及其依賴研究C17-C++17特性

2020-08-14 21:08:15

參考 安裝GCC-8.3.0及其依賴 在 win10 + vmware15 + ubuntu16.04(gcc4.8.5) 環境下 成功安裝 gcc9.3.0 以此研究C++17/C++20/C17的特性。注意:C17只是修復了C11中的bug,並未引入新的語言特性。

1.前言

爲體驗C17和C++17特性,需安裝更新版本的GCC編譯器。

GCC官網爲:https://gcc.gnu.org/,從這可下載最新版本的GCC。

本文在 ubuntu 中安裝 gcc 9.3.0.

gcc 9.3.0 (發佈於 2020.03.12 )安裝於 2020.08.14,截至該日期最新版本爲 gcc 10.2.

img-01

注意: ubuntu 20.04 預設自帶的gcc版本就是 gcc 9.3.0.

2. gcc原始碼 github映象

  1. https://github.com/gcc-mirror/gcc (gcc 官網原倉庫)
  2. https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git(清華大學開源映象)

清華大學 gcc 開源映象使用方法(如下),也可參考 官網幫助文件

特別注意:https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git 此地址用 git 可以存取,但用瀏覽器不可以存取

如需克隆 GCC 程式碼,使用

git clone https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git

若要將 tuna mirror 加入已有程式碼庫,可在已有倉庫中執行

git remote add tuna https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git

或執行

git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git

將預設上遊設定爲 TUNA 映象

3. GCC國內映象下載地址

下載速度不一,請選擇速度最快的:

  1. https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-9.3.0/ (清華大學開源映象)
  2. https://mirrors.ustc.edu.cn/gnu/gcc/gcc-9.3.0/(中國科學技術大學開源軟體映象)
  3. https://mirrors.nju.edu.cn/gnu/gcc/gcc-9.3.0/ (南京大學開源映象站)
  4. https://mirrors.huaweicloud.com/gnu/gcc/gcc-9.3.0/ (華爲雲開源映象)

第4部分 gcc 的依賴庫可在以上4個開源映象的 `*/gnu/ 路徑下下載,eg: 使用 清華大學開源映象 下載 gmp、mpfr、mpc、m4 ,其下載鏈接如下:

https://mirrors.tuna.tsinghua.edu.cn/gnu/gmp/*
https://mirrors.tuna.tsinghua.edu.cn/gnu/mpfr/*
https://mirrors.tuna.tsinghua.edu.cn/gnu/mpc/*
https://mirrors.tuna.tsinghua.edu.cn/gnu/m4/*

* 指定下載的版本

4. GCC的依賴庫

編譯之前需先安裝好GCC的依賴庫:gmpmpfrmpc。編譯還依賴 m4 等編譯工具,如果沒有,則在執行configue 時會報相應的錯誤,這時需要先安裝好這些編譯工具。

4.1. gmp庫

GMP爲「GNU MP Bignum Library」的縮寫,是一個GNU開源數學運算庫。本文選擇的是最新版本gmp-6.2.0.

4.2. mpfr庫

mpfr是一個GNU開源大數運算庫,它依賴gmp。本文選擇的是最新版本mpfr-4.0.2.

4.3. mpc庫

mpc是GNU的開源複雜數位演算法,它依賴gmp和mpfr。本文選擇的是最新版本mpc-1.1.0.

4.4. m4編譯工具

M4 是一個宏處理器.將輸入拷貝到輸出,同時將宏展開. 宏可以是內嵌的也可以是使用者定義的. 除了可以展開宏,m4還有一些內建的函數,用來參照檔案,執行Unix命令,整數運算,文字操作,回圈等. m4既可以作爲編譯器的前端也可以單獨作爲一個宏處理器.

本文選擇的是最新版本m4-1.4.16.

如果使用「–prefix」指定了安裝目錄,則在編譯gmp等之前還需先設定好環境變數PATH,以便configure時能找到m4。

4.5. 安裝原始碼包

涉及到的所有安裝原始碼包:

m4-1.4.16.tar.gz (2011-03-01)
gcc-9.3.0.tar.gz (2020-03-12)
mpfr-4.0.2.tar.gz (2015-02-20)
gmp-6.2.0.tar.xz (2020-01-18)
mpc-1.1.0.tar.gz (2018-01-11)

GCC的依賴庫間還互有依賴:mpfr依賴gmp、mpc依賴gmp和mpfr,所以GCC的編譯安裝順序爲:

  1. m4(如果需要)
  2. gmp
  3. mpfr
  4. mpc
  5. GCC

爲了不污染已有的編譯和執行環境,將GCC及依賴庫均安裝到/usr/local目錄,並且最好以root使用者完成下述所有操作。

5.安裝 M4

5.1 使用 apt install m4 安裝

sudo apt install m4

這種方式無需手動解決依賴庫。

5.2 使用 m4 原始碼安裝

這種方式可能需要手動解決依賴庫。

m4 一般安裝路徑爲/usr/bin/m4,如果系統沒有安裝m4, 需手動下載 從 「https://www.gnu.org/software/m4/」 下載安裝。

預計所需編譯時間:      0.1 SBU
預計所需硬碟空間:      3.0 MB

M4 安裝依賴關係

M4 依賴於: Bash, Binutils, Coreutils, Diffutils, GCC, Gettext, Glibc, Grep, Make, Perl, Sed.

注意: 安裝時系統必須預裝 gcc 的某個版本(本文 gcc 4.8.5).

爲編譯 M4 做準備:

tar xzf m4-1.4.16.tar.gz
cd m4-1.4.16
./configure --prefix=/usr/local/m4-1.4.16

編譯軟體包:

make

本軟體包自帶測試套件,能執行一些測試,以確定它是否編譯正確。如果你想執行測試套件,執行下面 下麪的命令:

make check

安裝軟體包:

make install

設定環境變數:

ln -s /usr/local/m4-1.4.16 /usr/local/m4
sudo gedit /etc/profile
# 在/etc/profile 最後新增以下內容,儲存。
# 註銷,重新登陸 或 重新啓動ubuntu後環境變數生效
# 如果想在設定後,在當前開啓的終端立即生效 執行 source /etc/profile
export PATH=/usr/local/m4/bin:$PATH

檢查 M4 是否安裝成功

m4 --version

安裝 m4-1.4.18 出錯

起初安裝 m4-1.4.18 (發佈於 2016-12-31)出現以下錯誤:

freadahead.c:92:3: error: #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread, ungetc on your system, then report this to bug-gnulib."
   92 |  #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread, ungetc on your system, then report this to bug-gnulib."
      |   ^~~~~
make[3]: *** [Makefile:1913: freadahead.o] Error 1
make[3]: Leaving directory '/tmp/soft-install/m4-1.4.18/lib'
make[2]: *** [Makefile:1674: all] Error 2
make[2]: Leaving directory '/tmp/soft-install/m4-1.4.18/lib'
make[1]: *** [Makefile:1572: all-recursive] Error 1
make[1]: Leaving directory '/tmp/soft-install/m4-1.4.18'
make: *** [Makefile:1528:all] 錯誤 2

img-02

經查閱資料,確定原因爲:M4版本相容性問題,M4-1.4.18 版本太新,不相容當前平臺,最後將 M4 的版本替換爲 M4-1.4.16 問題解決。

5. 編譯安裝gmp

執行 configure 生成Makefile時,需要用到m4,一般路徑爲/usr/bin/m4,如果沒有則需要先安裝,否則報錯「no usable m4」錯誤。

具體安裝步驟如下:

xz -d gmp-6.2.0.tar.xz
tar xf gmp-6.2.0.tar
cd gmp-6.2.0
./configure --prefix=/usr/local/gmp-6.2.0
make
make install
ln -s /usr/local/gmp-6.2.0 /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時,有些費時需要2~4小時,編譯GCC-9.3.0的GCC版本爲4.8.5(64位元)。

tar xzf gcc-9.3.0.tar.gz
cd gcc-9.3.0
./configure --prefix=/usr/local/gcc-9.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-9.3.0 /usr/local/gcc
sudo gedit /etc/profile
# 在/etc/profile 最後新增以下內容,儲存
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-9.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-9.3.0/x86_64-pc-linux-gnu/32/libatomic」
make[7]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/32/libatomic」
make[6]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/32/libatomic」
make[5]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/libatomic」
make[4]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/libatomic」
make[3]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/libatomic」
make[2]: 離開目錄「/data/GCC/gcc-9.3.0/x86_64-pc-linux-gnu/libatomic」
make[1]: 離開目錄「/data/GCC/gcc-9.3.0

在完成上列步驟後,檢查新安裝的GCC-9.3.0是否可用:gcc -v

img-03

參考

  1. https://www.cnblogs.com/aquester/p/10799125.html
  2. https://www.cnblogs.com/LeiFeng1000/p/12562211.html
  3. http://shouce.jb51.net/linux-from-scratch/chapter06/m4.html

附錄

附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

再體驗一段來源於 http://www.modernescpp.com/index.php/functional-in-c-17-and-c-20 的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++標準

可瀏覽 https://en.cppreference.com/w/cpp/compiler_support 瞭解各編譯器對C++標準的支援詳情。C++標準官網:https://isocpp.org/。

年份 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::optional5) 二進制常數和數位分隔符
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」的縮寫。

img-04
img-05
img-06

(本文完)