Hacker News 中文摘要

RSS订阅

Free Pascal 编译器现已支持动态包 -- Free Pascal compiler now supports dynamic packages

很高兴宣布,面向自由帕斯卡编译器(Free Pascal Compiler)和拉撒路集成开发环境(Lazarus IDE)的完整动态包支持首次发布,现已可从本网站下载完整实现。动态包让用户无需重新构建整个 IDE,就能在数秒内创建和安装组件、控件及拉撒路扩展;也可用于在自己的程序中开发和部署插件,通过动态包库公开原生 Pascal 类和类型。作者还改进了编译器、运行时和拉撒路 IDE,并新增了扩展。

正文

很高兴宣布,Free Pascal Compiler(FPC)和 Lazarus IDE 现已首次发布完整的动态包(dynamic package)支持。对生态系统来说,这个功能期待已久,现在已可从本站 下载 获得完整实现。

动态包让用户无需重新编译整个 IDE,就能在几秒内创建并安装组件、控件和 Lazarus 扩展。它们也能用在自己的程序里,开发和部署通过动态包库暴露原生 Pascal 类与类型的插件。为了支持这一功能,我对编译器、其运行时库和 Lazarus IDE 做了大量改进,还额外编写了一些 IDE 扩展,以改善使用 Lazarus 包的体验。

动态包在 Linux、Windows 和 macOS 上实现为标准的共享库文件。它们包含由编译器生成的额外元数据,可使用新的 RTL 单元检查和查询。运行时库还提供了机制,用于在程序与包之间,或多个包之间,安全保留线程变量,并管理字符串、动态数组等动态类型。

视频:动态包示例

Video 3

部署程序时,你仍然可以把所有内容打包进单个可执行文件。或者,也可以把它拆分成多个动态包,这些包能在程序运行期间被替换,从而提供一个插件系统。

限制

动态包有一些限制。首先,包内单元不能与包本身同名。我增强了默认的包系统,使生成的 Pascal 源文件自动在包名后附加 Package 一词。例如,创建一个名为 ElectroTools.lpk 的包时,列出包内所有单元的源文件将命名为 ElectroToolsPackage.pas,而不是 ElectroTools.pas。

另一个限制是,单元名在不同包之间必须唯一。如果别人已经写了一个名为 Widgets 的单元,你就不能安装另一个包含同名单元的包。你要么选择安装哪个包,要么重命名冲突的单元之一。

动态包也比普通共享库更大,因为它们包含内部所有内容的映射。剥离动态包会移除其作为动态包运行所必需的元数据。

RTL 增强

RTL 新增了 DynPkgTypes.pas 单元,用于读取动态包信息。其中定义的 TPackageType 记录描述了包内类型:UnitName 为声明该类型的单元名,Name 为类型名,Kind 为类型种类(TTypeKind),Info 为该类型的 RTTI(PTypeInfo),若 Kind 为 tkClass,则 ClassType 为对应的类(TClass),否则为 nil。

运行时库已得到增强以支持动态包,包含检查其内容所需的元数据,以及跨包边界安全管理动态类型和线程变量所需的机制。你可以从包中获取这些经过实践检验的 RTTI 信息来处理其中的内容。RTL 中已有足够函数用于操作动态包,完成加载、枚举、搜索和运行时卸载等全部所需操作。

Lazarus 增强

我对 Lazarus IDE 做了多项增强,以更好地利用动态包。

打开 Lazarus 时,你首先会注意到一个可以显示在 IDE 之外的新进度窗口。当你修改了 IDE 已注册包的源代码时,系统会检测到更改,并在 Lazarus 启动前自动重新构建该包。在此过程中,进度窗口会通知你已检测到更改,且正在重新构建包。

选择重新构建整个 IDE 时,也会出现同一个窗口。它会保持可见,并显示当前操作的信息,包括 IDE 重启前的预计剩余时间。添加或移除包时,如果操作超过五秒,也会出现该进度窗口。这在一次安装多个包时可能发生,而一次安装多个包也是一项新功能。

另一项增强是新的 Packages 窗口,默认停靠在右侧。它显示你最近打开的包,且列表在 Lazarus 会话之间保留。你可以浏览包内的文件,双击条目即可打开。

打开一个已安装的包,并在其包窗口中点击 Compile(编译)时,任何关联的控件、组件或扩展都会在一两秒内更新。这大大加快了开发速度,因为以前需要重新构建整个 IDE 的更改,现在几乎可以立即生效。

列出可用包的包菜单也得到了改进。现在添加或移除包会更新 IDE,而无需重新构建。

包选项也得到了扩展。在 IDE Integrations 下,现在可以将包限制为特定平台或 widgetset。如果包不满足当前平台或 widgetset 要求,它就不会出现在包列表中。当 IDE 检测到更改或原本会尝试打开该包时,也会忽略它。

例如,假设你为 Windows 的 IShellView COM 接口开发了一个 TWinControl 实现,你可以将该包限制为仅当 Lazarus 运行在 Windows 上时才可用。

为了展示动态包的能力,我还创建了一项新功能:用于 Lazarus 扩展的窗体或框架转换功能。它能把任意窗体或框架转换为可安装的控件,并自动添加到组件面板。所有控件、事件、方法和属性都会被复制到新控件中。

这样就可以可视化地设计和布局新控件,或轻松地在其他项目中复用现有窗体和框架。

注意: 如果你尝试构建某个正被已打开窗体使用的包,IDE 会要求你在构建包之前保存或关闭该窗体。

这些功能及更多内容现已可下载。对 FPC 和 Lazarus 的完整更改已提交到 GitLab 上我名为 dynamic packages 的 fork 分支。

如果遇到问题,请通过相关分支关联的 GitLab issue 跟踪器报告。如果想讨论动态包或提问,可以使用论坛。请注意,必须先由版主批准你的账号,才能创建新帖。

参与贡献

如果你想为这个项目提供帮助,站点需要版主。如果有意参与贡献,可以给我(sysrpl)发私信。

我在 macOS 上工作和生成必要构建方面也有困难。如果有人愿意捐赠一台 M1 Macintosh,请给我发私信。我真的很想编写支持 M1 架构动态包所需的编译器代码。

评论

社区对 FPC/Lazarus 动态包支持的发布总体偏正面,欢迎者认为它省去了重建 IDE 的麻烦,并唤起了对 Pascal 快速开发的怀旧与兴趣。讨论的主要分歧则在于:这是否是官方 Lazarus 主线能力,还是只是一个分支项目;同时也有人批评 FPC 语言特性停滞,并质疑 Pascal 在当今是否仍值得用于实际项目。

肯定动态包对 FPC/Lazarus 生态的实用价值

  • 发布者称动态包让组件、控件和 IDE 扩展能在数秒内安装,无需重建整个 Lazarus IDE;也可用来开发并部署插件,通过动态包库直接暴露原生 Pascal 类与类型。评论中有人简单致谢,也有人表示因厌倦 JavaScript、Python 等现代解释型语言和框架,想重新尝试 Turbo Pascal 时代的快速开发体验。(较多人)
  • > 祝贺整个团队;我一直欣赏 Pascal 的设计哲学和 Turbo Pascal 的快速开发能力,对 JavaScript、Python 等现代解释型语言与框架越来越失望,因此打算了解一下。(@publlus_enigma)

质疑这不是官方 Lazarus,而是分支项目

  • 有评论指出,发布内容看起来是 Lazarus 的一个 fork,并提醒官方 Lazarus 另有其站,暗示该功能未必已进入官方主线。(少数人)
  • > 这似乎是 Lazarus 的一个分支,官方 Lazarus 在别处。(@kristianp)

认为 FPC 语言本身停滞,缺少现代声明语法

  • 有人批评 FPC 至今仍要求变量声明集中在块顶部,类似 C89,而不像 Delphi 那样支持在任意位置声明变量;这种滞后被归因于生态长期停滞。(少数人)
  • > 相比 Delphi,FPC 缺失能在任意位置声明变量的能力,仍像 C89 那样要求声明集中在块顶;这大概就是生态停滞的结果。(@HexDecOctBin)

怀疑 Pascal 现在是否还有人用、为何选它做项目

  • 有人从个人经历出发,说除了 80 年代课业和 Apple 相关场景,专业领域几乎没听过 Pascal 被使用;面对如今众多语言且 Pascal 已很少被教,质疑为何还有项目会选择它。(少数人)
  • > 我 80 年代学 Pascal,后来只在课业和 Apple 相关场景听说有人用;如今语言选择那么多、Pascal 也很少被教,为什么还有人会在项目里用它?(@sizzzzlerz)

有价值的补充

  • 发布者还称对编译器、运行时和 Lazarus IDE 做了大量改进,并新增了 IDE 扩展来优化包的使用体验;这说明动态包牵动了工具链多层改动,而不仅是加了一个安装功能。
  • 据称这套动态包支持由众多开源开发者历时 20 多年才做成,侧面反映出 Pascal 生态在包管理与插件化上的落地之慢。