条件编译

开发者可以通过预定义或自定义的条件完成条件编译;仓颉目前支持顶层条件编译。

顶层条件编译

仓颉支持除 package 声明以外的 Top Level 条件编译。

使用方法

以内置 os 编译条件为例,其 Top Level 使用方法如下:

@When[os == "linux"]
class mc{}

main(): Int64 {
    var a = mc()
    return 0
}

在上面代码中,开发者在 linux 系统中可以正确编译执行;在 非 linux 系统中,则会遇到找不到 mc 类定义的编译错误。

注:仓颉不支持顶层编译条件嵌套,以下写法均不允许

// 错误示例
@When[os == "windows"]
@When[os == "linux"]    // error: illegal nested when conditional compilation macro
from std import ast.*

@When[os == "windows"]
@When[os == "linux"]    // error: illegal nested when conditional compilation macro
func A(){}

内置条件

仓颉内置了一些条件供开发者直接使用。所有条件的变量都是以字符串的形式存在的。

os

os 是仓颉内置的条件,支持 ==!= 两种操作符。支持的系统有:windowslinuxmacOShm

使用方式如下:

@When[os == "linux"]
func foo() {
    print("linux, ")
}
@When[os == "windows"]
func foo() {
    print("windows, ")
}
@When[os != "windows"]
func fee() {
    println("NOT windows")
}
@When[os != "linux"]
func fee() {
    println("NOT linux")
}
main() {
    foo()
    fee()
}

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

backend

backend 是仓颉内置的条件。仓颉是多后端语言,支持多种后端条件编译。backend 条件支持 ==!= 两种操作符。

支持的后端有:llvmllvm-x86llvm-x86_64llvm-armllvm-aarch64cjvmcjvm-x86cjvm-x86_64cjvm-armcjvm-aarch64

当用户使用的条件为 llvm/cjvm 时,arch 信息将会按编译器执行时环境信息自动补全。

使用方式如下:

@When[backend == "llvm"]
func foo() {
    print("llvm backend, ")
}
@When[backend == "cjvm"]
func foo() {
    print("cjvm backend, ")
}
@When[backend != "llvm"]
func fee() {
    println("NOT llvm backend")
}
@When[backend != "cjvm"]
func fee() {
    println("NOT cjvm backend")
}
main() {
    foo()
    fee()
}

llvm 后端的发布包编译执行,会得到 llvm backend, NOT cjvm backend 的信息;用 cjvm 后端的发布包编译执行,则会得到 cjvm backend, NOT llvm backend 的信息。

cjc_version

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

使用方式如下:

@When[cjc_version == "0.18.6"]
func foo() {
    println("cjc_version equals 0.18.6")
}
@When[cjc_version != "0.18.6"]
func foo() {
    println("cjc_version is NOT equal to 0.18.6")
}
@When[cjc_version > "0.18.6"]
func fnn() {
    println("cjc_version is greater than 0.18.6")
}
@When[cjc_version <= "0.18.6"]
func fnn() {
    println("cjc_version is less than or equal to 0.18.6")
}
@When[cjc_version < "0.18.6"]
func fee() {
    println("cjc_version is less than 0.18.6")
}
@When[cjc_version >= "0.18.6"]
func fee() {
    println("cjc_version is greater than or equal to 0.18.6")
}
main() {
    foo()
    fnn()
    fee()
}

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

debug

debug 是仓颉内置的条件。debug 条件仅支持一元运算。

使用方式如下:

@When[debug]
func foo() {
    println("cjc debug")
}
@When[!debug]
func foo() {
    println("cjc NOT debug")
}
main() {
    foo()
}

根据 cjc 是否是 debug 的版本,上面代码的执行输出结果会有不同。

如果是 debug 版本的 cjc 会输出 cjc debug,如果是 release 版本的 cjc 则会输出 cjc NOT debug

自定义条件

仓颉允许开发者自定义编译的条件。

自定义的条件拥有和内置条件一样的作用,不同点在于自定义的条件需要开发者在编译程序时写在编译选项中。自定义条件支持 ==!= 两种运算符。

假如开发者自定义条件为 feature,使用方式和内置条件没有什么不同。使用如下:

//source.cj
@When[feature == "tiger"]
func foo() {
    println("feature tiger")
}
@When[feature == "lion"]
func foo() {
    println("feature lion")
}
main() {
    foo()
}

上面这段代码,开发者想要顺利编译这段代码需要使用这段编译选项:

可以选择 feature == "tiger" 分支

cjc --conditional-compilation-config="(feature=tiger)" source.cj -o runner.out

或者选择 feature == "lion" 分支

cjc --conditional-compilation-config="(feature=lion)" source.cj -o runner.out

根据 feature 的值不同,编译运行上段代码的结果也会不同。

--conditional-compilation-config

此编译选项里的内容表示当前编译流程中 cjc 传递的自定义条件,cjc 会根据此编译选项的值来选择编译哪段代码。

这个选项中的值是以 key-value 来映射的,一个 key 只可以对应一个 value;此选项也支持多个 key-value 结构,用 逗号 (,) 分割,例如:

cjc --conditional-compilation-config="(feature=lion, target=dsp)" source.cj -o runner.out

开发者编写的条件编译代码需要和 --conditional-compilation-config 里的值对应上,否则条件编译不会生效。例如:

//source.cj
@When[feature == "lion"]
func foo() {
    print("feature lion, ")
}
@When[target == "dsp"]
func fee() {
    println("target dsp")
}
main() {
    foo()
    fee()
}

使用如下编译命令编译运行上段代码,会得到输出结果:feature lion, target dsp

cjc --conditional-compilation-config="(feature=lion,target=dsp)" source.cj -o runner.out

而使用如下编译命令编译运行上段代码,会报错:error: undeclared identifier 'foo'

cjc --conditional-compilation-config="(feature=dsp,target=dsp)" source.cj -o runner.out

多条件

仓颉条件编译允许开发者自由组合多个条件编译选项。支持逻辑运算符组合多个条件,支持括号运算符明确优先级。

使用方式如下:

//source.cj
@When[feature == "tiger" || os == "windows"]
func foo() {
    print("feature tiger, ")
}
@When[(debug || os == "linux") && cjc_version >= "0.18.6"]
func fee() {
    println("feature lion")
}
main() {
    foo()
    fee()
}

使用如下编译命令编译运行上段代码,

cjc --conditional-compilation-config="(feature=tiger)" source.cj -o runner.out

会得到输出结果如下:

feature tiger, feature lion