仓颉之编译和构建的奇妙旅程


                                                                                                                                                <span id="OSC_h2_1"></span> 

1 概述

1.1 案例介绍

仓颉编程语言作为一款面向全场景应用开发的现代编程语言,通过现代语言特性的集成、全方位的编译优化和运行时实现、以及开箱即用的 IDE工具链支持,为开发者打造友好开发体验和卓越程序性能。

案例结合代码体验,让大家更直观的了解仓颉语言中的编译和构建。

1.2 适用对象

  • 个人开发者
  • 高校学生

1.3 案例时间

本案例总时长预计40分钟。

1.4 案例流程

abf6ec3409dff70ce74ed05ed269792a.png
说明:

  1. 进入华为开发者空间,登录云主机;
  2. 使用CodeArts IDE for Cangjie编程和运行仓颉代码。

1.5 资源总览

资源名称 规格 单价(元) 时长(分钟)
开发者空间 – 云主机 鲲鹏通用计算增强型 kc2 | 4vCPUs | 8G | Ubuntu 免费 40

仓颉之编译和构建的奇妙旅程  👈👈👈体验完整版案例,点击这里。

2 运行测试环境准备

2.1 开发者空间配置

面向广大开发者群体,华为开发者空间提供一个随时访问的“开发桌面云主机”、丰富的“预配置工具集合”和灵活使用的“场景化资源池”,开发者开箱即用,快速体验华为根技术和资源。

领取云主机后可以直接进入华为开发者空间工作台界面,点击打开云主机 > 进入桌面连接云主机。没有领取在开发者空间根据指引领取配置云主机即可,云主机配置参考1.5资源总览

a1aae6ff53aac98855ef597dd6899967.png

552fc96c3b58a06e294e4a760ae719e3.PNG

2.2 创建仓颉程序

点击桌面CodeArts IDE for Cangjie,打开编辑器,点击新建工程,保持默认配置,点击创建

产物类型说明

  • executable,可执行文件;
  • static,静态库,是一组预先编译好的目标文件的集合;
  • dynamic,动态库,是一种在程序运行时才被加载到内存中的库文件,多个程序共享一个动态库副本,而不是像静态库那样每个程序都包含一份完整的副本。

28acbca9146a8a6aacbfdd4f6ac3791b.png

2.3 运行仓颉工程

创建完成后,打开src/main.cj,参考下面代码简单修改后,点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

<strong>package</strong> demo
<span style="color:#697070">// 第一个仓颉程序</span>
main(): Int64 {
    <span style="color:#397300">println</span>(<span style="color:#880000">"hello world"</span>)
    <span style="color:#397300">println</span>(<span style="color:#880000">"你好,仓颉!"</span>)
    <strong>return</strong> <span style="color:#880000">0</span>
}

(* 注意:后续替换main.cj文件代码时,package demo保留)

(* 仓颉注释语法:// 符号之后写单行注释,也可以在一对 /* 和 */ 符号之间写多行注释)

d1e16b48f5f9620fafe9fc59ae62a367.png

到这里,我们第一个仓颉程序就运行成功啦!后面案例中的示例代码都可以放到main.cj文件中进行执行,接下来我们继续探索仓颉语言。

3 仓颉之编译和构建

3.1 cjc使用

cjc是仓颉编程语言的编译命令,其提供了丰富的功能及对应的编译选项,本章将对基本使用方法进行介绍。关于编译选项详情,请查阅  cjc 编译选项章节。

cjc使用方式如下:

cjc [<strong>option</strong>] <strong>file</strong>...

具体代码操作如下:

Step1:在华为开发者空间云主机桌面新建hello.cj 文件,内容如下

main(): Int64 {
    <span style="color:#397300">println</span>(<span style="color:#880000">"hello Cangjie"</span>)
    <span style="color:#397300">println</span>(<span style="color:#880000">"你好,仓颉!"</span>)
    <strong>return</strong> <span style="color:#880000">0</span>
}

d1766861b45b41d75830fde948ff7b07.PNG

Step2:在华为开发者空间云主机桌面右键选择Open Terminal Here打开终端命令窗口。

95ad667b4b4a1f681c90b32e94e0e8fb.PNG

Step3:在终端命令窗口输入命令:cjc hello.cj,编译文件,此时工作目录下会新增可执行文件main。

e458fbe114d5a79fbe610342c82dccc2.PNG

Step4:在终端命令窗口输入命令:./main,执行main文件。

ef27349eaae2bdf789d58ec24c7c2b1a.PNG

3.2 cjpm介绍

CJPM(Cangjie Package Manager) 是仓颉语言的官方包管理工具,用于管理、维护仓颉项目的模块系统,并且提供更简易统一的编译入口,支持自定义编译命令。包管理器同时也提供基于仓颉语言原生的自定义构建机制,允许开发者在构建的不同阶段增加预处理和后处理流程,实现构建流程可灵活定制,能够满足开发者不同业务场景下的编译构建诉求。

cjpm基本使用方法:

通过 cjpm -h 即可查看主界面,由几个板块组成,从上到下分别是: 当前命令说明、使用示例(Usage)、支持的可用命令(Available subcommands)、支持的配置项(Available options)、更多提示内容。

具体操作如下:

在终端命令窗口输入命令:cjpm -h

29b61c2d172d1fddd3671f31cb6a0b5d.PNG

cjpm init 用来初始化一个新的仓颉模块或者工作空间。初始化模块时会默认在当前文件夹创建 cjpm.toml 文件,并且新建 src 源码文件夹,在 src 下生成默认的 main.cj 文件。

具体操作如下:

9da134cf9d20f4a685d43b02b5cb951e.PNG

cjpm build 用来构建当前仓颉项目,执行该命令前会先检查依赖项,检查通过后调用 cjc 进行构建。通过 cjpm build -V 命令可以打印所有的编译过程命令。

具体操作如下:

1a9efdef0a955c572d132c72ab906f79.PNG

cjpm.toml配置文件说明:

配置文件 cjpm.toml 用来配置一些基础信息、依赖项、编译选项等内容,cjpm 主要通过这个文件进行解析执行。

配置文件代码如下所示:

<strong>[package]</strong> <span style="color:#697070"># 单模块配置字段,与 workspace 字段不能同时存在</span>
  <span>cjc-version</span> = <span style="color:#880000">"0.53.1"</span> <span style="color:#697070"># 所需 `cjc` 的最低版本要求,必需</span>
  <span>name</span> = <span style="color:#880000">"demo"</span> <span style="color:#697070"># 模块名及模块 root 包名,必需</span>
  <span>description</span> = <span style="color:#880000">"nothing here"</span> <span style="color:#697070"># 描述信息,非必需</span>
  <span>version</span> = <span style="color:#880000">"1.0.0"</span> <span style="color:#697070"># 模块版本信息,必需</span>
  <span>compile-option</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 额外编译命令选项,非必需</span>
  <span>link-option</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 链接器透传选项,可透传安全编译命令,非必需</span>
  <span>output-type</span> = <span style="color:#880000">"executable"</span> <span style="color:#697070"># 编译输出产物类型,必需</span>
  <span>src-dir</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 指定源码存放路径,非必需</span>
  <span>target-dir</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 指定产物存放路径,非必需</span>
  <span>package-configuration</span> = {} <span style="color:#697070"># 单包配置选项,非必需</span>

<strong>[workspace]</strong> <span style="color:#697070"># 工作空间管理字段,与 package 字段不能同时存在</span>
  <span>members</span> = [] <span style="color:#697070"># 工作空间成员模块列表,必需</span>
  <span>build-members</span> = [] <span style="color:#697070"># 工作空间编译模块列表,需要是成员模块列表的子集,非必需</span>
  <span>test-members</span> = [] <span style="color:#697070"># 工作空间测试模块列表,需要是编译模块列表的子集,非必需</span>
  <span>compile-option</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 应用于所有工作空间成员模块的额外编译命令选项,非必需</span>
  <span>link-option</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 应用于所有工作空间成员模块的链接器透传选项,非必需</span>
  <span>target-dir</span> = <span style="color:#880000">""</span> <span style="color:#697070"># 指定产物存放路径,非必需</span>

<strong>[dependencies]</strong> <span style="color:#697070"># 源码依赖配置项,非必需</span>
  <span>coo</span> = { git = <span style="color:#880000">"xxx"</span>,branch = <span style="color:#880000">"dev"</span> } <span style="color:#697070"># 导入 `git` 依赖</span>
  <span>doo</span> = { path = <span style="color:#880000">"./pro1"</span> } <span style="color:#697070"># 导入源码依赖</span>

<strong>[test-dependencies]</strong> <span style="color:#697070"># 测试阶段的依赖配置项,格式和 dependencies 相同,非必需</span>

<strong>[script-dependencies]</strong> <span style="color:#697070"># 构建脚本的依赖配置项,格式和 dependencies 相同,非必需</span>

<strong>[ffi.c]</strong> <span style="color:#697070"># 导入 C 语言的库依赖,非必需</span>
  <span>clib1.path</span> = <span style="color:#880000">"xxx"</span>

<strong>[profile]</strong> <span style="color:#697070"># 命令剖面配置项,非必需</span>
  <span>build</span> = {} <span style="color:#697070"># build 命令配置项</span>
  <span>test</span> = {} <span style="color:#697070"># test 命令配置项</span>
  <span>customized-option</span> = {} <span style="color:#697070"># 自定义透传选项</span>

<strong>[target.x86_64-unknown-linux-gnu]</strong> <span style="color:#697070"># 后端和平台隔离配置项,非必需</span>
  <span>compile-option</span> = <span style="color:#880000">"value1"</span> <span style="color:#697070"># 额外编译命令选项,适用于特定 target 的编译流程和指定该 target 作为交叉编译目标平台的编译流程,非必需</span>
  <span>link-option</span> = <span style="color:#880000">"value2"</span> <span style="color:#697070"># 链接器透传选项,适用于特定 target 的编译流程和指定该 target 作为交叉编译目标平台的编译流程,非必需</span>

<strong>[target.x86_64-w64-mingw32.dependencies]</strong> <span style="color:#697070"># 适用于对应 target 的源码依赖配置项,非必需</span>

<strong>[target.x86_64-w64-mingw32.test-dependencies]</strong> <span style="color:#697070"># 适用于对应 target 的测试阶段依赖配置项,非必需</span>

<strong>[target.x86_64-unknown-linux-gnu.bin-dependencies]</strong> <span style="color:#697070"># 仓颉二进制库依赖,适用于特定 target 的编译流程和指定该 target 作为交叉编译目标平台的编译流程,非必需</span>
  <span>path-option</span> = [<span style="color:#880000">"./test/pro0"</span>, <span style="color:#880000">"./test/pro1"</span>] <span style="color:#697070"># 以文件目录形式配置二进制库依赖</span>
<strong>[target.x86_64-unknown-linux-gnu.bin-dependencies.package-option]</strong> <span style="color:#697070"># 以单文件形式配置二进制库依赖</span>
  <span>"pro0.xoo"</span> = <span style="color:#880000">"./test/pro0/pro0.xoo.cjo"</span>
  <span>"pro0.yoo"</span> = <span style="color:#880000">"./test/pro0/pro0.yoo.cjo"</span>
  <span>"pro1.zoo"</span> = <span style="color:#880000">"./test/pro1/pro1.zoo.cjo"</span>

3.3 条件编译

开发者可以通过预定义或自定义的条件完成条件编译;仓颉目前支持导入和声明的条件编译。

仓颉支持使用内置编译标记 @When 来完成条件编译,编译条件使用 [] 括起来,[] 内支持输入一组或多组编译条件。@When 可以作用于导入节点和除 package 外的声明节点。

内置编译条件变量:

仓颉提供了五个内置条件变量: os、 backend、 cjc_version、 debug 和 test。

os:

os表示目标平台的操作系统。os 支持 == 和 != 两种操作符。支持的操作系统有:Windows、Linux、macOS。

具体代码操作如下:

Step1:复制以下代码,替换main.cj文件中的代码。(保留package)

<strong>@When</strong>[os == <span style="color:#880000">"Linux"</span>]
func foo() {
    <span style="color:#397300">print</span>("Linux, ")
}
<strong>@When</strong>[os == <span style="color:#880000">"Windows"</span>]
func foo() {
    <span style="color:#397300">print</span>("Windows, ")
}
<strong>@When</strong>[os != <span style="color:#880000">"Windows"</span>]
func fee() {
    <span style="color:#397300">println</span>("NOT Windows")
}
<strong>@When</strong>[os != <span style="color:#880000">"Linux"</span>]
func fee() {
    <span style="color:#397300">println</span>("NOT Linux")
}
<strong>main</strong>() {
    <span style="color:#397300">foo</span>()
    <span style="color:#397300">fee</span>()
}

Step2:点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

96ae175039bcfe3e6343154b6361e707.PNG

如果在 Windows 环境下编译执行,会得到 Windows, NOT Linux 的信息;如果是在 Linux 环境下,则会得到 Linux, NOT Windows 的信息。

backend  

backend 是仓颉内置的条件。backend 条件支持 == 和 != 两种操作符。

支持的后端和处理器架构有:cjnative、cjnative-x86_64、cjnative-aarch64。

当使用的条件为 cjnative 时,仓颉编译器会自动获取当前运行环境的架构信息,并自动补全。

具体代码操作如下:

Step1:复制以下代码,替换main.cj文件中的代码。(保留package)

<strong>@When</strong>[backend == <span style="color:#880000">"cjnative-x86_64"</span>]
func foo() {
    <span style="color:#397300">print</span>("cjnative-x86_64 backend, ")
}
<strong>@When</strong>[backend == <span style="color:#880000">"cjnative-aarch64"</span>]
func foo() {
    <span style="color:#397300">print</span>("cjnative-aarch64 backend, ")
}
<strong>@When</strong>[backend != <span style="color:#880000">"cjnative-x86_64"</span>]
func fee() {
    <span style="color:#397300">println</span>("NOT cjnative-x86_64 backend")
}
<strong>@When</strong>[backend != <span style="color:#880000">"cjnative-aarch64"</span>]
func fee() {
    <span style="color:#397300">println</span>("NOT cjnative-aarch64 backend")
}

<strong>main</strong>() {
    <span style="color:#397300">foo</span>()
    <span style="color:#397300">fee</span>()
}

Step2:点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

8c24ed12f9eadd57a8202f2a71e85a01.PNG

cjc_version :

cjc_version 是仓颉内置的条件,开发者可以根据当前仓颉编译器的版本选择要编译的代码。cjc_version 条件支持 ==、!=、>、<、>=、<= 六种操作符,格式为 xx.xx.xx 支持每个 xx 支持 1-2 位数字,计算规则为补位 (补齐 2 位) 比较,例如:0.18.8 < 0.18.11, 0.18.8 == 0.18.08。

具体代码操作如下:

Step1:复制以下代码,替换main.cj文件中的代码。(保留package)

<strong>@When</strong>[cjc_version == <span style="color:#880000">"0.18.6"</span>]
func foo() {
    <span style="color:#397300">println</span>("cjc_version equals <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>@When</strong>[cjc_version != <span style="color:#880000">"0.18.6"</span>]
func foo() {
    <span style="color:#397300">println</span>("cjc_version is NOT equal to <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>@When</strong>[cjc_version > <span style="color:#880000">"0.18.6"</span>]
func fnn() {
    <span style="color:#397300">println</span>("cjc_version is greater than <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>@When</strong>[cjc_version <= <span style="color:#880000">"0.18.6"</span>]
func fnn() {
    <span style="color:#397300">println</span>("cjc_version is less than or equal to <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>@When</strong>[cjc_version < <span style="color:#880000">"0.18.6"</span>]
func fee() {
    <span style="color:#397300">println</span>("cjc_version is less than <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>@When</strong>[cjc_version >= <span style="color:#880000">"0.18.6"</span>]
func fee() {
    <span style="color:#397300">println</span>("cjc_version is greater than or equal to <span style="color:#880000">0.18</span>.<span style="color:#880000">6</span>")
}
<strong>main</strong>() {
    <span style="color:#397300">foo</span>()
    <span style="color:#397300">fnn</span>()
    <span style="color:#397300">fee</span>()
}

Step2:点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

备注:根据 cjc 的版本,上面代码的执行输出结果会有不同。

eef42ff7ba54a72bf1134b9be831d9c7.PNG

debug :

debug 表示当前是否启用了调试模式即开启 -g 编译选项,可以用于在编译代码时进行调试和发布版本之间的切换。debug 条件仅支持逻辑非运算符(!)。

具体代码操作如下:

Step1:复制以下代码,替换main.cj文件中的代码。(保留package)

<strong>@When</strong>[debug]
func foo() {
    <span style="color:#397300">println</span>("debug")
}
<strong>@When</strong>[!debug]
func foo() {
    <span style="color:#397300">println</span>("NOT debug")
}
<strong>main</strong>() {
    <span style="color:#397300">foo</span>()
}

Step2:点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

bc71a7184008991326a06c4c27814bc2.PNG

test :

test 表示当前是否启用了单元测试选项 –test。test 条件仅支持逻辑非运算符(!)。可以用于区分测试代码与普通代码。

具体代码操作如下:

Step1:复制以下代码,替换main.cj文件中的代码。(保留package)

<span style="color:#1f7199">@When</span>[test]
<span style="color:#1f7199">@Test</span>
<strong>class</strong> <strong>Tests</strong> {
    <span style="color:#1f7199">@TestCase</span>
    <strong>public</strong> func case1(): <span style="color:#397300">Unit</span> {
        <span style="color:#1f7199">@Expect(<span style="color:#3388aa">"run"</span>, foo())</span>
    }
}

func foo() {
    <span style="color:#880000">"run"</span>
}

<span style="color:#1f7199">@When</span>[!test]
main () {
    println(foo())
}

Step2:点击编辑器右上角运行按钮直接运行,终端窗口可以看到打印内容。

0fb48f5e53b4eb105611bac67d71aab7.PNG

至此,仓颉之编译和构建的奇妙旅程内容已全部完成。

如果想了解更多仓颉编程语言知识可以访问:https://cangjie-lang.cn/

                                                                                </div>



Source link

未经允许不得转载:紫竹林-程序员中文网 » 仓颉之编译和构建的奇妙旅程

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
关于我们 免责申明 意见反馈 隐私政策
程序员中文网:公益在线网站,帮助学习者快速成长!
关注微信 技术交流
推荐文章
每天精选资源文章推送
推荐文章
随时随地碎片化学习
推荐文章
发现有趣的