LLVM 项目博客

LLVM 项目新闻和来自战壕的细节

在 Linux 上使用 Clang 构建 Chrome 生产版本

Chrome 38 于 2014 年 10 月初发布。这是第一个在 Linux 上为用户提供的二进制文件由 Clang 构建的版本。之前,这是由 gcc 4.6 完成的。正如您在 公告邮件 中所看到的那样,切换过程非常顺利。性能基本保持不变,二进制文件大小减少了约 8%。在这篇文章中,我想讨论一下进行切换的动机。

动机

切换的原因有两个。

1. 许多 Chromium 开发人员已经在 Linux 上使用 Clang。我们一直支持自 选择使用 Clang 以来,在 Clang 支持 C++ 之前 就开始使用 Clang。因此,我们有一个流程,可以每隔几周向所有开发人员和机器人提供新的 Clang 二进制文件。由于 Clang 的诊断信息出色 (一些 我们认为编译器应该捕获的 错误,我们添加了这些错误 是因为 Chromium 中的错误),速度很快,并且因为我们 Chromium 专用的 Clang 插件,许多 Chromium 开发人员多年来都从 gcc 切换到了 Clang。将 Clang 设为默认编译器可以消除新加入项目的人遇到的障碍。

2. 我们希望在 Chromium 中使用现代的 C++ 功能。这需要一个最近的工具链,我们认为至少需要 gcc 4.8。对于 Chrome for Android 和 Chrome for Chrome OS,我们将 gcc 编译器更新到 4.8(然后是 4.9),这很容易,因为这些端口使用的是非系统 gcc。Chrome for Mac 自 Chrome 15 以来一直使用 Chromium 的 Clang,并且处于良好状态。Chrome for iOS 使用 Xcode 5 的 Clang,该 Clang 也足够新。Chrome for Windows 使用 Visual Studio 2013 Update 4。在 Linux 上,切换到 Clang 是最简单的方法。

跟上大型多平台项目中 C++ 的发展

C++ 在很多年里一直保持静态。C++11 是自最初的 C++ 标准(1998 年 7 月 27 日批准)以来对 C++ 语言的第一次真正更新。C++98 早于 Google、YouTube、Facebook、Twitter 的创立,以及 Mac OS X 和 Windows XP 的发布,以及 x86 SSE 指令的发布。在这两个标准之间的时间里,iPod 的兴衰、几波社交网络的兴起和智能手机的爆炸式增长。

C++11 和 C++14 之间的时间为三年,下一个主要语言迭代预计将在 2017 年完成,距离 C++14 三年。这是一个巨大的变化,它对如何构建和发布 C++ 程序有影响。我们花了 3 年多的时间才达到可以在 Chromium 中使用 C++11 的状态;C++14 有望花更短的时间。(如果您要针对更少的平台,那么您会更容易。)

C++11 包含两个部分:新语言功能和新库功能。语言功能只需要在构建机器上进行构建时使用现代编译器,库功能需要在用户机器上的运行时使用新的标准库。

部署新的编译器在概念上相对简单。如果您的开发人员使用 Ubuntu LTS 版本,并且您让他们使用最新的 LTS 版本,那么他们每两年就会获得新的编译器,因此只需使用默认的系统编译器就意味着您落后了两年。需要一些流程才能相对透明地将新的工具链部署到您的开发人员 - 一个“常青编译器”。我们现在在 Chromium 中实现了这一点 - 在 Linux 上,通过使用 Clang。(我们仍然接受补丁以使 Chromium 可使用 gccs >= 4.8 进行构建,以供那些更愿意在本地编译而不是使用预编译二进制文件的人使用,并且我们仍然使用 gcc 作为 Chrome for Android 和 Chrome for Chrome OS 的目标编译器。)

库的情况略微棘手:在 Linux 和 Mac OS X 上,程序通常与系统 C++ 库链接。Chrome 希望更长时间地支持 Mac OS X 10.6(我们的用户似乎很喜欢这个 OS X 版本),并且它附带的唯一 C++ 库是 libstdc++ 4.2,它没有任何 C++11 部分。同样,Ubuntu Precise 只拥有 libstdc++ 4.6。看来,随着 C++ 更新的频率越来越高,产品要么必须停止支持旧的操作系统版本(即使这些旧版本上仍然有许多用户),要么非常缓慢地采用新的 C++ 功能,要么与捆绑的 C++ 标准库一起发布。后者意味着系统库不应该出于 ABI 原因而具有 C++ 接口,幸运的是,这种情况已经基本存在。

为了使事情变得更复杂,gcc 和 libstdc++ 预计同时更新。gcc 4.8 链接到 libstdc++ 4.8,因此在仍然链接到 Precise 的 libstdc++ 4.6 的情况下升级 gcc 4.8 并不容易。clang 明确支持 使用旧的 libstdc++ 版本进行构建。

对于 Chromium,我们选择现在启用 C++11 语言功能,然后在确定了库方面的情况后,再启用 C++11 库功能。这使我们能够 逐步采用 Chromium 中的 C++11 功能,但这并非没有风险:例如,vector<int> v0{42} 在旧的 C++ 库和具有 vector 构造函数(采用 initializer_list)的新 C++ 库中含义不同。由于这种情况,我们目前不允许使用统一初始化。

由于随着新的 C++ 更新节奏,捆绑 C++ 库似乎变得越来越普遍,因此如果编译器驱动程序能在这方面提供帮助,那就太好了。如果发布的产品包含多个可执行文件或共享库,那么仅仅静态链接 libstdc++ / libc++ 还不够,它们需要动态链接到具有正确 rpath 的共享 C++ 库,C++ 库可能需要不会与系统 C++ 库冲突的混淆符号名称,而系统 C++ 库可能由于其他系统库在内部使用它而被加载到同一个进程中(例如,可能使用具有应用程序特定名称的内联命名空间),等等。

未来方向

如上所述,我们正在努力解决 C++ 库问题。棘手的情况是 Chrome for Android(目前使用 STLport)和 Chrome for Mac。我们希望将 Chrome for Android 切换到 libc++(同时仍然使用 gcc 作为编译器)。在 Mac 上,我们也可能会将 libc++ 与 Chrome 捆绑在一起。

我们正在 努力 使 Clang 能够 用于编译 Chrome for Windows。这样做的主要动机是使用 AddressSanitizer,为开发人员提供一个具有出色诊断信息的编译器,以及使我们的 工具基础设施 在 Windows 上正常工作(例如用于 自动化大规模跨平台重构 以及构建我们的 代码搜索索引,尝试点击几个类名称,目前只有在 Linux 上构建的代码是超链接的)。除非 Clang 生成的 Chrome 二进制文件在二进制文件大小和性能方面都能与 Visual Studio 的二进制文件相媲美,否则我们不会在 Windows 上使用 Clang 作为生产编译器。(从开源的角度来看,能够使用开源编译器来编译开源程序确实很好。)

您可以通过 [email protected] 联系我们。