跳到主要内容

Ubuntu 22.04 更新 C++ 编译器

Sol
千里之行,始于足下。

Ubuntu 22.04 默认使用 g++-11clang++-14 作为默认的 g++clang++

本文说明如何升级 C++ 编译器并设置默认版本,从而使用最新的 C++ 语言特性。

安装最新版本的 C++ 编译器

安装最新的 g++

sudo apt update
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt install gcc-12 g++-12 -y
sudo apt install gcc-13 g++-13 -y

安装最新的 clang++

参见 LLVM Debian/Ubuntu Packages 中的安装指南:

wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
# sudo ./llvm.sh <version number> all
# or
# sudo ./llvm.sh all
sudo ./llvm.sh 18 all

切换编译器的默认版本

上述命令执行之后,我们会发现,g++ 仍然是 g++11clang++ 仍然是 clang++-14

这里介绍一下 update-alternatives,由于管理 Ubuntu 上软件版本的切换,使其多版本共存。语法:

注册可选的软件版本:

sudo update-alternatives --install link name path priority \
[--slave link name path]

切换默认的软件版本:

sudo update-alternatives --config name
注意

切换编译器软件包可能有风险,建议只在个人计算机上使用。

切换 g++ 的默认版本

注册 gcc / g++ 版本:

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11 --slave /usr/bin/g++ g++ /usr/bin/g++-11
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12 --slave /usr/bin/g++ g++ /usr/bin/g++-12
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13 --slave /usr/bin/g++ g++ /usr/bin/g++-13

选择默认 gcc / g++ 版本:

sudo update-alternatives --config gcc

会弹出以下选项:

There are 3 choices for the alternative gcc (providing /usr/bin/gcc).

Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/gcc-13 13 auto mode
1 /usr/bin/gcc-11 11 manual mode
2 /usr/bin/gcc-12 12 manual mode
3 /usr/bin/gcc-13 13 manual mode

Press <enter> to keep the current choice[*], or type selection number:

输入序号即可。

切换 clang++ 的默认版本

clang / clang++ 是 LLVM 工具链的一部分,更新的时候,建议把 llvm 所有工具一起更新。

这里使用以下脚本 update-alternatives-clang.sh 进行批量注册:

#!/usr/bin/env bash

# Colors
RESET=$(tput sgr0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
BOLD=$(tput bold)

# Get available versions from /lib/llvm-*
# You can also use specific versions, e.g. VERSIONS=("14" "17" "18"), but not recommend
VERSIONS=()
for dir in /lib/llvm-*; do
if [[ -d "$dir" ]]; then
version=$(basename "$dir" | cut -d'-' -f2)
VERSIONS+=("$version")
fi
done

# Loop through versions
for VERSION in "${VERSIONS[@]}"; do
# Check if /lib/llvm-${VERSION} directory exists
if [[ -d "/lib/llvm-${VERSION}" ]]; then
# Scan paths and generate string
alternative_string=""
alternative_cmds=()
for cmd in "/lib/llvm-${VERSION}/bin/"*; do
if [[ -x "$cmd" ]] && [[ "$(basename "$cmd")" != "clang" ]]; then
base_cmd=$(basename "$cmd")
symlink="/usr/bin/${base_cmd}-${VERSION}"
if [[ -x "${symlink}" ]]; then
alternative_cmds+=($(basename ${symlink}))
alternative_string+="--slave /usr/bin/${base_cmd} ${base_cmd} ${symlink} "
fi
fi
done

# Remove specific alternative configuration
sudo update-alternatives --remove clang "/usr/bin/clang-${VERSION}" > /dev/null

# Install alternatives
install_command="sudo update-alternatives \
--quiet \
--install /usr/bin/clang clang /usr/bin/clang-${VERSION} ${VERSION} \
${alternative_string}"

# Print the concatenated string
echo "${BOLD}${GREEN}[Adding alternative /usr/bin/clang-${VERSION} ...]${RESET}"
echo "Master command: clang-${VERSION}"
echo "Slave commands: ${alternative_cmds[*]}"

eval "$install_command"

# Check eval command's return value
if [[ $? -eq 0 ]]; then
echo "${BOLD}${GREEN}[Adding alternative /usr/bin/clang-${VERSION}: succeeded]${RESET}"
else
echo "${BOLD}${RED}[Adding alternative /usr/bin/clang-${VERSION}: failed]${RESET}"
fi

echo ""
else
# Remove specific alternative configuration if /lib/llvm-${VERSION} directory does not exist
sudo update-alternatives --remove clang "/usr/bin/clang-${VERSION}" &> /dev/null
fi
done

clang_path=$(sudo update-alternatives --get-selections | grep ^clang | awk '{print $NF}')

echo "======================================================================"
echo "${GREEN}clang alternative is set to: ${clang_path}${RESET}"
echo "======================================================================"

# print helps
echo ""
echo "Info:"
num_versions=${#VERSIONS[@]}
if [[ num_versions -gt 1 ]]; then
echo " use '${GREEN}sudo update-alternatives --config clang${RESET}' to change default clang alternative"
fi
echo " use '${GREEN}sudo update-alternatives --remove clang /usr/bin/clang-*${RESET}' to delete a clang alternative"
echo " use '${GREEN}sudo update-alternatives --remove-all clang${RESET}' to delete all clang alternatives"
sudo bash update-alternatives-clang.sh

结果如下:

[Adding alternative /usr/bin/clang-14 ...]
Master command: clang-14
Slave commands: analyze-build-14 bugpoint-14 ...
[Adding alternative /usr/bin/clang-14: succeeded]

[Adding alternative /usr/bin/clang-18 ...]
Master command: clang-18
Slave commands: amdgpu-arch-18 analyze-build-18 ...
[Adding alternative /usr/bin/clang-18: succeeded]

======================================================================
clang alternative is set to: /usr/bin/clang-18
======================================================================
...

同上面的 gcc/g++ 版本切换,切换 clang / llvm 工具链版本命令如下:

sudo update-alternatives --config clang

会弹出以下选项:

There are 2 choices for the alternative clang (providing /usr/bin/clang).

Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/clang-18 18 auto mode
1 /usr/bin/clang-14 14 manual mode
2 /usr/bin/clang-18 18 manual mode

Press <enter> to keep the current choice[*], or type selection number:

输入序号即可。