Skip to content

Latest commit

 

History

History
203 lines (165 loc) · 7.64 KB

external-blocks.md

File metadata and controls

203 lines (165 loc) · 7.64 KB

External blocks

Syntax
ExternBlock :
   unsafe? extern Abi? {
      InnerAttribute*
      ExternalItem*
   }

ExternalItem :
   OuterAttribute* (
         MacroInvocationSemi
      | ( Visibility? ( ExternalStaticItem | ExternalFunctionItem ) )
   )

ExternalStaticItem :
   static mut? IDENTIFIER : Type ;

ExternalFunctionItem :
   fn IDENTIFIER Generics?
   ( ( NamedFunctionParameters | NamedFunctionParametersWithVariadics )? )
   FunctionReturnType? WhereClause? ;

NamedFunctionParameters :
   NamedFunctionParam ( , NamedFunctionParam )* ,?

NamedFunctionParam :
   OuterAttribute* ( IDENTIFIER | _ ) : Type

NamedFunctionParametersWithVariadics :
   ( NamedFunctionParam , )* NamedFunctionParam , OuterAttribute* ...

External blocks provide declarations of items that are not defined in the current crate and are the basis of Rust's foreign function interface. These are akin to unchecked imports.

Two kind of item declarations are allowed in external blocks: functions and statics. Calling functions or accessing statics that are declared in external blocks is only allowed in an unsafe context.

The unsafe keyword is syntactically allowed to appear before the extern keyword, but it is rejected at a semantic level. This allows macros to consume the syntax and make use of the unsafe keyword, before removing it from the token stream.

Functions

Functions within external blocks are declared in the same way as other Rust functions, with the exception that they may not have a body and are instead terminated by a semicolon. Patterns are not allowed in parameters, only IDENTIFIER or _ may be used.

Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI.

A function declared in an extern block is implicitly unsafe. When coerced to a function pointer, a function declared in an extern block has type unsafe extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R, where 'l1, ... 'lm are its lifetime parameters, A1, ..., An are the declared types of its parameters and R is the declared return type.

Statics

Statics within external blocks are declared in the same way as statics outside of external blocks, except that they do not have an expression initializing their value. It is unsafe to access a static item declared in an extern block, whether or not it's mutable, because there is nothing guaranteeing that the bit pattern at the static's memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is in charge of initializing the static.

Extern statics can be either immutable or mutable just like statics outside of external blocks. An immutable static must be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it.

ABI

By default external blocks assume that the library they are calling uses the standard C ABI on the specific platform. Other ABIs may be specified using an abi string, as shown here:

// Interface to the Windows API
extern "stdcall" { }

There are three ABI strings which are cross-platform, and which all compilers are guaranteed to support:

  • extern "Rust" -- The default ABI when you write a normal fn foo() in any Rust code.
  • extern "C" -- This is the same as extern fn foo(); whatever the default your C compiler supports.
  • extern "system" -- Usually the same as extern "C", except on Win32, in which case it's "stdcall", or what you should use to link to the Windows API itself

There are also some platform-specific ABI strings:

  • extern "cdecl" -- The default for x86_32 C code.
  • extern "stdcall" -- The default for the Win32 API on x86_32.
  • extern "win64" -- The default for C code on x86_64 Windows.
  • extern "sysv64" -- The default for C code on non-Windows x86_64.
  • extern "aapcs" -- The default for ARM.
  • extern "fastcall" -- The fastcall ABI -- corresponds to MSVC's __fastcall and GCC and clang's __attribute__((fastcall))
  • extern "vectorcall" -- The vectorcall ABI -- corresponds to MSVC's __vectorcall and clang's __attribute__((vectorcall))

Variadic functions

Functions within external blocks may be variadic by specifying ... after one or more named arguments in the argument list:

extern {
    fn foo(x: i32, ...);
}

Attributes on extern blocks

The following attributes control the behavior of external blocks.

The link attribute

The link attribute specifies the name of a native library that the compiler should link with for the items within an extern block. It uses the MetaListNameValueStr syntax to specify its inputs. The name key is the name of the native library to link. The kind key is an optional value which specifies the kind of library with the following possible values:

  • dylib — Indicates a dynamic library. This is the default if kind is not specified.
  • static — Indicates a static library.
  • framework — Indicates a macOS framework. This is only valid for macOS targets.

The name key must be included if kind is specified.

The wasm_import_module key may be used to specify the WebAssembly module name for the items within an extern block when importing symbols from the host environment. The default module name is env if wasm_import_module is not specified.

#[link(name = "crypto")]
extern {
    // …
}

#[link(name = "CoreFoundation", kind = "framework")]
extern {
    // …
}

#[link(wasm_import_module = "foo")]
extern {
    // …
}

It is valid to add the link attribute on an empty extern block. You can use this to satisfy the linking requirements of extern blocks elsewhere in your code (including upstream crates) instead of adding the attribute to each extern block.

The link_name attribute

The link_name attribute may be specified on declarations inside an extern block to indicate the symbol to import for the given function or static. It uses the MetaNameValueStr syntax to specify the name of the symbol.

extern {
    #[link_name = "actual_symbol_name"]
    fn name_in_rust();
}

Attributes on function parameters

Attributes on extern function parameters follow the same rules and restrictions as regular function parameters.