Conditional Compilation
Developers can complete conditional compilation based on predefined or user-defined conditions. Currently, Cangjie supports conditional compilation for imports and declarations.
Conditional Compilation for Imports and Declarations
Cangjie can use the built-in compilation tag @When
to complete conditional compilation. One or more sets of conditions are enclosed in square brackets ([]
). @When
can be used for the import nodes and declaration nodes except the package
nodes.
Usage
The following uses the built-in OS compilation conditions as an example:
@When[os == "Linux"]
class mc{}
main(): Int64 {
var a = mc()
return 0
}
In the preceding code, developers can correctly compile and execute the code in the Linux
system. In a non-Linux
system, a compilation error indicating that the mc
class definition cannot be found occurs.
Note that:
-
Cangjie does not support compilation condition nesting. The following is not allowed:
@When[os == "Windows"] @When[os == "Linux"] // Error, illegal nested when conditional compilation import std.ast.* @When[os == "Windows"] @When[os == "Linux"] // Error, illegal nested when conditional compilation func A(){}
-
@When[...]
is a built-in compilation tag and is processed before import. If the code generated by expanding the macro contains@When[...]
, a compilation error is reported. For example:@M0 // macro which returns the input @When[os == "Linux"] // Error, unexpected when conditional compilation directive func A(){}
Built-in Compilation Condition Variables
Cangjie provides five built-in condition variables: os
, backend
, cjc_version
, debug
, and test
.
os
os
indicates the operating system of the target platform. os
supports the ==
and !=
operators. The following operating systems are supported: Windows
, Linux
, and macOS
.
The usage is as follows:
@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()
}
If the compilation is performed in the Windows
environment, the information Windows, NOT Linux
is displayed. If the compilation is performed in the Linux
environment, the information Linux, NOT Windows
is displayed.
backend
backend
is a built-in condition of Cangjie. Cangjie is a multi-backend language that supports various backend conditional compilations. The backend
condition supports the ==
and !=
operators.
The following backends are supported: cjnative
, cjnative-x86_64
, cjnative-aarch64
.
When the condition is cjnative
, the arch
information is automatically supplemented based on the environment information when the compiler is executed.
The usage is as follows:
@When[backend == "cjnative-x86_64"]
func foo() {
print("cjnative-x86_64 backend, ")
}
@When[backend == "cjnative-aarch64"]
func foo() {
print("cjnative-aarch64 backend, ")
}
@When[backend != "cjnative-x86_64"]
func fee() {
println("NOT cjnative-x86_64 backend")
}
@When[backend != "cjnative-aarch64"]
func fee() {
println("NOT cjnative-aarch64 backend")
}
main() {
foo()
fee()
}
If the compilation is performed using a release package of the cjnative-x86_64
backend, you will obtain the cjnative-x86_64 backend, NOT cjnative-aarch64 backend
information. If the compilation is performed using a release package of the cjnative-aarch64
backend, you will obtain the cjnative-aarch64 backend, NOT cjnative-x86_64 backend
information.
cjc_version
cjc_version
is a built-in condition of Cangjie. Developers can select the code to be compiled based on the current Cangjie compiler version. The cjc_version
condition supports the ==
, !=
, >
, <
, >=
, and <=
operators. The format is xx.xx.xx
, where each xx
can be one or two digits. The comparison rule is based on zero-padding (padding to 2 digits), for example, 0.18.8 < 0.18.11
, 0.18.8 == 0.18.08
.
The usage is as follows:
@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()
}
The execution result of the preceding code varies according to the cjc
version.
debug
debug
specifies whether the debugging mode is enabled, that is, whether the -g
compilation option is enabled. This option can be used to switch between the debugging and release versions during code compilation. The debug
condition supports only the logical NOT operator (!
).
The usage is as follows:
@When[debug]
func foo() {
println("debug")
}
@When[!debug]
func foo() {
println("NOT debug")
}
main() {
foo()
}
If -g
is enabled, the cjc debug
information is displayed. If -g
is not enabled, the NOT debug
information is displayed.
test
test
specifies whether the unit test option --test
is enabled. The test
condition supports only the logical NOT operator (!
). It can be used to distinguish test code from common code.
The usage is as follows:
@When[test]
@Test
class Tests {
@TestCase
public func case1(): Unit {
@Expect("run", foo())
}
}
func foo() {
"run"
}
@When[!test]
main () {
println(foo())
}
Using --test
for compilation and execution will yield test results, while compiling and running without --test
will complete normally and provide the run
information.
User-defined Compilation Condition Variables
Cangjie allows developers to define compilation condition variables and values. A defined condition variable must be a valid identifier and cannot have the same name as built-in condition variables. Its value is a character string literal. User-defined conditions support the ==
and !=
operators. Different from built-in condition variables, user-defined conditions need to be defined by using the --cfg
compilation option during compilation or in the cfg.toml
configuration file.
Configuring User-defined Condition Variables
You can configure user-defined condition variables in either of the following ways: Configure key-value pairs in the compilation options or configure key-value pairs in the configuration file.
You can use --cfg <value>
to pass user-defined compilation condition variables to the compiler in the form of key-value pairs or specify the search path of the cfg.toml
configuration file.
-
The option value must be enclosed in double quotation marks (
""
). -
If the option value contains an equal sign (
=
), the value is configured in the form of key-value pairs. If the path contains an equal sign (=
), use a backslash (\
) to escape the equal sign. Multiple key-value pairs can be separated by commas (,
). Example:$ cjc --cfg "feature = lion, platform = dsp" source.cj
-
The
--cfg
compilation option can be used for multiple times, for example:$ cjc --cfg "feature = lion" --cfg "platform = dsp" source.cj
-
The same condition variable cannot be defined for multiple times, for example:
$ cjc --cfg "feature = lion" --cfg "feature = meta" source.cj
$ cjc --cfg "feature = lion, feature = meta" source.cj
Errors are reported for the preceding two compilation commands.
-
If the option value does not contain the equal sign (
=
) or contains the equal sign (=
) that is escaped by the backslash (\
), the option value is passed to the compiler as the search path of thecfg.toml
configuration file, for example:$ cjc --cfg "./cfg" source.cj
If the
cfg.toml
file exists in the./cfg
directory, the user-defined compilation conditions configured in the./cfg/cfg.toml
file are passed to the compiler during compilation. In thecfg.toml
file, you need to use key-value pairs to configure user-defined condition variables. Each key-value pair occupies a line. The key name is a valid identifier, and the key value is a character string enclosed in double quotation marks (""
). Example:feature = "lion" platform = "dsp"
-
When
--cfg
is used to configure the search path of thecfg.toml
file for multiple times, thecfg.toml
file is searched in the input sequence. If thecfg.toml
file is not found in any input search path, thecfg.toml
file is searched in the default path. -
If the
--cfg
compilation option is used for multiple times and the configuration is performed in the form of key-value pairs, the configuration in thecfg.toml
configuration file is ignored. -
If the
--cfg
compilation option is not used, the compiler searches for thecfg.toml
configuration file in the default path (thepackage
directory orcjc
execution directory specified by--package
or-p
).
Multi-condition Compilation
Cangjie conditional compilation allows developers to combine multiple conditional compilation options. Logical operators can be used to combine multiple conditions, and parentheses can be used to specify priorities.
The usage is as follows:
//source.cj
@When[(test || feature == "lion") && !debug]
func fee() {
println("feature lion")
}
main() {
fee()
}
Run the following command to compile and run the preceding code:
$ cjc --cfg="feature=lion" source.cj -o runner.out
The output is as follows:
feature lion