写点什么

LLVM 提议向 C 语言中加入模块机制

  • 2012-12-05
  • 本文字数:2096 字

    阅读完需:约 7 分钟

在今年 11 月的 LLVM 开发者大会上,来自 Apple 的 Doug Gregor 做了一场讲座,主题是向 C 语言中加入模块(Module)机制。讲座中提到:

长期以来,C 的预处理器就是程序员和工具的问题之源。写得不好的头文件致使宏污染和包含顺序等问题大量存在,程序员必须不断地与之斗争。为了缓解这些问题,开发者习惯上采用各种预处理器变通方案,比如 LONG_MACRO_PREFIXES 这种风格的很长的宏前缀,#include 防卫语句,或是临时使用#undef 来处理库中的宏。

另一方面,工具也必须能够处理重复解析相同头文件时所面对的内在可伸缩性问题,因为即便程序员并不希望,但不同的处理环境还是可能影响头文件的解释方式。

模块试图解决这一问题,它的理念是:隔离特定库的接口,并将其一次性编译为一种高效的、序列化的表示形式,当使用该库时,可以高效地导入,从而改进程序员的体验和编译过程的伸缩性。

该提议的基本前提是,作为一种加速编译并允许复用之前解析过的头文件的手段,即使编译最简单的文件,也要避免使用预处理器来包含大量头文件。在一个与“Hello World”同名的例子中,他强调到,一个包含 64 个字符的 C 程序经过预处理变成了 11 074 个字符,而一个包含 81 个字符的 C++ 程序预处理后变成了 1 161 033 个字符。他还指出,因为包含要依赖于预处理器当时的状态,所以重新解析头文件可能让程序很脆弱(比如,如果在 #include 之前使用#define FILE “myfile.txt”,预处理器会破坏头文件,从而导致构建失败)。

他的建议是使用一个新关键字 import 来加载模块。不同于预处理器的文本包含方式,编译器能够理解该模块是一个固定的版本,所以只解析一次。如果多次使用相同的模块,可以使用前面解析过的同一数据结构,不需要每次都重新解析。

模块也可以嵌套,这允许导入子模块;在所给的例子中,他演示了 std 模块中的子模块 stdio 可以使用 import std.stdio 来包含。导入模块之后,其中的所有公开 API 就都导入到客户代码中了,但非公开 API 是隐藏的。为了实现这种控制,模块需要声明哪些接口是公开的,哪些是非公开的,这可以利用 public 关键字:

复制代码
// stdio.c
export std.stdio:
public:
typedef struct {
} FILE;
int printf(const char*, …) {
}

请注意,在这个例子中,仅提供实现文件就可以了,不需要头文件。export 包含了模块的名字,这里就是 std.stdio。public 用于区分 API 的公开部分与非公开部分。这可以编译为库以及带有充分元数据的函数类型和宏,供客户代码使用。

当然,这只是对未来的一个建议,并非标准。那么这种方式应如何实现呢?建议使用头文件来处理现有模块的公开 API,并将模块定义为一组头文件:

复制代码
// /usr/include/module.map
module std {
module stdio { header "stdio.h" }
module stdlib { header "stdlib.h" }
module math { header "math.h" }
exclude header "assert.h"
}
module ClangAST {
umbrella "AST/AST.h"
module * { }
} // 可以使用“import ClangAST.Decl”来导入 AST/Decl.h

为便于以后生成模块(部分原因是方便 Objective-C 框架导出模块),“umbrella module”机制允许将一个目录下的一组头文件作为单个模块导出。

适于处理模块的编译器可以在头文件上利用单独的一遍(Pass)来构建模块,之后在随后的头文件中复用该模块的信息。(编译好的模块应采用什么格式尚未指定,可能交由具体的编译器定义。)模块中也可以加入附加的元信息,比如说明模块运行所需的库。这允许编译器处理每个模块所需的链接标记,从而避免了用户在链接时提供一大堆 -l 标记。

要使用模块,客户代码唯一需要修改的是将#include 替换为等价的 import。此外,因为在预处理后,模块中带有导出的函数和类型等信息,因此能够更好地进行编译诊断;利用这些信息,编译器报错和 IDE 快速修复等功能也能提示所需的 import,而不仅仅是直接失败。

最后,复用模块信息也允许将调试信息与模块关联起来,而非让这些信息重复出现在每个目标文件中。编译器和链接器就可以少生成一些调试信息,反过来又加速了编译过程。模块也为调试器提供了额外的类型信息(而不是将类型信息内联到每个目标文件中),因此调试器可以报告模块中定义的正确类型。

模块提议的净效应是,它提供了一种能够兼容现有工具的迁移途径,同时,在用户无需对原有代码进行多少修改的条件下,还带来了一些优点(主要是提升了编译速度,并改进了诊断错误消息和调试)。它也支持文件增量式升级,支持增量式地将单个预处理器指令切换为基于模块的导入机制。同时无需将编译速度测量当做模块表示的一部分,该工作已经在 LLVM 实现这些模块时进行了。虽然模块机制没有考虑版本或命名空间(很大程度上是因为必须满足向后兼容性),但该机制如果得以广泛应用的话,能够显著提升 C 和 C++ 程序的编译速度。此外,向后兼容性被明确提了出来,像 LLVM 的块(block)规范,当需要的时候很可能用于支持其他编译器或规范中的包含。不过,在广为使用的 C 和 C++ 编译器中,LLVM 编译器工具链是唯一的一个保持创新并以身作则的了。其他编译器是否会引入这些特性,可能取决于 LLVM 实现方案能否成功以及能够带来哪些益处。

查看英文原文 LLVM Proposes Adding Modules to C

2012-12-05 05:473206
用户头像
臧秀涛 略懂技术的运营同学。

发布了 300 篇内容, 共 150.2 次阅读, 收获喜欢 35 次。

关注

评论

发布
暂无评论
发现更多内容

android插件化原理,android开发视频百度网盘

android 程序员 移动开发

极光笔记丨百亿级数据的实时存取优化与实践

极光GPTBots-极光推送

高可用 软件架构 多级存储系统 高性能存储

Android开发者必须收藏的8个开源库,阿里蚂蚁金服五面

android 程序员 移动开发

Android开发者跳槽面试,深夜思考

android 程序员 移动开发

架构实战-模块一

唐敏

架构实战营

Android快速转战Kotlin教程,安卓已死

android 程序员 移动开发

Android插件化入门指南,程序员必看

android 程序员 移动开发

【推荐】如何将枯燥的大数据呈现为可视化的图和动画?

云智慧AIOps社区

大数据 开源 大前端 数据可视化 大屏可视化

Android开发者该学习哪些东西提高竞争力,做了5年Android

android 程序员 移动开发

Android开发面试技能介绍,动脑学院架构师vip视频

android 程序员 移动开发

Android开发面试题!动脑学院安卓教程vip2019

android 程序员 移动开发

没想到!我在简历上写了“精通MySQL”,阿里面试官跟我死磕后就给我发了高薪offer

收到请回复

程序员 编程语言 后端

Android性能优化面试题集锦,架构师必备

android 程序员 移动开发

Android技术类校招面试题汇总:android享学课堂vip课程下载

android 程序员 移动开发

Android推送技术解析,Android开发工程师面试题

android 程序员 移动开发

Android开发者面试如何系统复习,Android小技巧

android 程序员 移动开发

Android性能优化推荐书,享学课堂课程怎么样

android 程序员 移动开发

COSCon'21 参会指南 你想要的这里都有

开源社

开源社区 第六届中国开源年会 COSCon'21 开源社

Android技术类校招面试题汇总,享学课堂Android架构师课程

android 程序员 移动开发

Android技术类校招面试题汇总:扔物线rxJava

android 程序员 移动开发

极客时间 - 架构实战营 - 模块一作业

秋夫人

架构实战营

android插件化开发指南,享学课堂课程怎么样

android 程序员 移动开发

Android开发者该学习哪些东西提高竞争力,程序员面试防坑宝典

android 程序员 移动开发

Android开发进大厂面试必备技能,大厂面试必备技能

android 程序员 移动开发

Android开发面试题目,动脑学院vip

android 程序员 移动开发

Android攒了一个月的面试题及解答,Android程序员必会

android 程序员 移动开发

android插件化和热修复区别,扔物线学堂

android 程序员 移动开发

android插件化资源冲突,享学课堂vip二期

android 程序员 移动开发

从错误中学习

FunTester

学习 测试 bug 自学 FunTester

Android开发谈,html5移动开发即学即用网盘

android 程序员 移动开发

Android插件化主流框架和实现原理,挑战大厂重燃激情

android 程序员 移动开发

LLVM提议向C语言中加入模块机制_C++_Alex Blewitt_InfoQ精选文章