#Link
#Link names the shared library an extern declaration is imported from, and optionally the symbol the library exports under a different name. Every extern function needs one.
link-attribute = "#Link" "(" library [ "," symbol ] ")"
library = string-literal | constant-name
symbol = string-literal | constant-name
Library
The first argument is the library's file name as the system loader finds it — "Kernel32.dll", "libc.so.6", "libSystem.B.dylib" — not a path. It may be a string literal or the name of a string constant declared in the same package; a constant imported from another package is refused:
error: '#Link' library name 'CRuntime' is not a compile-time constant
A constant lets one when choose the library for every declaration that uses it:
import Core::{ #target, #Error };
when #target.os {
.FreeBSD => const CRuntime = "libc.so.7";
.Linux => const CRuntime = "libc.so.6";
.macOS => const CRuntime = "libSystem.B.dylib";
.Windows => const CRuntime = "ucrtbase.dll";
else => #Error("unknown C runtime")
}
#Link(CRuntime)
extern func llabs(n: int64) -> int64;
Symbol
By default the imported symbol is the declaration's own name. A second argument binds a different exported name, so the Rux name can follow Rux conventions:
#Link(CRuntime, "abs")
extern func AbsoluteValue(n: int32) -> int32; // calls C's abs
The symbol may also be a string constant. One symbol cannot stand for every function in a block, so the two-argument form applies only to a single extern func:
error: an imported symbol name cannot be applied to an extern block; use the one-argument '#Link("library")' form
On a block
The one-argument form on an extern { } block applies the library to every member:
#Link(CRuntime)
extern {
func abs(n: int32) -> int32;
func strlen(text: *char8) -> uint;
}
Rules
| Mistake | Error |
|---|---|
an extern func with no #Link | extern function 'GetTickCount64' must specify a source DLL via #Link("dll.dll") |
#Link on anything but an extern | '#Link' can only be applied to an extern function or extern block |
| three arguments | '#Link' accepts at most two arguments |
| a name that is not a string constant here | '#Link' library name 'Missing' is not a compile-time constant |
two #Links on one declaration | duplicate '#Link' attribute |
The compiler cannot see inside the library. On Windows the linker checks that the DLL exports the symbol, and a misspelt name stops the build at linking:
error: cannot link PE/COFF executable 'Extern': import function 'GetCurrentProcessID' was not found in DLL 'Kernel32.dll'
On the other systems the name is resolved by the dynamic loader when the program is loaded.
See also
- Foreign function interface —
externdeclarations - Linking — choosing libraries per platform
#Abi— the calling convention of an extern- Learn: Extern, ABI
#Unsendable
The #Unsendable attribute: marking a type whose values stay on the thread that made them, the Sendable bound it takes away, and the errors for misuse.
#Abi
The #Abi attribute: fixing the calling convention of a function, asm func or extern to .C, .SysV or .Win64, and the default for each target.