25 Conditional compilation
Conditional compilation enables code to be included or excluded based on target platform, architecture, or build configuration.
Grammar: See grammar.ebnf § ATTRIBUTES
25.1 Overview
Two attribute forms control conditional compilation:
| Attribute | Purpose |
|---|---|
#target(...) | Platform and architecture conditions |
#cfg(...) | Build configuration flags |
Code in false conditions is parsed but not type-checked. Code in true conditions is type-checked and compiled.
25.2 Target conditions
25.2.1 Operating system
#target(os: "linux")
#target(os: "macos")
#target(os: "windows")
#target(os: "freebsd")
#target(os: "android")
#target(os: "ios")
25.2.2 Architecture
#target(arch: "x86_64")
#target(arch: "aarch64")
#target(arch: "arm")
#target(arch: "wasm32")
#target(arch: "riscv64")
25.2.3 Target families
Target families group related operating systems:
| Family | Operating Systems |
|---|---|
unix | linux, macos, freebsd, openbsd, netbsd, android, ios |
windows | windows |
wasm | wasm32, wasm64 |
#target(family: "unix")
@get_home_dir () -> str = Env.get("HOME").unwrap_or("/home");
25.2.4 Combined conditions (AND)
Multiple conditions in one attribute require all to match:
#target(os: "linux", arch: "x86_64")
@linux_x64_only () -> void = ...;
Multiple attributes also combine with AND:
#target(os: "linux")
#target(arch: "x86_64")
@linux_x64_only () -> void = ...;
25.2.5 OR conditions
The any_* variants match any value in a list:
#target(any_os: ["linux", "macos", "freebsd"])
@unix_like () -> void = ...;
#target(any_arch: ["x86_64", "aarch64"])
@desktop_arch () -> void = ...;
25.2.6 Negation
The not_* prefix negates a condition:
#target(not_os: "windows")
@non_windows () -> void = ...;
#target(not_arch: "wasm32")
@native_only () -> void = ...;
#target(not_family: "wasm")
@native_platform () -> void = ...;
25.3 Configuration flags
25.3.1 Build mode
#cfg(debug)
@debug_only () -> void = ...;
#cfg(release)
@release_only () -> void = ...;
#cfg(not_debug)
@optimized () -> void = ...;
25.3.2 Feature flags
#cfg(feature: "ssl")
@secure_connect () -> void = ...;
#cfg(feature: "async")
type AsyncRuntime = ...;
#cfg(not_feature: "ssl")
@insecure_fallback () -> void = ...;
Feature names shall be valid Ori identifiers:
- Start with a letter or underscore
- Contain only letters, digits, and underscores
- Case-sensitive
25.3.3 OR for features
#cfg(any_feature: ["ssl", "tls"])
@secure_connection () -> void = ...;
25.4 Applicable items
Conditional compilation applies to:
| Item | Example |
|---|---|
| Functions | #target(os: "linux") @platform_func () -> void |
| Types | #target(os: "windows") type Handle = int |
| Trait implementations | #target(os: "linux") impl Socket: FileDescriptor |
| Constants | #cfg(debug) let $log_level = "debug" |
| Imports | #target(os: "linux") use "./linux/io" { epoll_create } |
25.5 File-level conditions
The #! prefix applies a condition to the entire file:
#!target(os: "linux")
// Everything in this file is Linux-only
@epoll_create () -> int = ...;
@epoll_wait (fd: int) -> [Event] = ...;
File-level conditions shall appear before any declarations (after comments and doc comments).
25.6 Compile-time constants
Target information is available as compile-time constants:
| Constant | Type | Description |
|---|---|---|
$target_os | str | Operating system (“linux”, “macos”, etc.) |
$target_arch | str | Architecture (“x86_64”, “aarch64”, etc.) |
$target_family | str | Target family (“unix”, “windows”, “wasm”) |
$debug | bool | True in debug builds |
$release | bool | True in release builds |
25.6.1 Usage in expressions
@get_path_separator () -> str =
if $target_os == "windows" then "\\" else "/";
Branches conditioned on compile-time constants are eliminated. The false branch is not type-checked:
@get_window_handle () -> WindowHandle =
if $target_os == "windows" then
WinApi.get_hwnd() // Only type-checked on Windows
else
panic(msg: "Not supported");
25.7 Compilation semantics
25.7.1 Dead code elimination
Code in false conditions is completely eliminated from the binary:
#target(os: "linux")
@linux_func () -> void = ...; // Not in Windows binary
#cfg(debug)
let $verbose = true; // Not in release binary
25.7.2 Parse vs type-check
Code in false conditions is:
- Parsed: Syntax errors are reported regardless of condition
- Not type-checked: Type errors in unused code do not trigger
#target(os: "nonexistent")
@broken () -> void =
this_is_not_valid!@#$; // Parse error, even if not compiled
#target(os: "windows")
@windows_only () -> void =
WindowsApi.call(); // Only type-checked when targeting Windows
25.8 Command line
# Target specification
ori build --target linux-x86_64
ori build --target macos-aarch64
# Features
ori build --feature ssl --feature async
ori build --no-default-features --feature minimal
# Build mode
ori build --debug # sets cfg(debug)
ori build --release # sets cfg(release)
# Custom cfg flags
ori build --cfg experimental
25.9 Project configuration
# ori.toml
[package]
name = "myapp"
version = "1.0.0"
[features]
default = ["ssl"]
ssl = []
async = ["dep:async-runtime"]
[target.linux]
dependencies = ["libc"]
[target.windows]
dependencies = ["winapi"]
25.10 Error codes
| Code | Description |
|---|---|
| E0930 | Invalid target OS |
| E0931 | Invalid target architecture |
| E0932 | Invalid feature name |
| E0933 | File-level condition must be first |