Carbon 语言 `Main//default` 默认库的文件类型演进:为何 `main.carbon` 取代 `main.impl.carbon`
Carbon 语言Main//default默认库的文件类型演进为何main.carbon取代main.impl.carbon【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang导读本文围绕 Carbon Language 仓库中的设计提案 proposals/p003403-change-main-default-to-an-api-file.md 展开系统讲解省略package指令时源文件所属的Main//default库由impl文件改为api文件这一核心变更。你将掌握 Carbon 中 API 文件与实现文件的命名规则、Main//default库的特殊地位、该变更对可执行程序入口文件fn Run的实际影响以及编译器toolchain/check中对应检查逻辑与测试用例的实现细节从而正确编写与组织 Carbon 程序入口文件。背景Carbon 的 API 文件与实现文件在 Carbon 语言中每个源文件都属于某个包package下的某个库library而每个库由一个 API 文件interface和零个或多个实现文件implementation构成。根据 docs/design/code_and_name_organization/README.md 的定义API 文件package指令不带impl修饰符例如package Geometry library Shapes;。其文件名必须以.carbon结尾不得以.impl.carbon结尾见 README.md 第 425-427 行。实现文件package指令带impl修饰符例如impl package Geometry library Shapes;。其文件名必须以.impl.carbon结尾见 README.md 第 432-434 行。实现文件会隐式导入同库的 API 文件这意味着只有实现文件而没有 API 文件的库在语义上是不成立的。反之一个 API 文件却可以没有对应的实现文件——API 文件本身可以承载全部实现代码这是单文件库得以存在的前提。问题Main//default曾经默认是一个impl文件在 Carbon 中如果源文件既没有package指令也没有library指令它就隐式地属于Main包下的默认库Main//default。Main//default是预期承载程序入口函数fn Run()的库。在提案 p003403 之前Main//default被默认规定为一个impl文件。而按照上述命名规则实现文件必须使用.impl.carbon扩展名因此无指令的入口文件将被命名为main.impl.carbon这与绝大多数开发者直觉中的main.carbon相去甚远。这正是提案在 Problem 一节 指出的核心问题。历史成因提案的 Background 一节追溯了这一现状的由来一般规则下单文件库天然可以是 API 文件。由于实现文件会隐式导入 API一个没有 API 文件的impl库必然导致导入失败而 API 文件不要求有实现文件所以单文件库用api文件表达是自然且自洽的。提案 #2550: Simplified package declaration for theMainpackage 选择impl作为默认并为此提供了一个空的、无法被导入的 API 文件来兜底但该提案并未给出选择impl的明确理由——这更像是顺带做出的决定。C 的main.cpp惯例可能影响了最初的选择C 中入口文件通常写作main.cpp这种更对等的感觉可能是impl默认被选中的心理来源。核心提案无指令文件默认为Main//default api提案 p003403 的核心变更只有一句话省略package指令时文件默认属于Main//default api而不是Main//default impl。由此带来两个用户可见的直接影响变更项变更前变更后文件扩展名.impl.carbon如main.impl.carbon.carbon如main.carbon文件数量限制允许存在多个Main//default impl文件每个可执行程序仅允许一个Main//default api文件第二个影响的根源在于 Carbon 的库规则一个库只能有一个 API 文件api只能定义一次。因此每个可执行程序有且仅有一个无指令的入口文件这与程序只有一个入口的直觉一致。移除的特殊规则变更还消除了一个此前的特殊规则文档中不再出现Main//default api是一个空文件的表述。在旧方案中为了给impl文件提供兜底的 API必须虚构一个无法被导入的空 API 文件改成api默认后这个特殊的空文件定义不再需要。保留的限制提案同时明确以下既有限制保持不变Main//default不能作为package、library或import指令中的显式名称该库只能通过同时省略package与library的方式隐式定义Main//default不能被导入。设计理由提案在 Rationale 一节引用 Code that is easy to read, understand, and write 这一项目目标把Run逻辑写在main.carbon中显然比写在main.impl.carbon中更直观。入口文件是每个程序作者最先接触、最常打开的文件其命名应当最贴近直觉。被否决的替代方案继续默认Main//default impl提案明确将Main//default impl即变更前的现状列为被否决的替代方案理由如下一致性Main//default api与其它场景下单文件库即 API 文件的惯例保持一致无需为Main//default单独开例外命名自由开发者更偏好main.carbon而非main.impl.carbon采用api默认后main.carbon的扩展名是通用规则的直接结果不需要为文件扩展名做任何特殊化处理规则简化不再需要Main//default api是空文件的特殊定义多实现文件价值有限虽然旧方案允许多个Main//default impl文件但Run只能定义在其中某一个文件里且Main//default api被定义为空文件、不允许共享任何内容因此多实现文件的实际价值非常有限。源码级佐证编译器如何落实这一规则当前仓库提案已合并的 toolchain 实现与上述规则完全吻合。核心逻辑位于 toolchain/check/check.cpp1. 隐式Main包的判定在 check.cpp 第 63 行编译器用常量定义了Main包名static constexpr llvm::StringLiteral MainPackageName Main;而在校验导入时第 133-136 行编译器判断文件是否通过省略显式包名而隐式属于Main包// True if the files package is implicitly Main (by omitting an explicit // package name). bool is_file_implicit_main !packaging || !packaging-names.package_id.has_value();也就是说既没有package指令、也没有library指令的文件packaging为空其包被认定为隐式的Main。这正是设计文档中Main//default规则第 363-367 行的实现If neither apackagedirective nor alibrarydirective is provided, the file is an API file forMain//default. Animplcannot be provided forMain//default.2. 禁止导入Main//defaultcheck.cpp 第 165-174 行对显式导入Main//default发出诊断错误// Diagnose explicit imports of Main//default. There is no api for it. // This lets other diagnostics handle explicit Main package naming. if (is_file_implicit_main is_import_implicit_current_package is_import_default_library) { CARBON_DIAGNOSTIC(ImportMainDefaultLibrary, Error, cannot import Main//default); ... }注释中的 There is noapifor it 直接呼应了提案中Main//default不能被导入的规则——它只能通过省略指令隐式定义不存在可供导入的实体。3. 同库导入的冗余检查第 154-163 行还处理了同库自我导入的情况API 文件导入自身报ImportSelffile cannot import itself而实现文件显式导入本库 API 则报ExplicitImportApiexplicit import ofapifromimplfile is redundant with implicit import因为实现文件本就隐式导入了 API。4. 测试用例验证仓库中的文件测试 toolchain/check/testdata/packages/fail_import_default.carbon 对这一系列诊断做了端到端验证fail_main_import_default.carbon无任何指令的文件import library default;触发ExplicitImportApi错误文件不能导入自身fail_main_lib_import_default.carbon使用library ...指令的文件import library default;触发ImportMainDefaultLibrary错误不能导入Main//defaultfail_default_api.carbonpackage A;触发ImportSelffail_default.impl.carbonimpl package A;触发ExplicitImportApi。这组测试同时覆盖了 API 文件、实现文件、无指令文件三种形态是理解Main//default边界规则的完整样例。实战编写你的main.carbon基于当前规则一个标准 Carbon 程序入口文件的写法非常直接——什么都不用声明文件天然成为Main//default api。仓库中的真实示例可以佐证这一点examples/hello_world.carbon// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import Core library io; fn Run() { Core.PrintStr(Hello world!\n); }examples/sieve.carbon 同样以无指令文件 fn Run() - i32的形式承载入口逻辑。甚至 examples/advent2024/ 系列如 day1_part1.carbon的每个day*_part*.carbon入口文件也都是通过import library dayX_common、import library sort导入同包其它库再定义各自的fn Run()——多个入口文件存在于同一包中各自构成独立的可执行程序。作为对比非入口的库文件则需要显式声明。例如预置库的聚合文件 core/prelude.carbon 使用了完整的包与库声明并通过export import对外公开各子库package Core library prelude; export import library prelude/copy; export import library prelude/default; export import library prelude/destroy; // ...实操要点总结程序入口文件不写package/library指令直接定义fn Run()文件名使用main.carbon或任意*.carbon每程序仅一个入口文件Main//default api每程序限一个这是 API 文件一库一 API规则的直接推论禁止导入与显式命名Main//default不能出现在package、library、import中也不能被任何文件导入非入口库文件使用package Name library Lib;API或impl package Name library Lib;实现显式归属分别对应.carbon与.impl.carbon扩展名。结语提案 p003403 是一次删繁就简的设计修正它把Main//default从需要特殊兜底规则的impl库收敛为与通用单文件库即 API 文件规则完全一致的api库。最终效果是Carbon 程序的入口文件回归直觉化的main.carbon同时消除了一项不必要的特殊规则也让每可执行程序仅一个入口文件成为类型系统层面的保证。对语言实现者而言check.cpp 中的MainPackageName常量、隐式Main判定与ImportMainDefaultLibrary诊断加上 fail_import_default.carbon 测试组构成了这套规则从设计到落地的完整闭环。【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考