2023年11月29日发(作者:)

Ubuntu16.04系统中GCC9.1编译器安装⽅法及C++17标准测试⽰例

严正声明:本⽂系作者davidhopper原创,未经许可,不得转载。

2019年8⽉2⽇更新:

本⽂⽅法适⽤于GCC 9.1.0,只需将原⽂中的GCC 7.3.0替换为GCC 9.1.0即可。

为什么要更新到GCC 9.1.0?因为该版本可⽀持C++ 17标准的并⾏策略。

如何使⽤C++17标准的并⾏策略,参考我的另⼀篇博客:《》。

2017年底,C++17标准正式颁布,该标准的最⼤贡献是,提供了STL库算法的并⾏运算版本,对于我这种喜欢追求算法性能的程序员⽽

⾔,⽆疑是⼀个极⼤的福⾳。幸运地是,Linux系统标准编译器GCC能完美地⽀持C++ 17标准,但需升级到7.0以上版本;不幸地

是,Ubuntu 16.04版本⾃带的GCC版本为5.4.0,可⽀持C++ 14标准,但基本不⽀持C++ 17标准。怎么办?那就从零开始,从GCC官

⽅⽹站下载、安装最新标准的编译器吧。

⼀、下载GCC 7.3.0版本源代码

⼆、编译安装GCC 7.3.0

2.1 解压源代码压缩包

此时,我以为只要进⼊构建⽂件夹,然后执⾏如下配置命令就可以⽣成Makefile了,真是“too simple, sometimes naive”,世界哪有这

么美好?

cd ~/code/gcc/gcc-7.3.0-build

../gcc-7.3.0/configure

果不其然,上述命令产⽣的错误信息如下,原来是缺少⼏个依赖包:GMP 4.2+, MPFR 2.4.0+, MPC 0.8.0+,需要我们⾃⼰下载。

configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+.

Try the --with-gmp, --with-mpfr and/or --with-mpc options to specify

their locations. Source code for these libraries can be found at

their respective hosting sites as well as at

ftp:///pub/gcc/infrastructure/. See also

bash contrib/download_prerequisites

如果提⽰如下信息,则代表下载并解压成功:

2018-03-24 21:01:37 URL:/gnu/gcc/infrastructure/2 [2383840/2383840] -> "./2" [1]

2018-03-24 21:01:46 URL:/gnu/gcc/infrastructure/2 [1279284/1279284] -> "./2" [1]

2018-03-24 21:01:51 URL:/gnu/gcc/infrastructure/ [669925/669925] -> "./" [1]

2018-03-24 21:01:58 URL:/gnu/gcc/infrastructure/2 [1626446/1626446] -> "./2" [1]

2: 确定

2: 确定

: 确定

2: 确定

All prerequisites downloaded successfully.

如果出现如下信息,则表⽰包:2没有下载成功:

2018-03-24 20:54:39 URL:/infrastructure/ [669925/669925] -> "./" [1]

2018-03-24 20:56:16 URL:/infrastructure/2 [1626446/1626446] -> "./2" [1]

2: 失败

sha512sum: 警告:1 个校验和不匹配

error: Cannot verify integrity of possibly corrupted file 2

这是因为⽹络连接不正常造成的,解决⽅案是,进⼊⽬录“/home/davidhopper/code/gcc/gcc-7.3.0”,⼿动将已下载的“mpc-

”、“2”⽂件删除,重新执⾏命令下载。如果仍然提⽰失败,则应使⽤vi

bash contrib/download_prerequisites

也就是说,推断本机没有32位开发库,如果的确有就加上选项,否则就使⽤选项只构建64位版

configure--enable-multilib--disable-multilib

本。现在的机器谁还⽤32位系统,于是我⽴即重新运⾏配置程序如下:

../gcc-7.3.0/configure --disable-multilib

结果令⼈欣慰,总算在构建⽬录“/home/davidhopper/code/gcc/gcc-7.3.0-build”中⽣成了Makefile。

2.5 运⾏命令编译构建GCC编译器

make

接下来的事情似乎很简单,只要运⾏命令(需指出的是, Make程序⽀持并发处理,你的处理器有⼏个核,就可以加上选项,以

make-j x

便加快编译速度)就可以编译构建GCC编译器了,事实证明,我⼜把问题估计简单了⼀些。

cd ~/code/gcc/gcc-7.3.0-build

make -j 8

编译了不⼀会,就出现如下错误:

checking LIBRARY_ contains current directory

configure: error:

*** LIBRARY_PATH shouldn't contain the current directory when

*** building gcc. Please change the environment variable

*** and run configure again.

于是⽴即在⽹上搜索解决⽅案,找到如下类似的:

出现这个错误的原因是由于环境变量的LD_LIBRARY_PATH中出现了当前⽬录。

找了好久不知道是啥原因,因为不可能把这⽬录放在环境变量啊。后来发现,

通常我们写环境变量都喜欢写:

export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:foo/bar

如果⼀开始LD_LIBRARY_PATH不存在的话,这个上⾯这串环境变量开头就是冒号,

这就把当前⽂件夹包含进去了。⼀般来说我们挺需要这种效果,因为在编译的时候

可以include某些东西,但是对于编译glibc来说这个是多余的。

最简单的解决⽅法就是unset LD_LIBRARY_PATH,这能把这个环境变量直接⼲掉。

好吧,开始照⽅抓药,重新执⾏如下命令:

unset LIBRARY_PATH

../gcc-7.3.0/configure --disable-multilib

make -j 8

在我机器上⼤约等了⼀个⼩时,最后全部构建成功。

cd ~/code/gcc/gcc-7.3.0-build

sudo make install

因为我在运⾏命令时,没有指定安装⽬录,因此上述命令会将最新版本的GCC编译器安装到默认位置:,也就是说,头

configure/usr/local

⽂件在⽬录,可执⾏⽂件在⽬录,库⽂件在⽬录。

/usr/local/include/usr/local/bin/usr/local/lib

2.7 指定本机使⽤最新版本GCC编译器

使⽤命令配置增加最新版本编译器,注意:gcc是编译C程序的默认程序,g++是编译C++程序的默认程序。

update-alternatives

# update-alternatives --install <链接> <名称> <路径> <优先级>

sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc 50

sudo update-alternatives --install /usr/bin/g++ g++ /usr/local/bin/g++ 50

使⽤下述命令查询当前已经安装的GCC编译器版本:

# 查询本机已有GCC编译器情况

sudo update-alternatives --query gcc

# 查询本机已有G++编译器情况

sudo update-alternatives --query g++

我机器上的显⽰结果为:

Name: gcc

Link: /usr/bin/gcc

Status: auto

Best: /usr/local/bin/gcc

Value: /usr/local/bin/gcc

Alternative: /usr/bin/gcc-5

Priority: 20

Alternative: /usr/local/bin/gcc

Priority: 50

Name: g++

Link: /usr/bin/g++

Status: auto

Best: /usr/local/bin/g++

Value: /usr/local/bin/g++

Alternative: /usr/bin/g++-5

Priority: 20

Alternative: /usr/local/bin/g++

2 个候选项可⽤于替换 gcc (提供 /usr/bin/gcc)

选择 路径 优先级 状态

------------------------------------------------------------

* 0 /usr/local/bin/gcc 50 ⾃动模式

1 /usr/bin/gcc-5 20 ⼿动模式

2 /usr/local/bin/gcc 50 ⼿动模式

要维持当前值[*]请按<回车键>,或者键⼊选择的编号:

2 个候选项可⽤于替换 g++ (提供 /usr/bin/g++)

选择 路径 优先级 状态

------------------------------------------------------------

* 0 /usr/local/bin/g++ 50 ⾃动模式

1 /usr/bin/g++-5 20 ⼿动模式

2 /usr/local/bin/g++ 50 ⼿动模式

要维持当前值[*]请按<回车键>,或者键⼊选择的编号:

可以使⽤如下命令查询当前的版本:

gccg++

# gcc

查询版本

gcc --version

# g++

查询版本

g++ --version

三、C++ 17标准程序测试

写⼀个C++ 17标准中关于结构化绑定(structured bindings)的⼩程序,代码如下:

#include

#include

#include

#include

bool divide_remainder(int dividend, int divisor, int &fraction, int &remainder)

{

if (divisor == 0)

{

return false;

}

fraction = dividend / divisor;

remainder = dividend % divisor;

return true;

}

std::pair<int, int> divide_remainder(int dividend, int divisor)

{

if (divisor == 0)

{

throw std::runtime_error{"Attempt to divide by 0"};

}

return {dividend / divisor, dividend % divisor};

}

int main()

{

{ // old school way

int fraction, remainder;

const bool success{divide_remainder(16, 3, fraction, remainder)};

if (success)

{

std::cout << "16 / 3 is " << fraction << " with a remainder of " << remainder << "n";

}

}

}

{ // C++11 way

const auto result(divide_remainder(16, 3));

std::cout << "16 / 3 is " << result.first << " with a remainder of " << result.second << "n";

}

{ // C++11, ignoring fraction part of result

int remainder;

std::tie(std::ignore, remainder) = divide_remainder(16, 5);

std::cout << "16 % 5 is " << remainder << "n";

}

{ // C++17, use structured bindings

auto[fraction, remainder] = divide_remainder(16, 3);

std::cout << "16 / 3 is " << fraction << " with a remainder of " << remainder << "n";

}

{ // C++17, decompose a tuple into individual vars

std::tuple<int, float, long> tup{1, 2.0, 3};

auto[a, b, c] = tup;

std::cout << a << ", " << b << ", " << c << "n";

}

{ // C++17, use structured binding in for-loop

std::map<std::string, size_t> animal_population{

{"humans", 7000000000},

{"chickens", },

{"camels", 24246291},

{"sheep", 1086881528}

/* … */

};

for (const auto & [ species, count ] : animal_population)

{

std::cout << "There are " << count << " " << species << " on this planet.n";

}

}

}

编译命令如下:

g++ -g -Wall -std=c++17 *.cpp -o test

运⾏测试程序及结果如下:

./test

16 / 3 is 5 with a remainder of 1

16 / 3 is 5 with a remainder of 1

16 % 5 is 1

16 / 3 is 5 with a remainder of 1

1, 2, 3

There are 24246291 camels on this planet.

There are chickens on this planet.

There are 7000000000 humans on this planet.

There are 1086881528 sheep on this planet.

四、可能遇到的问题

4.1 使⽤G++7.3.0构建多线程程序,运⾏程序时出现类似“./main: /usr/lib/x86_64-linux-gnu/libstdc++.so.6:

version `GLIBCXX_3.4.22’ not found (required by ./main)”的错误

写⼀个使⽤C++ 17标准实现多线程的⼩程序,代码如下:

#include

#include

#include

#include

#include

using namespace std;

using namespace chrono_literals;

queue<size_t> q;

mutex mut;

condition_variable cv;

bool finished = false;

void producer(size_t items) {

for (size_t i = 0; i < items; ++i) {

this_thread::sleep_for(100ms);

{

lock_guard<mutex> lk(mut);

q.push(i);

}

cv.notify_all();

}

{

lock_guard<mutex> lk(mut);

finished = true;

}

cv.notify_all();

}

void comsumer() {

while (!finished) {

unique_lock<mutex> lk(mut);

cv.wait(lk, []() {

return !q.empty() || finished;

});

while (!q.empty()) {

cout << "Got " << q.front() << " from queue. " << endl;

q.pop();

}

}

}

int main() {

thread t1(producer, 10);

thread t2(comsumer);

t1.join();

t2.join();

cout << "Finished! " << endl;

return 0;

}

编译命令如下:

g++ -g -Wall -std=c++17 -pthread *.cpp -o main

运⾏测试程序:

./main

提⽰如下错误信息:

./main: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by ./main)

这是因为没有使⽤“libstdc++.so.6”版本不够新造成的,解决⽅法如下:

⾸先,在GCC 7.3.0的安装⽬录(如果未更改,默认安装路径为:/usr/local)中查找“libstdc++.so.6”,命令如下:

find /usr/local -name "libstdc++.so.6"

结果如下:

/usr/local/lib64/libstdc++.so.6

接着,将修改后缀名备份,并将复制到本地,命令如下:

/usr/lib/x86_64-linux-gnu/libstdc++.so.6/usr/local/lib64/libstdc++.so.6

cd /usr/lib/x86_64-linux-gnu

#

备份原有版本

sudo mv libstdc++.so.6 libstdc++.

#

复制新版本

sudo cp /usr/local/lib64/libstdc++.so.6 ./

#

最后,进⼊测试程序所在⽬录,重新运⾏⽣成的程序:

cd ~/code/C++17/SimpleProducerConsumerThread/

./main

结果如下:

Got 0 from queue.

Got 1 from queue.

Got 2 from queue.

Got 3 from queue.

Got 4 from queue.

Got 5 from queue.

Got 6 from queue.

Got 7 from queue.

Got 8 from queue.

Got 9 from queue.

Finished!

# 1.GCC

删除原有低优先级的⽼配置项

sudo update-alternatives --remove gcc /usr/bin/gcc-5

sudo update-alternatives --remove g++ /usr/bin/g++-5

# 2.GCC

以更⾼的优先级重新安装⽼配置项

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 70