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:

AttributePurpose
#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:

FamilyOperating Systems
unixlinux, macos, freebsd, openbsd, netbsd, android, ios
windowswindows
wasmwasm32, 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:

ItemExample
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:

ConstantTypeDescription
$target_osstrOperating system (“linux”, “macos”, etc.)
$target_archstrArchitecture (“x86_64”, “aarch64”, etc.)
$target_familystrTarget family (“unix”, “windows”, “wasm”)
$debugboolTrue in debug builds
$releaseboolTrue 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

CodeDescription
E0930Invalid target OS
E0931Invalid target architecture
E0932Invalid feature name
E0933File-level condition must be first