Directives
Compiler directives (or pragmas) are statements that describe how the compiler should handle source code. Directives are safe to use. It is checked by the compiler and incorrect usage is warned.
For a directive to be valid, it must be used correctly in the right place. The directive must be start with the # prefix.
For example to directives:
#typedefTop Directives
Top directives are must be placed at top of source file. Usually contains specific compiler configurations for file or package.
Arguments
The arguments of the directives are separated by spaces. The directive must be followed by the required arguments, separated by spaces.
For example:
#foo "my-argument"Directive Expressions
Some directives evaluate the expression you wrote with a custom syntax, and if the expression returns true as a result, your file will be included in the build. Expression must always return a boolean. Expressions are only logical. So the tags you will use are boolean, and the binary operations you can do are only logical and, and logical or.
While some tags are automatically set by the compiler, others are passed using the --tags option in the compilation command. The tags you can use are the same as in file annotation. They are tags that are also described in the platform support documentation.
WARNING
Evaluation results in false on any syntax errors and empty expressions.
Syntax
The syntax is simple and easy to learn. The logical and operator is && and the logical or operator is ||. These are the same as Jule. The precedence of these operators is also the same. First, the logical or (||) operator is evaluated, then the logical and (&&) operator is evaluated. You also have parentheses. The parentheses, of course, are evaluated first. In addition to these, the logical not (!) operator is also available.
Tags
Here is the list of tags and their existence:
windows: operating system is Windowsmacos: operating system is macOSdarwin: operating system is darwinlinux: operating system is Linuxunix: operating system is UNIX, or UNIX-likei386: cpu architecture is intel 386arm64: cpu architecture is ARM64amd64: cpu architecture is AMD64x32: 32-bit cpu architecturex64: 64-bit cpu architectureproduction: production compilation enabledtest: compiling for testingclang: backend compiler is Clanggcc: backend compiler is GCCcpp20: using C++20 standard
Examples
Here is an example code via build directive:
#build (darwin || windows) && x64#build unix && !darwinDirective: pass
Directive pass is a top directive. Passes compiler flags to the generated compile command for compiling source code. Uses a string literal as an argument, but literals are not processed; it accepts it directly. So, you can't use escape sequences like original string literals. Pass directives add to command lines after source files.
In a pass directive, it may be necessary to provide multiple arguments. For example, passing -framework Cocoa as a single argument directly to the back-end compiler may not work as expected. For this reason, you can split the pass directive into separate arguments. Each one will be forwarded to the back-end compiler as an individual argument.
INFO
There are no issue if you are using same passes. The compiler may eliminate duplicate passes.
For example:
#pass "-framework" "Foundation"
#pass "-framework" "Cocoa"
fn main() {
// ...
}The #pass directive treats its expression strictly as a single argument. This means that if you try to pass multiple arguments within a single directive, the compiler will not split them for you. For example, according to the case above, #pass "-framework Foundation -framework Cocoa" is not the same as using two separate directives. It will be passed to the back-end compiler as a single argument, which can lead to compilation issues.
Directive: build
The build directive is a top directive. Different way of specific programming such as platform specific programming. It can be used with or instead of file annotation. Unlike file annotation, it is a directive, not a naming convention.
Please look at the specific programming section for more information.
Directive: typedef
In external structs, if the structure is a typedef use this will configure code generation correctly. Otherwise, the struct will be treated as a classical structures.
Directive: cdef
In external functions, if the function is a #define, it configures code generation to be compatible.
Directive: test
Declares test function. For more information, read the Writing Tests section.
Directive export
The export directive is an important part of Integrated Jule. Determines how existing definitions are passed to the backend. This way you have a fixed identifier and can provide an API to the backend language for your Jule codes.
For more information, read the API development section.
Directive disable
Disables some default configuration options of the language for specific areas of the source code. Supported by only functions. Supports multiple arguments.
List of arguments:
boundary: Disables boundary checking for slice and array index/slice expressions. It also disables nil checking for slices.nilptr: Disables nil pointer dereferencing checking for reference pointer dereferencing, smart pointer dereferencing, and anonymous function call expressions.shift: Disables shift amount checking for<<and>>operators. Useful to obtain pure shift expressions for performance critical software.
Directive noinit
Disables default and compiler-generated zero-initialization for global variables. When applied, the variable is allocated in uninitialized memory.
DANGER
Using #noinit is unsafe and intended for low-level or performance-critical programming. Reading from a variable marked with #noinit before manually initializing it results in undefined behavior.
Directive: inline
Suggests to the compiler that the body of the target function should be expanded directly at each call site, replacing the standard function call overhead (such as stack frame allocation and jump instructions) with the function's actual instruction stream.
INFO
In C++, inline also relaxes the One Definition Rule (ODR), allowing the function to be defined across multiple translation units (headers) without causing duplicate symbol linker errors. Modern compilers treat inline as a hint rather than a command and may ignore it if inlining is suboptimal.
Directive: noinline
Explicitly instructs the compiler never to inline the marked function, forcing it to remain a standalone call site regardless of optimization levels.
Directive future
Declares an async function as future function.
Directive ready
Declares a function as ready function, suitable for the future returns.