link_extern("libname") { … } blocks (ADR-0085)
A link_extern item form has the shape link_extern "(" string-literal ")" "{" item* "}". The string literal names a library; the body is a sequence of body-less fn declarations. Each fn declared inside a link_extern block is implicitly an extern declaration: the symbol resolves at link time, no body is permitted, and the call uses the C calling convention (implicit @mark(c)). Body-less fn declarations (fn name(...) [-> type] ;) are only permitted inside a link_extern block. A body-less fn at top level is a compile-time error. A fn declared inside a link_extern block must not carry a body. A fn with a body inside a link_extern block is a compile-time error. The library name passed to link_extern("…") must be a non-empty string. link_extern blocks do not nest. link_extern("m") {
fn sin(x: f64) -> f64;
fn cos(x: f64) -> f64;
}
link_extern("c") {
fn abs(x: i32) -> i32;
}
The @link_name("…") directive overrides the linker symbol name of an extern declaration. Without @link_name, the symbol equals the Gruel identifier. Library names from every link_extern("…") block across the compilation are deduplicated and contribute a single -l<name> flag to the link command in lexicographic order. Every fn declared inside a link_extern or static_link_extern block must carry @mark(unchecked) in its directive list (ADR-0088). Imported C symbols are unverified from the Gruel side by construction; the marker makes the call-site discipline visible — every caller must wrap the call in a checked { } block. link_extern("m") {
@mark(unchecked) fn sin(x: f64) -> f64;
@mark(unchecked) fn cos(x: f64) -> f64;
}
fn compute(x: f64) -> f64 {
checked { sin(x) + cos(x) }
}