仓颉语言工具链设计与实现

文摘   2024-09-09 19:30   上海  

章旭东


编程语言实验室工具链高级工程师


在软件开发中,工具链是一组编程工具,用于执行复杂的软件开发任务或创建软件产品,该软件产品通常是另一个计算机程序或一组相关程序[1]。通常这些工具可以包括包管理、调试器、静态检查、格式化、自动化测试工具等。工具链的目的是提高开发效率、简化开发流程,并帮助开发人员更好地完成项目。


仓颉规划了完整的工具链,以帮助开发者高效的完成软件开发、编译、调试调优等各个环节的工作。


图1:仓颉工具链全景


本篇介绍其中的三个软件:包管理工具(cjpm)、静态检查工具(cjlint)和调试工具(cjdb)。


包管理工具 (cjpm)


cjpm 是仓颉语言的包管理工具,为仓颉开发者提供了简易的编译、测试和运行入口。下图展示了cjpm的功能设计。


图2:cjpm架构图


接下来介绍cjpm的基本功能和未来规划。


1

基础功能


模块初始化


开发者可以使用cjpm init命令初始化一个新的仓颉模块,这个命令会生成一个包含cjpm.toml模块配置文件和src仓颉源码目录的工程结构。cjpm.toml文件是模块的配置文件,它使用toml格式,包含了模块名、版本号、依赖模块等基础信息,同时支持用户自定义透传编译命令、导入依赖、管理工作空间等功能[2]


下图展示了demo模块的初始化过程。其中,dependencies字段用于配置该模块所依赖的其它模块,package字段用于指定该模块的一些公共配置项:cjc-version显示当前使用的编译器版本、compile-option可用于透传编译器提供的编译选项、name字段代表该模块的模块名、output-type字段用于指定该模块的产物类型等。


图3:模块初始化演示




依赖检查和源码构建


开发者可以使用cjpm build命令一键式构建仓颉项目,如下图所示。


图4:模块编译演示


cjpm首先会通过toml配置文件汇总所有模块的信息,接下来会扫描每个模块的源码目录并汇总所有包的信息,然后通过拓扑排序算法分析包之间的依赖关系,最后调用cjc编译器完成并行编译。




运行和测试


开发者可以使用cjpm run命令构建并运行仓颉项目,使用cjpm test命令运行项目中定义的单元测试[3]


图5:模块运行和单元测试演示




依赖管理


cjpm为开发者在cjpm.toml配置文件中提供了dependencies字段去指定构建依赖项。该字段目前支持导入本地的源码依赖模块和git依赖模块,后续也会支持导入中心仓依赖模块,cjpm会帮助开发者在构建项目前自动加载、汇总并编译这些依赖。此外,cjpm也为开发者提供了单元测试依赖、构建脚本依赖、二进制依赖和互操作依赖等可配置字段,从而简化用户的编译流程。




多平台兼容


cjpm 目前已经支持了windows、linux、macos等平台,陆续也会支持更多的平台和架构,以便仓颉项目能够在更广泛的平台上运行。

cjpm.toml是一个平台无关的文件,可直接在多平台上使用,开发者无需额外切换的成本。对于有平台差异的配置项,cjpm为开发者提供了target字段定义在各个平台上的行为,举例如下:


图6:toml文件的target字段使用示例




命令扩展和构建脚本机制


软件开发中,开发者可能需要外接其它的功能,以更好的完成工程管理。

cjpm 提供了命令扩展机制,开发者可以通过编写自己的代码构建出文件名形如 cjpm-cmd 的可执行文件,此时直接使用cjpm cmd命令即可间接调用该可执行文件的扩展功能,cjpm期待更多的开发者参与cjpm扩展功能的开发,以更好的适配各种项目构建场景。


cjpm 还提供了构建脚本机制,用于支持定制cjpm 某些操作的前序/后序操作。如图7所示,开发者自定义了编译cffi模块的stagePreBuild任务和删除cffi源码的stagePostBuild任务。当执行build命令时,cjpm会先执行stagePreBuild任务,build完成后再执行stagePostBuild任务。


图7:构建脚本功能演示



2

未来规划


cjpm作为仓颉大型项目构建和管理的入口,计划提供更多的能力,以提升开发效率。


  • 提供仓颉语言的中心仓,支持开发者发布和下载仓颉软件。

  • 支持语义化版本控制、依赖替换等能力,提升复杂项目管理能力。

  • 优化构建缓存和增量构建机制,提升构建效率。


静态检查(cjlint)


1

基础功能


静态检查可以帮助发现程序中潜在的编码问题,仓颉语言提供了cjlint 来完成这一功能。其在不执行程序的情况下,通过对源代码的分析来发现和识别潜在的代码错误和安全漏洞,提升代码的质量。仓颉编译器提供了AST(Abstract Syntax Tree)和CHIR(Cangjie High-Level IR)等编译中间产物,用于承载不同级别的源码结构和语义信息。基于这些信息,cjlint可以对应用代码进行分析和检查。


编程风格、命名规范检查以及语法模式识别等场景只需要语法信息即可完成,所以基于更贴近源码的AST来完成,从而获得更快的分析速度。


但是对于需要深入分析的性能和安全性问题,我们则基于具备良好数据流分析能力的CHIR来进行。经过编译器前端的处理,源码被映射为严格顺序执行的basic block, block之间的跳转关系形成边,从而构成控制流图CFG(Control Flow Graph)。cjlint通过在控制流和数据流分析中识别程序中的所有路径,分析路径中的变量使用、资源分配和释放、条件判断等情况,实现规则的有效告警。


基于CHIR的静态检查的核心原理主要集中在对程序的结构化分析上。利用CHIR提供的抽象和结构化信息,通过数据流分析、控制流分析、抽象解释和符号执行等技术,对程序进行全面而深入的静态分析。数据流分析追踪变量的定义和使用,控制流分析检查程序的执行路径,抽象解释在抽象域上模拟程序执行,而符号执行则使用符号值探索程序的不同路径。这些方法相互补充,共同构成了一个强大的分析框架,能够检测各种潜在的程序错误(如未初始化变量、空指针引用、缓冲区溢出)、识别优化机会(如死代码消除、常量传播),并提供关于程序行为的有价值见解。通过在IR级别进行这些分析,静态检查可以独立于源语言和目标平台,提供更通用和强大的分析能力。


以如下仓颉源码为例,我们需要判断打开的临时文件在程序结束时是否被删除。根据此用例,可以得到如下图所示的CFG信息,if语句使得CFG中存在不同的路径分支。在else分支对应的block C中可以发现在block A中打开的文件没有删除,因此触发资源泄露的告警。


图8:cfg(Control Flow Graph)信息



2

未来规划


近年来,以智能化编程辅助插件为代表的工具受到开发者的欢迎和重视。因此, cjlint未来的发展方向应该涵盖三个方面:


  • 智能化:在静态检查工具中引入机器学习和人工智能技术,以更好地理解代码的上下文和开发者的意图,有效地提高检测的准确性、降低漏报率;

  • 跨语言:复杂项目,通常涉及到多种编程语言,跨语言的代码质量检查场景越来越多,不断丰富cjlint支持的编程语言,可以整体提升仓颉复杂应用的质量;

  • 检查效率提升:支持增量代码检查,从而在大型工程上提升开发效率。


cjdb


调试是程序开发中必不可少的一环,仓颉语言通过cjdb为开发者提供程序调试能力[4]


仓颉语言是面向多场景的应用编程语言,为了兼容现有的生态以及支持不同的设备,仓颉支持不同编译模式,并且支持高效跨语言调用。为此,cjdb提供了统一的API和CLI调试接口,在应用开发者层面屏蔽了不同编译模式下的运行时调试差异,提供给用户无感知的统一调试体验。静态编译模式下仓颉调试器整体架构如下:


图9:仓颉调试器整体架构


1

基础能力


cjdb是一款基于开源LLDB开发的仓颉调试工具,具备仓颉语言的基础调试能力:


1) 源码断点/函数断点/条件断点(breakpoint)

2) 观察点(watchpoint)

3) 单步调试(s,n, finish, continue)

4) 变量查看/变量修改(print,set)

5) 表达式计算(expr)

6) 仓颉线程查看(cjthread)


此外,由于仓颉支持和C语言的互调。为了使开发者无需在不同语言的调试器之间来回切换,仓颉提供了跨语言调试能力,使开发者在同一调试界面中无缝切换调试不同语言的代码,提升代码调试效率。


2

跨语言调试


cjdb跨语言调试原理如下图所示:


图10:跨语言调试原理

 

仓颉函数通过wrapper函数调用C函数,C侧通过wrapper函数调回到仓颉。调试时在仓颉函数代码行执行step in能够直接单步进入到C函数内,会跳过中间的wrapper函数,在C函数里面能够正常进行调用栈查看、变量查看修改、step in/step over操作,在C侧函数进行finish操作后能正常返回到仓颉函数,用户不会感知wrapper函数。


3

未来规划


随着仓颉编程语言的不断发展和完善,cjdb调试功能也将不断得到优化和扩展,如下是目前计划支持的能力。


  • 提升图形化调试能力,降低cjdb调试入门门槛;

  • 增强并发调试能力,以支持开发者高效的调试并发问题;

  • 提供仓颉和ArkTS的跨语言调试能力


引用


[1] Wikipedia: https://en.wikipedia.org/wiki/Toolchain
[2] https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/cj-wp-package-V5
[3] https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/cj-wp-testframework-V5
[4] https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/cj-wp-debugger-V5


点击下方阅读全文,试用仓颉编程语言SDK

仓颉编程语言
仓颉编程语言官方公众号
 最新文章