Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Compiler Configuration1

This page describes the configuration surface of leafc: where configuration comes from, which compiler passes run, and how instrumentation rules select MIR entities. It also documents the settings behind Leaf’s standard compiler setup for codegen, sysroot compatibility, and the runtime shim.

Pass configuration

Each configurable pass is configured in its own passes.<pass_name> table. At minimum, every such table has an enabled flag, which defaults to true and enables or disables that pass. Some pass tables have additional fields; instrumentation and internalization provide a rules field.

PassAdditional configuration
instrumentationrules selects MIR entities for instrumentation.
instrumentation_counternone
instrumentation_rec_checknone
internalizationrules selects functions for internalization.
program_mapnone
program_depnone
type_exportnone
md_infonone

For example, a pass can be disabled as follows and it won’t run during compilation:

[passes.instrumentation]
enabled = false

Instrumentation rules

Each rule is an include or exclude entry with an entity tag. The available entities and aliases are:

include and exclude are parallel lists. If any include rule matches an entity, it is included and takes precedence over every matching exclude rule. Otherwise, a matching exclude rule excludes it; if neither list matches, the rules provide no decision and the pass’s normal behavior is retained.

Canonical entityAliasesEntity-specific field
whole_bodybodynone
method_dyn_definitiondyn_defnone
place_infononekind, then piece for structure
operand_kindnonekind
constant_typeconst_typety or alias type
assignmentnonekind
assignment_infononekind
storage_lifetime_markerstorage_lifetime, lifetime_markerkind
call_flownonekind
dropnonekind
switchnonekind

Every instrumentation filter has two parts: criteria for the selected entity, such as kind or piece, and location criteria named loc that describe the location of the function MIR body being instrumented. loc is a field in the configuration schema, but it is flattened when reading TOML, so its predicates appear next to the other criteria rather than under a literal loc key. The conceptual shape is:

entity-specific criteria + loc: location expression

The TOML form is:

[[passes.instrumentation.rules.exclude]]
entity = "assignment"
kind = "binary_op"
crate = { name = "my_app" }

Here, kind is the entity-specific criterion and crate is part of loc.

The accepted location values are:

Location fieldValuesDescription
crate.nameregex stringThe name of the parent crate of the body.
crate.is_externaltrue or falseWhether the parent crate of the body is external (a dependency)
def_path (alias def_path_match)regex stringMIR’s DefPath of the body.
def_id"crate-number:index"MIR’s DefId of the function body.

The accepted entity-specific values are:

Entity kindFieldValuesExpressions
place_infokindstructure (alias struct), address (alias addr), type (alias ty)no
place_infopiecelocal, deref, field, index, constant_index, subslice, downcast, opaque_cast, unwrap_unsafe_binderyes
operand_kindkindcopy, move, constant (alias const)yes
constant_typetybool, char, int, float, str, byte_str, ptr, zstyes
assignment / assignment_infokinduse, repeat, ref, thread_local_ref, raw_ptr, cast, binary_op, unary_op, discriminant, aggregate, wrap_unsafe_binder, intrinsic_unary_op, intrinsic_binary_op, intrinsic_ternary_op, intrinsic_misc_op, intrinsic_memory_op, atomic_binary_op, atomic_memory_opyes
storage_lifetime_markerkindlive, deadyes
call_flowkindcall_control, call_address (alias call_addr), call_input, function_address (alias func_addr), function_data (alias func_data)yes
dropkindcall_control, call_address (alias call_addr), call_inputyes
switchkindcontrol, datayes

Writing rule expressions

Where supported, a field can be a boolean expression rather than a single value. The tables above mark the fields that support expressions. An atomic value is a string, enum value, boolean, or nested table accepted by the field. An expression can also be a table with a single field of not, any, or all:

[[passes.instrumentation.rules.exclude]]
entity = "operand_kind"
kind = { any = ["move", "copy"] }
all = [
    { crate = { is_external = true } },
    { not = { crate = { name = "std" } } },
]

any is true when at least one child is true; all requires every child; not negates one child. An empty formula table, {}, is a valid empty formula and evaluates false. This is useful when a rule intentionally supplies no location restriction, as in all = []: the all formula itself is true, but an empty atomic formula {} is false. Keep the distinction explicit in configuration.

Invalid regex syntax is an error when the rules are converted for use.

It’s worth mentioning that two top-level aliases, instr_rules and rules, are available for passes.instrumentation.rules. While we do not guarantee stability over this shortcut, it is important that you do not provide configurations in both locations as it is an error.

Advanced settings

Leaf has internal procedures for instrumenting the standard library and linking the runtime shim. The defaults below are the recommended settings for that workflow. Customize them when you need to control how Leaf builds or selects a compatible toolchain, uses a different runtime shim, or changes codegen behavior.

Compiler marker

marker_cfg_name defaults to "leafc" and adds that cfg to the crate it compiles. Set it to another valid cfg name to use a different marker, or to "" to omit the marker.

For example, the default marker lets a sample select code that is compiled only by leafc:

#[cfg(leafc)]
let x: u8 = {
  use leaf::annotations::*;
  x.mark_symbolic()
};

Runtime shim

The default is equivalent to:

[runtime_shim.location.external]
crate_name = "leaf"
search_path = "sysroot"

Use the core library as the shim with either spelling:

[runtime_shim]
location = "core_lib" # `core` is an alias

For an external shim, crate_name defaults to "leaf". search_path accepts:

ValueMeaning
"sysroot" or "default"Find the crate through the normal library search paths. This is the default and is intended for Leaf-compatible sysroots.
"crate_deps" or "deps"Treat the shim as a normal dependency found in the crate’s sysroot or supplied search paths.
"compiler"Use Leaf’s compiler-side runtime_shim/libleafrtsh.rlib and its adjacent deps directory.
{ exact = "..." } or { exact = "/absolute/path/to/libleafrtsh.rlib" }Use an exact runtime-shim library path and its adjacent dependency directory. "exact" is also the enum alias, but the value must be a path string.

For example:

[runtime_shim.location.external]
crate_name = "my_leaf_shim"
search_path = "deps"

The external form adds the configured crate as a forced prelude dependency; the core-library form expects the shim to be part of core and adds no external dependency.

Sysroot and codegen

KeyDefaultEffect
codegen_all_mirtrueEnables MIR/codegen for all items, i.e., including items from upstream dependencies. It also forces one codegen unit, disables LTO when necessary, and uses unwind panic strategy when required.
override_sysroottrueAllows codegen-all mode to find or build a Leaf-compatible sysroot when the current sysroot is incompatible.
building_corefalseIdentifies a core-library build. Used when building a compatible toolchain. See How Leaf Builds a Compatible Compiler Toolchain.

codegen_all_mir and override_sysroot are usually left at their defaults.

codegen_all_mir = false selects the non-codegen-all pipeline. However, runtime_shim.location = "external" with search_path = "sysroot" requires codegen-all mode and enables it with a warning. When codegen-all mode is on, Leaf may override the current sysroot unless override_sysroot is false. Disabling that override is intended for special build scenarios and can cause errors if the sysroot does not contain MIR for all required libraries.

Selecting functions for internalization

The internalization pass is configured under passes.internalization. Its enabled flag controls the pass, and its rules select which generated functions are made internal. Each include or exclude entry matches a generated function’s symbol name with a regex and can use the same boolean expression forms as instrumentation.

[passes.internalization.rules]
include = [
    { any = ["my_crate::public_api::.*", "leafrtsh::.*"] },
]
exclude = [
    { not = "my_crate::keep_exported" },
]

The same not, any, all, empty-formula, and regex rules apply. A matching include selects the symbol for internalization. An unmatched symbol follows the compiler’s default of internalizing it unless it is a required public C export, weak lang item, Rust compiler symbol, or proc-macro export.

Loading and precedence

leafc relies on the config to load configurations. The sources are applied in this order:

  1. schema defaults,
  2. leafc_config.<ext> file: searched in the current working directory, the compiler executable’s directory, including their ancestors in order,
  3. an inline configuration string, and
  4. LEAFC environment variables.

Later sources override earlier values.

Inline configuration

An inline configuration is enabled only when both variables are set:

export LEAFC_CONFIG_STR=$'[passes.instrumentation]\nenabled = false'
export LEAFC_CONFIG_STR_FMT=toml

The format name may be a supported file extension: toml, json, json5, yaml, ron, or ini. An unknown format is ignored with a warning.

Environment variables

LEAFC is the environment-variable prefix used by leafc. The loader uses _ between the prefix and a top-level key, and __ for nested keys. For example:

export LEAFC_PASSES__INSTRUMENTATION__ENABLED=false
export LEAFC_MARKER_CFG_NAME=my_leafc_marker

The file and inline string use the config crate’s normal source merging, so the names and value types must match the schema above.

Example

codegen_all_mir = true
override_sysroot = true
marker_cfg_name = "leafc"

[runtime_shim.location.external]
crate_name = "leaf"
search_path = "sysroot"

[passes.instrumentation]
enabled = true

[[passes.instrumentation.rules.exclude]]
entity = "whole_body"
crate = { is_external = true }

[[passes.instrumentation.rules.include]]
entity = "assignment"
kind = { any = ["binary_op", "atomic_binary_op"] }
crate = { name = "my_app" }

[passes.internalization]
enabled = true

[passes.internalization.rules]
exclude = ["LLVMFuzzerInitialize"]

[passes.md_info]
enabled = false

Troubleshooting

  • Failed to read configurations: check TOML syntax, environment value types, table nesting, and inline format. An inline string requires both LEAFC_CONFIG_STR and LEAFC_CONFIG_STR_FMT.
  • Unknown search_path value: use sysroot/default, crate_deps/deps, compiler, or { exact = "..." }. The external form also needs a crate_name if it is not leaf.
  • Runtime shim not found: use core_lib only when the shim is in the core library; otherwise verify the selected library path and its adjacent deps directory.
  • Sysroot or MIR errors: sysroot shim lookup and codegen-all mode are coupled. Use a Leaf-compatible sysroot, leave override_sysroot = true, or choose another shim location for a special non-codegen-all build.
  • Rules appear ignored: use passes.instrumentation.rules for new files, and do not populate it together with non-empty top-level instr_rules or rules.
  • A rule fails to parse: verify the entity tag, its field (ty versus kind), aliases, enum spelling, and formula shape. def_id must be a crate-number:index string and pattern values must be valid regexes.

Implementation references


  1. This page was created with AI assistance under the supervision and review of the maintainers. ↩