cjc Compilation Options

This section describes some common cjc compilation options. If an option also applies to cjc-frontend, the option is marked with a superscript [frontend]. If the behavior of the option in cjc-frontend is different from that of the option in cjc, the description is added for the option.

  • An option starting with two hyphens (-) is a long option, for example, --xxxx. If a long option is followed by a parameter, a space or an equal sign (=) can be used between the option and parameter. For example, --xxxx <value> is equivalent to --xxxx=<value>.

  • An option starting with a hyphen (-) is a short option, for example, -x. If a short option is followed by a parameter, the option and parameter can be separated by a space or not. For example, -x <value> is equivalent to -x<value>.

Basic Options

--output-type=[exe|staticlib|dylib] [frontend]

Specifies the type of the output file. In exe mode, an executable file will be generated. In staticlib mode, a static library file (.a file) will be generated. In dylib mode, a dynamic library file (.so file for Linux, .dll file for Windows, and .dylib file for macOS) will be generated. By default, the exe mode is used for cjc.

In addition to compiling the .cj file into an executable file, you can also compile it into a static or dynamic link library. For example, using

$ cjc tool.cj --output-type=dylib

tool.cj can be compiled into a dynamic link library. On the Linux platform, cjc will generate a dynamic link library file named libtool.so.

[frontend] In cjc-frontend, the compilation process is performed only to the LLVM IR. Therefore, the output is always the .bc file. However, different --output-type types still affect the front-end compilation policy.

--package, -p [frontend]

Compiles a package. If using this option, you need to specify a directory as the input. The source code files in the directory must belong to the same package.

Assume that there is the log/printer.cj file.

package log

public func printLog(message: String) {
    println("[Log]: ${message}")
}

In addition, there is the main.cj file.

import log.*

main() {
    printLog("Everything is great")
}

Using

$ cjc -p log --output-type=staticlib

To compile the log package. cjc will generate the liblog.a file in the current directory. Then, you can use the liblog.a file to compile the main.cj file. The compilation command is as follows:

$ cjc main.cj liblog.a

cjc compiles main.cj and liblog.a into an executable file main.

--module-name <value> [frontend]

Specifies the name of the module to be compiled.

Assume that there is the my_module/src/log/printer.cj file.

package log

public func printLog(message: String) {
    println("[Log]: ${message}")
}

In addition, there is the main.cj file.

import my_module.log.*

main() {
    printLog("Everything is great")
}

Using

$ cjc -p my_module/src/log --module-name my_module --output-type=staticlib -o my_module/liblog.a

To compile the log package and specify the module name as my_module. The cjc generates a my_module/liblog.a file in the my_module directory. Then, you can use the liblog.a file to compile the main.cj file where the log package is imported. The compilation command is as follows:

$ cjc main.cj my_module/liblog.a

cjc compiles main.cj and liblog.a into an executable file main.

--output <value>, -o <value>, -o<value> [frontend]

Specifies the path of the output file. The output of the compiler will be written to the specified file.

For example, the following command specifies the name of the executable file that is output as a.out:

cjc main.cj -o a.out

--library <value>, -l <value>, -l<value>

Specifies the library file to be linked.

The specified library file is directly transferred to the linker. Generally, this compilation option needs to be used together with --library-path <value>.

The file name must be in the lib[arg].[extension] format. To link the a library, you can use the -l a option. The linker will search for files such as liba.a and liba.so in the library file search paths (or search for liba.dll when linking to the Windows target program) and links them to the final output as required.

--library-path <value>, -L <value>, -L<value>

Specifies the directory of the library file to be linked.

Generally, when using the --library <value> option, you also need to use this option to specify the directory of the library file to be linked.

The path specified by --library-path <value> will be added to the library file search paths of the linker. The path specified by the environment variable LIBRARY_PATH will also be added to the library file search paths of the linker. The path specified by --library-path has a higher priority than the path specified by LIBRARY_PATH.

Assume that there is the dynamic library file libcProg.so that is generated by compiling the following C language source file using the C language compiler.

#include <stdio.h>

void printHello() {
    printf("Hello World\n");
}

In addition, there is the Cangjie file main.cj.

foreign func printHello(): Unit

main(): Int64 {
  unsafe {
    printHello()
  }
  return 0
}

Using

cjc main.cj -L . -l cProg

To compile main.cj and specify the cProg library to be linked. cjc will output an executable file main. When main is executed, the output is as follows:

$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
Hello World

Note that because the dynamic library file is used, you need to add the directory of the library file to $LD_LIBRARY_PATH to ensure that main can be dynamically linked during execution.

-g [frontend]

Generates an executable file or library file with debugging information.

Note:

-g can be used only with -O0. If a higher optimization level is used, an exception may occur for the debugging function.

--trimpath <value> [frontend]

Removes the prefix of the source file path information from the debugging information.

When compiling the Cangjie code, the cjc saves the absolute path information of the source file (.cj file) to provide debugging and exception information at runtime. This option can be used to remove the specified path prefix from the source file path information. In this way, the source file path information in the file output by cjc does not contain the specified content. You can use --trimpath multiple times to specify multiple different path prefixes. For each source file path, the compiler removes the first matched prefix from the path.

--coverage [frontend]

Generates an executable program that supports code coverage statistics. The compiler generates a code information file with the suffix gcno for each compilation unit. After the program is executed, an execution statistics file with the suffix gcda is generated for each compilation unit. With these two files, you can use the cjcov tool to generate the code coverage report for the current execution.

Note:

--coverage can be used only with -O0. If a higher optimization level is used, the compiler generates an alarm and forces -O0 to be used. --coverage is used to compile and generate executable programs. If it is used to generate static or dynamic libraries, link errors may occur when the libraries are used.

--int-overflow=[throwing|wrapping|saturating] [frontend]

Specifies the overflow policy for fixed-precision integer operation. The default value is throwing.

  • In the throwing policy, when the overflow occurs for an integer operation, an exception is thrown.
  • In the wrapping policy, the integer operation wraps to the other end of the corresponding fixed-precision integer when the overflow occurs.
  • In the saturating policy, when the overflow occurs for an integer operation, the extremum value in the corresponding fixed precision is specified as the result.

--diagnostic-format=[default|noColor|json] [frontend]

Note:

Windows does not support the output of error information rendered in colors.

Specifies the output format of error information. The default value is default.

  • default: Error information is output in default format (with color).
  • noColor: Error information is output in the default format (without color).
  • json: Error information is output in json format.

--verbose, -V [frontend]

cjc prints the compiler version, toolchain dependency, and commands executed during compilation.

--help, -h [frontend]

Prints available compilation options.

When this option is used, the compiler only prints information about compilation options and does not compile any input file.

--version, -v [frontend]

Prints the compiler version information.

When this option is used, the compiler only prints version information and does not compile any input file.

--save-temps <value>

Saves the intermediate files generated during compilation to the directory specified by <value>.

The compiler retains intermediate files such as .bc, .o generated during compilation.

--import-path <value> [frontend]

Specifies the search path of the AST file of the imported module.

Assume that the following directory structure exists: The libs/myModule directory contains the library file of the myModule module and the AST export file of the log package.

.
├── libs
|   └── myModule
|       ├── log.cjo
|       └── libmyModule.a
└── main.cj

And there is the main.cj file containing the following code:

import myModule.log.printLog

main() {
    printLog("Everything is great")
}

You can use --import-path ./libs to add ./libs to the AST file search paths of the imported module. cjc uses the ./libs/myModule/log.cjo file to perform semantic check and compilation on the main.cj file.

--import-path provides the same functionality as the CANGJIE_PATH environment variable, but the path set through --import-path has a higher priority.

--scan-dependency [frontend]

Uses the --scan-dependency command to obtain the information about the direct dependency of the source code of a specified package or the cjo file of a package on other packages and other information. The information is output in json format.

// this file is placed under directory pkgA
macro package pkgA
import pkgB.*
import std.io.*
import pkgB.subB.*
cjc --scan-dependency --package pkgA

Or

cjc --scan-dependency pkgA.cjo
{
  "package": "pkgA",
  "isMacro": true,
  "dependencies": [
    {
      "package": "pkgB",
      "isStd": false,
      "imports": [
        {
          "file": "pkgA/pkgA.cj",
          "begin": {
            "line": 2,
            "column": 1
          },
          "end": {
            "line": 2,
            "column": 14
          }
        }
      ]
    },
    {
      "package": "pkgB.subB",
      "isStd": false,
      "imports": [
        {
          "file": "pkgA/pkgA.cj",
          "begin": {
            "line": 4,
            "column": 1
          },
          "end": {
            "line": 4,
            "column": 19
          }
        }
      ]
    },
    {
      "package": "std.io",
      "isStd": true,
      "imports": [
        {
          "file": "pkgA/pkgA.cj",
          "begin": {
            "line": 3,
            "column": 1
          },
          "end": {
            "line": 3,
            "column": 16
          }
        }
      ]
    }
  ]
}

--no-sub-pkg [frontend]

Indicates that the current compilation package does not have subpackages.

After this option is enabled, the compiler can further reduce the code size.

--warn-off, -Woff <value> [frontend]

Disables all or some of the warnings that occur during compilation.

<value> can be specified as all or a preset warning group. If the parameter is specified as all, the compiler does not print all warnings generated during compilation. If the parameter is specified as a preset warning group, the compiler does not print the warnings in this group generated during compilation.

When a warning is printed, a #note line is displayed, indicating the group to which the warning belongs and how to close the warning. You can use --help to print all available parameters of the compilation option to view the specific group names.

--warn-on, -Won <value> [frontend]

Enables all or some of the warnings that occur during compilation.

The value range of <value> of --warn-on is the same as that of <value> of --warn-off. --warn-on is usually used together with --warn-off. For example, you can set -Woff all -Won <value> to allow only the warnings in the group specified by <value> to be printed.

Note that the sequence of --warn-on and --warn-off is sensitive. For the same group, the later option overwrites the previous option. For example, if you change the positions of the two compilation options in the preceding example to -Won <value> -Woff all, all warnings will be disabled.

--error-count-limit <value> [frontend]

Limits the maximum number of errors printed by the compiler.

The parameter <value> can be specified as all or a non-negative integer. If the parameter is specified as all, the compiler prints all errors generated during compilation. If the parameter is specified as a non-negative integer N, the compiler prints a maximum of N errors. The default value is 8.

--output-dir <value> [frontend]

Controls the directory for storing intermediate files and final files generated by the compiler.

Controls the directory for storing intermediate files generated by the compiler, for example, the .cjo files. If both --output-dir <path1> and --output <path2> are specified, the intermediate files are saved to <path1>, and the final output files are saved to <path1>/<path2>.

Note:

If this option and the --output option are specified at the same time, the parameter of the --output option must be specified as a relative path.

--static-std

Statically links the std module of the Cangjie library.

This option takes effect only when the dynamic link library or executable file is compiled. By default, cjc statically links to the std module of the Cangjie library.

--dy-std

Dynamically links the std module of the Cangjie library.

This option takes effect only when the dynamic link library or executable file is compiled.

Note:

  1. If the --static-std and --dy-std options are used together, only the last option takes effect.
  2. The --dy-std and --static-libs options cannot be used together. Otherwise, an error is reported.

--static-libs

Statically links to non-std modules of the Cangjie library.

This option takes effect only when the dynamic link library or executable file is compiled. By default, cjc statically links to non-std modules of the Cangjie library.

--dy-libs

Dynamically links to non-std modules of the Cangjie library.

This option takes effect only when the dynamic link library or executable file is compiled.

Note:

  1. If the --static-libs and --dy-libs options are used together, only the last option takes effect.
  2. The --static-std and --dy-libs options cannot be used together. Otherwise, an error is reported.
  3. If --dy-std is used independently, the --dy-libs option takes effect by default and an alarm is generated.
  4. If --dy-libs is used independently, the --dy-std option takes effect by default and an alarm is generated.

--stack-trace-format=[default|simple|all]

Specifies the print format of the abnormal call stack to control the display of the stack frame information when an exception is thrown. The default format is default.

The formats of the abnormal call stack are described as follows:

  • default: The format is Function name with generic parameters omitted (File name:Line number).
  • simple: The format is File name:Line number.
  • all: The format is Complete function name (File name:Line number).

--lto=[full|thin]

Enables and specifies the compilation mode of Link Time Optimization (LTO).

Note:

  1. Executable files and static libraries (.bc files) in LTO mode can be compiled, but dynamic libraries cannot be compiled and generated. That is, if --output-type=dylib is specified in LTO mode, an error is reported during compilation.
  2. Windows and macOS do not support this function.
  3. When the Link Time Optimization (LTO) compilation mode is enabled and specified, the following optimization compilation options cannot be used at the same time: -Os and -Oz.

LTO supports two compilation modes:

  • --lto=full: full LTO merges all compilation modules into a single module for global optimization. This can maximize the optimization potential and requires longer compilation time.

  • --lto=thin: Compared with full LTO, thin LTO uses parallel optimization on multiple modules and supports incremental compilation during link by default. The compilation time is shorter than that of full LTO. Because more global information is lost, the optimization effect of thin LTO is not as good as that of full LTO.

    • Generally, the optimization effects from high to low are as follows: full LTO > thin LTO > common static link compilation.
    • Generally, the compilation time in descending order is as follows: full LTO > thin LTO > common static link compilation.

LTO is used in the following scenarios:

  1. Run the following command to compile the executable file:

    $ cjc test.cj --lto=full
    or
    $ cjc test.cj --lto=thin
    
  2. Run the following command to compile the static library (.bc file) required in LTO mode and use the library file to compile the executable file:

    # The generated static library is a .bc file.
    $ cjc pkg.cj --lto=full --output-type=staticlib -o libpkg.bc
    # Input the .bc file and source file to the Cangjie compiler to compile the executable file.
    $ cjc test.cj libpkg.bc --lto=full
    

    Note:

    The path of the static library (.bc file) in LTO mode needs to be input to the Cangjie compiler together with the file.

  3. In LTO mode, when the standard library is statically linked (--static-std & -static-libs), the code of the standard library also participates in LTO optimization and is statically linked to the executable file. When the standard library is dynamically linked (--dy-std & -dy-libs), the dynamic library in the standard library is still used for linking in LTO mode.

    # Static linking. The code of the standard library also participates in LTO optimization.
    $ cjc test.cj --lto=full --static-std
    # Dynamic linking. The dynamic library is still used for linking. The code of the standard library is not participated in LTO optimization.
    $ cjc test.cj --lto=full --dy-std
    

--pgo-instr-gen

Enables instrumentation compilation to generate an executable program that carries instrumentation information.

This function does not support the compilation of macOS targets.

Profile-guided optimization (PGO) is a common compilation optimization technique that uses runtime profiling information to further improve program performance. Instrumentation-based PGO is a PGO optimization method using instrumentation information. It usually consists of three steps:

  1. The compiler performs instrumentation compilation on the source code, and generates the instrumented program.
  2. Run the instrumented program to generate a configuration file.
  3. The compiler uses the configuration file to compile the source code again.
# Generate the executable program "test" that supports source code execution statistics (carrying instrumentation information).
$ cjc test.cj --pgo-instr-gen -o test
# Run the executable program "test" to generate the configuration file "test.profraw".
$ LLVM_PROFILE_FILE="test.profraw" ./test

Note:

When running the program, you can use the environment variable LLVM_PROFILE_FILE="test%c.profraw" to enable the continuous mode. That is, a configuration file can still be generated when the program crashes or is killed by a signal. You can use the llvm-profdata tool to view and analyze the configuration file. However, PGO does not support subsequent optimization steps in continuous mode.

--pgo-instr-use=<.profdata>

Uses the specified profdata configuration file to instruct the compilation and generate an optimized executable program.

This function does not support the compilation of macOS targets.

Note:

The --pgo-instr-use compilation option supports only configuration files in the profdata format. You can use the llvm-profdata tool to convert the profraw configuration file to the profdata configuration file.

# Convert the 'profraw' file to the 'profdata' file.
$ LD_LIBRARY_PATH=$CANGJIE_HOME/third_party/llvm/lib:$LD_LIBRARY_PATH $CANGJIE_HOME/third_party/llvm/bin/llvm-profdata merge test.profraw -o test.profdata
# Uses the specified configuration file "test.profdata" to instruct the compilation and generate an optimized executable program "testOptimized".
$ cjc test.cj --pgo-instr-use=test.profdata -o testOptimized

--target <value> [frontend]

Specifies the triple of the target platform for compilation.

The <value> parameter is a character string in the <arch>(-<vendor>)-<os>(-<env>) format. Specifically:

  • <arch> indicates the system architecture of the target platform, for example, aarch64 or x86_64.
  • <vendor> indicates the vendor of the target platform, such as pc or apple. If the platform vendor is not specified or the vendor is not important, you can type unknown or omit this item.
  • <os> indicates the operating system of the target platform, for example, Linux or Win32.
  • <env> indicates the ABI or standard specifications of the target platform, which is used to distinguish different running environments of the same operating system in a finer granularity, for example, gnu or musl. <env> can be omitted when the operating system does not need to be identified in a finer granularity.

cjc supports the following local and target platforms for cross compilation.

Local Platform (host)Target Platform (target)
x86_64-linux-gnuaarch64-hm-gnu

Before using --target to specify the target platform for cross compilation, prepare the cross compilation tool chain of the target platform and the corresponding Cangjie SDK version that can run on the local platform and be compiled to the target platform.

--target-cpu <value>

Note:

This option is an experimental function. The binary files generated using this option may have potential runtime problems. Pay attention to the risks of using this option. This option must be used together with the --experimental option.

Specifies the CPU type of the compilation target.

When the CPU type of the compilation target is specified, the compiler attempts to use the extended instruction set specific to the CPU type when generating the binary files and attempts to apply the optimization applicable to the CPU type. The binary files generated for a particular CPU type typically lose portability and may not be able to run on other CPUs (with the same architectural instruction set).

This option supports the following tested CPU types:

x86-64 architecture:

  • generic

aarch64 architecture:

  • generic
  • tsv110

generic is a general-purpose CPU type. When generic is specified, the compiler generates a general instruction applicable to the architecture. In this way, the generated binary file can run on various CPU types based on the architecture on the premise that the dynamic dependency of the operating system is consistent with that of the binary file. The default value of the --target-cpu option is generic.

This option also supports the following CPU types. They are not tested and verified. Note that the binary files generated using the following CPU types may have runtime problems.

x86-64 architecture:

  • alderlake
  • amdfam10
  • athlon
  • athlon-4
  • athlon-fx
  • athlon-mp
  • athlon-tbird
  • athlon-xp
  • athlon64
  • athlon64-sse3
  • atom
  • barcelona
  • bdver1
  • bdver2
  • bdver3
  • bdver4
  • bonnell
  • broadwell
  • btver1
  • btver2
  • c3
  • c3-2
  • cannonlake
  • cascadelake
  • cooperlake
  • core-avx-i
  • core-avx2
  • core2
  • corei7
  • corei7-avx
  • geode
  • goldmont
  • goldmont-plus
  • haswell
  • i386
  • i486
  • i586
  • i686
  • icelake-client
  • icelake-server
  • ivybridge
  • k6
  • k6-2
  • k6-3
  • k8
  • k8-sse3
  • knl
  • knm
  • lakemont
  • nehalem
  • nocona
  • opteron
  • opteron-sse3
  • penryn
  • pentium
  • pentium-m
  • pentium-mmx
  • pentium2
  • pentium3
  • pentium3m
  • pentium4
  • pentium4m
  • pentiumpro
  • prescott
  • rocketlake
  • sandybridge
  • sapphirerapids
  • silvermont
  • skx
  • skylake
  • skylake-avx512
  • slm
  • tigerlake
  • tremont
  • westmere
  • winchip-c6
  • winchip2
  • x86-64
  • x86-64-v2
  • x86-64-v3
  • x86-64-v4
  • yonah
  • znver1
  • znver2
  • znver3

aarch64 architecture:

  • a64fx
  • ampere1
  • apple-a10
  • apple-a11
  • apple-a12
  • apple-a13
  • apple-a14
  • apple-a7
  • apple-a8
  • apple-a9
  • apple-latest
  • apple-m1
  • apple-s4
  • apple-s5
  • carmel
  • cortex-a34
  • cortex-a35
  • cortex-a510
  • cortex-a53
  • cortex-a55
  • cortex-a57
  • cortex-a65
  • cortex-a65ae
  • cortex-a710
  • cortex-a72
  • cortex-a73
  • cortex-a75
  • cortex-a76
  • cortex-a76ae
  • cortex-a77
  • cortex-a78
  • cortex-a78c
  • cortex-r82
  • cortex-x1
  • cortex-x1c
  • cortex-x2
  • cyclone
  • exynos-m3
  • exynos-m4
  • exynos-m5
  • falkor
  • kryo
  • neoverse-512tvb
  • neoverse-e1
  • neoverse-n1
  • neoverse-n2
  • neoverse-v1
  • saphira
  • thunderx
  • thunderx2t99
  • thunderx3t110
  • thunderxt81
  • thunderxt83
  • thunderxt88

In addition to the preceding optional CPU types, this option can use native as the current CPU type. The compiler attempts to identify the CPU type of the current machine and uses the CPU type as the target type to generate binary files.

--toolchain <value>, -B <value>, -B<value>

Specifies the path for storing binary files in the compilation toolchain.

Binary files include C runtime target files (such as crt0.o and crti.o) provided by compilers, linkers, and toolchains.

After the compilation toolchain is prepared, you can save it in a customized path and transfer the path to the compiler using --toolchain <value>. Then, the compiler can invoke the binary files in the path for cross compilation.

--sysroot <value>

Specifies the root directory of the compilation toolchain.

For a cross compilation toolchain with a fixed directory structure, if you do not need to specify other paths to binary files, dynamic libraries, and static libraries, you can use --sysroot <value> to transfer the root directory of the toolchain to the compiler. The compiler will automatically search for required binary files, dynamic libraries, and static libraries by analyzing the directory structures based on the target platform type. If this option is used, you do not need to specify the --toolchain and --library-path parameters.

Assume that cross compilation is performed on the platform whose triple is arch-os-env, and the cross compilation toolchain has the following directory structure:

/usr/sdk/arch-os-env
├── bin
|   ├── arch-os-env-gcc (Cross compiler)
|   ├── arch-os-env-ld  (Linker)
|   └── ...
├── lib
|   ├── crt1.o          (Target file at C runtime)
|   ├── crti.o
|   ├── crtn.o
|   ├── libc.so         (Dynamic library)
|   ├── libm.so
|   └── ...
└── ...

In addition, there is the Cangjie source file hello.cj. You can run the following command to cross-compile hello.cj to the arch-os-env platform:

cjc --target=arch-os-env --toolchain /usr/sdk/arch-os-env/bin --toolchain /usr/sdk/arch-os-env/lib --library-path /usr/sdk/arch-os-env/lib hello.cj -o hello

You can also use abbreviated parameters:

cjc --target=arch-os-env -B/usr/sdk/arch-os-env/bin -B/usr/sdk/arch-os-env/lib -L/usr/sdk/arch-os-env/lib hello.cj -o hello

If the directory of the toolchain complies with the common directory structure, you can run the following command without using the --toolchain and --library-path parameters:

cjc --target=arch-os-env --sysroot /usr/sdk/arch-os-env hello.cj -o hello

--strip-all, -s

Deletes the symbol table in the output file during the compilation of an executable file or dynamic library.

--discard-eh-frame

Deletes some information in the eh_frame and eh_frame_hdr segments (the CRT information is not processed) during the compilation of an executable file or dynamic library. This can reduce the size of the executable file or dynamic library. However, the debugging information is affected.

This function does not support the compilation of macOS targets.

Specifies a linker option.

cjc transparently transmits the parameter of this option to the linker. The available parameters vary depending on the linker (system or specified). --link-options can be repeatedly used to specify multiple linker options.

The 1 superscript indicates that the linker transparent transmission option may vary according to the linker. For details about the supported options, see the linker document.

--disable-reflection

Disables the reflection option. That is, no reflection information is generated during compilation.

Note:

When cross compilation is performed to the aarch64-linux-ohos target, the reflection information is not generated default. This option does not take effect.

Unit Test Options

--test [frontend]

Indicates the entry provided by the unittest framework, which is automatically generated by the macro. When the cjc --test option is used for compilation, the program entry is test_entry instead of main. For details about how to use the unittest framework, see Cangjie Programming Language Library API.

For the a.cj file in the pkgc directory:

import std.unittest.*
import std.unittest.testmacro.*

@Test
public class TestA {
    @TestCase
    public func case1(): Unit {
        print("case1\n")
    }
}

You can run the following command in the pkgc directory:

cjc a.cj --test

Compile a.cj. The following information is displayed if you run main:

Note:

The execution duration of a test case may be inconsistent each time.

case1
--------------------------------------------------------------------------------------------------
TP: default, time elapsed: 29710 ns, Result:
    TCS: TestA, time elapsed: 26881 ns, RESULT:
    [ PASSED ] CASE: case1 (16747 ns)
Summary: TOTAL: 1
    PASSED: 1, SKIPPED: 0, ERROR: 0
    FAILED: 0
--------------------------------------------------------------------------------------------------

For the following directory structure:

application
├── src
├── pkgc
|   ├── a1.cj
|   └── a2.cj
└── a3.cj

You can use the -p compilation option in the application directory to compile the entire package.

cjc pkgc --test -p

Compile the test cases a1.cj and a2.cj in the pkgc package.

/*a1.cj*/
package a

import std.unittest.*
import std.unittest.testmacro.*

@Test
public class TestA {
    @TestCase
    public func caseA(): Unit {
        print("case1\n")
    }
}
/*a2.cj*/
package a

import std.unittest.*
import std.unittest.testmacro.*

@Test
public class TestB {
    @TestCase
    public func caseB(): Unit {
        throw IndexOutOfBoundsException()
    }
}

When you run main, the output is as follows (for reference only):

case1
--------------------------------------------------------------------------------------------------
TP: a, time elapsed: 367800 ns, Result:
    TCS: TestA, time elapsed: 16802 ns, RESULT:
    [ PASSED ] CASE: caseA (14490 ns)
    TCS: TestB, time elapsed: 347754 ns, RESULT:
    [ ERROR  ] CASE: caseB (345453 ns)
    REASON: An exception has occurred:IndexOutOfBoundsException
        at std/core.Exception::init()(std/core/exception.cj:23)
        at std/core.IndexOutOfBoundsException::init()(std/core/index_out_of_bounds_exception.cj:9)
        at a.TestB::caseB()(/home/houle/cjtest/application/pkgc/a2.cj:7)
        at a.lambda.1()(/home/houle/cjtest/application/pkgc/a2.cj:7)
        at std/unittest.TestCases::execute()(std/unittest/test_case.cj:92)
        at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:194)
        at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:78)
        at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:200)
        at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:78)
        at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:200)
        at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:75)
        at std/unittest.entryMain(std/unittest::TestPackage)(std/unittest/entry_main.cj:11)
Summary: TOTAL: 2
    PASSED: 1, SKIPPED: 0, ERROR: 1
    FAILED: 0
--------------------------------------------------------------------------------------------------

--mock <on|off|runtime-error> [frontend]

If on is specified, the mock compilation is enabled for the package. This option allows classes in the package to be mocked in test cases. off is a method for explicitly disabling mock.

Note:

The mock is automatically enabled for this package in test mode (when --test is enabled), and the --mock option does not need to be explicitly passed.

runtime-error is available only in test mode (when --test is enabled). It allows compilation of packages with mock code, but any mock-related processing is not executed in the compiler (the processing may cause some overhead and affect the runtime performance of the test). This may be useful for the benchmark test of cases with mock code. When using this compilation option, avoid compiling cases with mock code and running tests. Otherwise, a runtime exception will be thrown.

Macro Options

cjc supports the following macro options. For more information about the macro, see Macro.

--compile-macro [frontend]

Compiles the macro definition file to generate the default macro definition dynamic library file.

--debug-macro [frontend]

Generates the Cangjie code file after macro expansion. This option can be used to debug the macro expansion function.

--parallel-macro-expansion [frontend]

Enables parallel macro expansion. This option can be used to shorten the macro expansion compilation time.

Conditional Compilation Options

cjc supports the following conditional compilation options. For more information about conditional compilation, see Conditional Compilation.

--cfg <value> [frontend]

Specifies a customized compilation condition.

Parallel Compilation Options

cjc supports the following parallel compilation options for higher compilation efficiency.

--jobs <value>, -j <value> [frontend]

Sets the maximum number of jobs for parallel compilation. value must be a proper positive integer. When value is greater than the maximum parallel processing capability supported by hardware, the compiler performs parallel compilation based on the default setting calculated based on the parallel processing capability supported by the hardware.

If this compilation option is not set, the compiler performs parallel compilation based on the default setting calculated based on the parallel processing capability supported by the hardware.

Note:

--jobs 1 indicates that the compilation is performed in serial mode.

--aggressive-parallel-compile, --apc [frontend]

After this option is enabled, the compiler uses a more aggressive policy (which may affect optimization) to perform parallel compilation to achieve higher compilation efficiency.

Note:

In some scenarios, the --aggressive-parallel-compile option is forcibly enabled or disabled by the compiler.

The --aggressive-parallel-compile option is forcibly enabled by the compiler in the following scenarios:

  • -O0
  • -g

The --aggressive-parallel-compile option is forcibly disabled by the compiler in the following scenarios:

  • --fobf-string
  • --fobf-const
  • --fobf-layout
  • --fobf-cf-flatten
  • --fobf-cf-bogus
  • --lto
  • --coverage
  • Compiling Windows targets

Optimization Options

--fchir-constant-propagation [frontend]

Enables the chir constant propagation optimization.

--fno-chir-constant-propagation [frontend]

Disables the chir constant propagation optimization.

--fchir-function-inlining [frontend]

Enables the chir function inlining optimization.

--fno-chir-function-inlining [frontend]

Disables the chir function inlining optimization.

--fchir-devirtualization [frontend]

Enables the chir call devirtualization optimization.

--fno-chir-devirtualization [frontend]

Disables the chir call devirtualization optimization.

--fast-math [frontend]

After this option is enabled, the compiler makes fast assumption about floating-point numbers that may cause precision loss to optimize floating-point number operations.

-O<N> [frontend]

Specifies the code optimization level with parameters.

A higher optimization level indicates that the compiler performs more code optimization to generate more efficient programs and may require longer compilation time.

By default, cjc performs the code optimization at level O0. Currently, cjc supports the following optimization levels: O0, O1, O2, Os, and Oz.

When the optimization level is 2, cjc also enables the following options in addition to the corresponding optimization:

  • --fchir-constant-propagation
  • --fchir-function-inlining
  • --fchir-devirtualization

When the optimization level is s, cjc also optimizes the code size in addition to O2-level optimization.

When the optimization level is z, cjc further reduces the code size in addition to Os-level optimization.

Note:

When the optimization level is s or z, the link-time optimization compilation option --lto=[full|thin] cannot be used.

-O [frontend]

Uses O1-level code optimization, which is equivalent to -O1.

Code Obfuscation Options

cjc supports code obfuscation, which is disabled by default, to provide extra code protection.

cjc supports the following code obfuscation options:

--fobf-string

Enables string obfuscation.

Obfuscate strings in code so that attackers cannot statically and directly read string data in binary programs.

--fno-obf-string

Disables string obfuscation.

--fobf-const

Enables constant obfuscation.

Obfuscate constants in code by replacing numeric operation instructions with the equivalent numeric operation instruction sequence that is more complex.

--fno-obf-const

Disables constant obfuscation.

--fobf-layout

Enables layout obfuscation.

The layout obfuscation function obfuscates symbols (including function names and global variable names), path names, code line numbers, and function layout in code. After this compilation option is used, cjc generates the symbol mapping output file *.obf.map in the current directory. If the --obf-sym-output-mapping option is configured, the parameter value in --obf-sym-output-mapping is used as the name of the symbol mapping output file generated by cjc. The symbol mapping output file contains the mapping between symbols before and after obfuscation, and can be used to de-obfuscate the obfuscated symbols.

Note:

Layout obfuscation and parallel compilation conflict with each other. Do not enable them at the same time. Otherwise, parallel compilation becomes invalid.

--fno-obf-layout

Disables layout obfuscation.

--obf-sym-prefix <string>

Specifies the prefix string added by the layout obfuscation function for symbol obfuscation.

After this option is configured, the prefix is added to all obfuscated symbols. Symbol conflicts may occur when multiple Cangjie packages are obfuscated during compilation. You can use this option to specify different prefixes for different packages to avoid symbol conflicts.

--obf-sym-output-mapping <file>

Specifies the symbol mapping output file for layout obfuscation.

The symbol mapping output file records the original symbol names, symbol names after obfuscation, and paths of the files containing symbols. The symbol mapping output file can be used to de-obfuscate the obfuscated symbols.

--obf-sym-input-mapping <file,...>

Specifies symbol mapping input files for layout obfuscation.

The layout obfuscation function uses the mapping relationships in these files to obfuscate symbols. To compile Cangjie packages with call relationships, use the symbol mapping output file of the called package as the parameter of the --obf-sym-input-mapping option for obfuscating the calling package, ensuring that the obfuscation results of the same symbol are the same.

--obf-apply-mapping-file <file>

Provides a customized symbol mapping file for layout obfuscation. The layout obfuscation function obfuscates symbols based on the mapping in the file.

The file format is as follows:

<original_symbol_name> <new_symbol_name>

original_symbol_name indicates the names before obfuscation, and new_symbol_name indicates the names after obfuscation. original_symbol_name consists of multiple fields. field indicates a field name, which can be a module name, package name, class name, structure name, enumeration name, function name, or variable name. fields are separated by '.'. If field indicates a function name, the parameter type of the function needs to be modified with parentheses '()' and appended to the function name. For a function without parameters, the content in the parentheses is empty. If field has a generic parameter, use angle brackets '<>' to add the generic parameter to the end of field.

The layout obfuscation function replaces original_symbol_name in Cangjie apps with new_symbol_name. The symbols that are not in the file are replaced with random names. If the mapping specified in the file conflicts with that in --obf-sym-input-mapping, the compiler throws an exception and stops compilation.

--fobf-export-symbols

Enables the layout obfuscation function to obfuscate export symbols. This option is enabled by default when the layout obfuscation function is enabled.

After this option is enabled, the layout obfuscation function will obfuscate the export symbols.

--fno-obf-export-symbols

Disables the layout obfuscation function from obfuscating export symbols.

--fobf-source-path

Enables the layout obfuscation function to obfuscate the path information of symbols. This option is enabled by default when the layout obfuscation function is enabled.

After this option is enabled, the layout obfuscation function obfuscates the path in the exception stack information and replaces the path name with the character string "SOURCE".

--fno-obf-source-path

Disables the layout obfuscation function from obfuscating the path in the stack information.

--fobf-line-number

Enables the layout obfuscation function to obfuscate the line number in the stack information. This option is enabled by default when the layout obfuscation function is enabled.

After this option is enabled, the layout obfuscation function obfuscates the line number in the exception stack information and replaces the line number with 0.

--fno-obf-line-number

Disables the layout obfuscation function from obfuscating the line number in the stack information.

--fobf-cf-flatten

Enables control flow flattening obfuscation.

Obfuscate the control flow in the code to complicate the transfer logic.

--fno-obf-cf-flatten

Disables control flow flattening obfuscation.

--fobf-cf-bogus

Enables false control flow obfuscation.

A false control flow is inserted into the code, complicating the code logic.

--fno-obf-cf-bogus

Disables false control flow obfuscation.

--fobf-all

Enables all obfuscation functions.

Specifying this option is equivalent to specifying the following options:

  • --fobf-string
  • --fobf-const
  • --fobf-layout
  • --fobf-cf-flatten
  • --fobf-cf-bogus

--obf-config <file>

Specifies the path of the code obfuscation configuration file.

In the configuration file, you can disable the obfuscation tool from obfuscating some functions or symbols. The format of the configuration file is as follows:

obf_func1 name1
obf_func2 name2
...

The first parameter obf_func indicates the specific obfuscation function as follows:

  • obf-cf-bogus: False control flow obfuscation
  • obf-cf-flatten: Control flow flattening obfuscation
  • obf-const: constant obfuscation
  • obf-layout: layout obfuscation

The second parameter name indicates the object to be reserved. It consists of multiple fields. field indicates a field name, which can be a package name, class name, structure name, enumeration name, function name, or variable name.

fields are separated by '.'. If field indicates a function name, the parameter type of the function needs to be modified with parentheses '()' and appended to the function name. For a function without parameters, the content in the parentheses is empty.

For example, assume that the packA package contains the following code:

package packA
class MyClassA {
    func funcA(a: String, b: Int64): String {
        return a
    }
}

To disable the control flow flattening function from obfuscating funcA, you can write the following rule:

obf-cf-flatten packA.MyClassA.funcA(std.core.String, Int64)

You can also use wildcards to write a more flexible rule so that one rule can retain multiple objects. Currently, the following types of wildcards are supported:

Wildcards of obfuscation functions

Wildcard of Obfuscation FunctionsDescription
?Matches a single character in names.
*Matches any number of characters in names.

Wildcards of field names

Wildcard of Field NamesDescription
?Matches a single non-delimiter '.' character in field names.
*Matches any number of characters in field names, excluding separators '.' and parameters.
**Matches any number of characters in field names, including the separator '.' between fields and parameters. '**' takes effect only when it is used as an independent field. Otherwise, it is processed as '*'.

Wildcards of parameter types of functions

Wildcard of Parameter TypesDescription
...Matches any number of parameters.
***Matches a parameter of any type.

Note:

Parameter types also consist of field names. Therefore, wildcards of field names also can be used to match a single parameter type.

Here are some examples of using wildcards:

Example 1:

obf-cf-flatten pro?.myfunc()

This rule indicates that the obf-cf-flatten function is not allowed to obfuscate the pro?.myfunc() function. pro?.myfunc() can match pro0.myfunc() but cannot match pro00.myfunc().

Example 2:

* pro0.**

This rule indicates that any obfuscation function is not allowed to obfuscate any function or variable in the pro0 package.

Example 3:

* pro*.myfunc(...)

This rule indicates that any obfuscation function is not allowed to obfuscate the pro*.myfunc(...) function. pro*.myfunc(...) can match the myfunc function with any parameters in any single-layer package starting with pro.

For a multi-layer package name, for example, pro0.mypack.myfunc(), use pro*.**.myfunc(...) for matching. Note that '**' takes effect only when it is used as a field name. Therefore, pro**.myfunc(...) is equivalent to pro*.myfunc(...) and cannot be used for multi-layer package names. To match all myfunc functions in all packages starting with pro (including functions named myfunc in classes), use pro*.**.myfunc(...).

Example 4:

obf-cf-* pro0.MyClassA.myfunc(**.MyClassB, ***, ...)

This rule indicates that the obf-cf-* function is not allowed to obfuscate the pro0.MyClassA.myfunc(**.MyClassB, ***, ...) function. obf-cf-* matches the obf-cf-bogus and obf-cf-flatten obfuscation functions. pro0.MyClassA.myfunc(**.MyClassB, ***, ...) matches the pro0.MyClassA.myfunc function, where the first parameter can be of the MyClassB type in any package, and the second parameter can be of any type and be followed by zero or more parameters.

--obf-level <value>

Specifies the obfuscation strength level.

You can specify the strength level from 1 to 9. The default strength level is 5. The larger the level number, the higher the strength. This option affects the size of the output file and the execution overhead.

--obf-seed <value>

Specifies the random seed of the obfuscation algorithm.

By specifying the random seed of the obfuscation algorithm, the same Cangjie code can have different obfuscation results in different builds. By default, the same Cangjie code has the same obfuscation result after each obfuscation.

Compiler Security Options

Note:

Windows and macOS versions do not support compiler security options.

By default, cjc generates address-independent code and address-independent executable files when compiling executable files.

cjc supports the following security-related linker options using --link-options:

Sets a thread stack to be a non-executable one.

Sets a global offset table (GOT) relocation to read-only.

Sets immediate binding.

Code Coverage Instrumentation Options

Note:

Windows and macOS versions do not support the code coverage instrumentation options.

Cangjie supports code coverage instrumentation (SanitizerCoverage, short for SanCov) and provides the same interfaces as those of LLVM SanitizerCoverage. The compiler inserts the coverage feedback function at the function or BasicBlock level. You only need to implement the specified callback function to obtain the program running status during running.

Cangjie provides the SanCov function by package. That is, a package can only be instrumented or not instrumented.

--sanitizer-coverage-level=0/1/2

Indicates the instrumentation level. The value 0 indicates that no instrumentation is performed. The value 1 indicates that function-level instrumentation is performed, that is, callback functions are inserted only at the entry of every function. The value 2 indicates that BasicBlock-level instrumentation is performed, that is, callback functions are inserted at every basic block.

If no value is specified, the value 2 is used by default.

This compilation option affects only the instrumentation levels of --sanitizer-coverage-trace-pc-guard, --sanitizer-coverage-inline-8bit-counters, and --sanitizer-coverage-inline-bool-flag.

--sanitizer-coverage-trace-pc-guard

After this option is enabled, the function call __sanitizer_cov_trace_pc_guard(uint32_t *guard_variable) is inserted on every edge. The option is affected by sanitizer-coverage-level.

Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) is not inserted to a constructor; instead the function call uint32_t *__cj_sancov_pc_guard_ctor(uint64_t edgeCount) is inserted during package initialization.

The callback function __cj_sancov_pc_guard_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.

To call __sanitizer_cov_trace_pc_guard_init, you are advised to call it in __cj_sancov_pc_guard_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.

A standard __cj_sancov_pc_guard_ctor reference implementation is as follows:

uint32_t *__cj_sancov_pc_guard_ctor(uint64_t edgeCount) {
    uint32_t *p = (uint32_t *) calloc(edgeCount, sizeof(uint32_t));
    __sanitizer_cov_trace_pc_guard_init(p, p + edgeCount);
    return p;
}

--sanitizer-coverage-inline-8bit-counters

After this option is enabled, an accumulator is inserted on every edge and the accumulator is incremented by 1 for the experienced edge. The option is affected by sanitizer-coverage-level.

Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_8bit_counters_init(char *start, char *stop) is not inserted to a constructor; instead the function call uint8_t *__cj_sancov_8bit_counters_ctor(uint64_t edgeCount) is inserted during package initialization.

The callback function __cj_sancov_pc_guard_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.

To call __sanitizer_cov_8bit_counters_init, you are advised to call it in __cj_sancov_8bit_counters_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.

A standard __cj_sancov_8bit_counters_ctor reference implementation is as follows:

uint8_t *__cj_sancov_8bit_counters_ctor(uint64_t edgeCount) {
    uint8_t *p = (uint8_t *) calloc(edgeCount, sizeof(uint8_t));
    __sanitizer_cov_8bit_counters_init(p, p + edgeCount);
    return p;
}

--sanitizer-coverage-inline-bool-flag

After this option is enabled, a boolean value is inserted on every edge and the boolean value is set to True for the experienced edge. The option is affected by sanitizer-coverage-level.

Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_bool_flag_init(bool *start, bool *stop) is not inserted to a constructor; instead the function call bool *__cj_sancov_bool_flag_ctor(uint64_t edgeCount) is inserted during package initialization.

The callback function __cj_sancov_bool_flag_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.

To call __sanitizer_cov_bool_flag_init, you are advised to call it in __cj_sancov_bool_flag_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.

A standard __cj_sancov_bool_flag_ctor reference implementation is as follows:

bool *__cj_sancov_bool_flag_ctor(uint64_t edgeCount) {
    bool *p = (bool *) calloc(edgeCount, sizeof(bool));
    __sanitizer_cov_bool_flag_init(p, p + edgeCount);
    return p;
}

--sanitizer-coverage-pc-table

This compilation option provides the mapping between instrumentation points and source code. Currently, only the function-level mapping is provided. This option must work with --sanitizer-coverage-trace-pc-guard, --sanitizer-coverage-inline-8bit-counters, and --sanitizer-coverage-inline-bool-flag options, and requires one or more of the options to be enabled at the same time.

Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, const uintptr_t *pcs_end); is not inserted to a constructor; instead the function call void __cj_sancov_pcs_init(int8_t *packageName, uint64_t n, int8_t **funcNameTable, int8_t **fileNameTable, uint64_t *lineNumberTable) is inserted during package initialization. The input parameters are described as follows:

  • int8_t *packageName: package name, which is a character string. (The instrumentation uses the C-style int8 array as the input parameter to express the character string, same as below.)
  • uint64_t n: indicates that n functions are instrumented.
  • int8_t **funcNameTable: string array whose length is n. The function name corresponding to the ith instrumentation point is funcNameTable[i].
  • int8_t **fileNameTable: string array whose length is n. The file name corresponding to the ith instrumentation point is fileNameTable[i].
  • uint64_t *lineNumberTable: uint64 array whose length is n. The line number corresponding to the ith instrumentation point is lineNumberTable[i].

To call __sanitizer_cov_pcs_init, you need to convert Cangjie pc-table to C pc-table.

--sanitizer-coverage-stack-depth

After this compilation option is enabled, the SP pointer can be obtained only that the call __updateSancovStackDepth is inserted at every function entry and implemented in C, because Cangjie cannot obtain the SP pointer.

A standard updateSancovStackDepth implementation is as follows:

thread_local void* __sancov_lowest_stack;

void __updateSancovStackDepth()
{
    register void* sp = __builtin_frame_address(0);
    if (sp < __sancov_lowest_stack) {
        __sancov_lowest_stack = sp;
    }
}

--sanitizer-coverage-trace-compares

After this option is enabled, the function callback functions are inserted before all compare and match instructions are called. The following are the function lists, which are the same as the API functions of LLVM. For details, see Tracing data flow.

void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2);
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2);
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2);
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases);

--sanitizer-coverage-trace-memcmp

Feeds back prefix comparison information in String and Array comparisons. If this option is enabled, a callback function is inserted before the comparison functions of String and Array. Specifically, the corresponding stub functions will be inserted for the following APIs of String and Array:

  • String==: __sanitizer_weak_hook_memcmp
  • String.startsWith: __sanitizer_weak_hook_memcmp
  • String.endsWith: __sanitizer_weak_hook_memcmp
  • String.indexOf: __sanitizer_weak_hook_strstr
  • String.replace: __sanitizer_weak_hook_strstr
  • String.contains: __sanitizer_weak_hook_strstr
  • CString==: __sanitizer_weak_hook_strcmp
  • CString.startswith: __sanitizer_weak_hook_memcmp
  • CString.endswith: __sanitizer_weak_hook_strncmp
  • CString.compare: __sanitizer_weak_hook_strcmp
  • CString.equalsLower: __sanitizer_weak_hook_strcasecmp
  • Array==: __sanitizer_weak_hook_memcmp
  • ArrayList==: __sanitizer_weak_hook_memcmp

Experimental Function Options

--experimental [frontend]

Enables the experimental function to allow other experimental function options to be used on the command line.

Note:

Binary files generated using the experimental function may have potential runtime problems. Pay attention to the risks of using this option.

Other Functions

Coloring the error information of the compiler

For the Cangjie compiler for Windows, the error information is colored only when the compiler runs Windows 10 version 1511(Build 10586) or later.

Setting build-id

--link-options "--build-id=<arg>"1 can be used to transparently transmit the linker options to set build-id.

This function is unavailable to compile Windows targets.

Setting rpath

--link-options "-rpath=<arg>"1 can be used to transparently transmit the linker options to set rpath.

This function is unavailable to compile Windows targets.

Incremental compilation

--incremental-compile[frontend] can be used to enable incremental compilation. After this function is enabled, cjc accelerates the compilation based on the cache file of the previous compilation.

Environment Variables Used by cjc

Here describe the environment variables that may be used by the Cangjie compiler during code compilation.

TMPDIR or TMP

The Cangjie compiler saves the temporary files generated during compilation to a temporary directory. By default, the files are saved in the /tmp directory for the Linux and macOS operating systems, and in the C:\Windows\Temp directory for the Windows operating system. The Cangjie compiler also allows you to set the directory of temporary files. On the Linux and macOS operating systems, you can set the environment variable TMPDIR to change the directory of temporary files. On the Windows operating system, you can set the environment variable TMP to change the directory of temporary files.

For example: In Linux shell

export TMPDIR=/home/xxxx

In Windows cmd

set TMP=D:\\xxxx