#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

MistakeError
an extern func with no #Linkextern 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 declarationduplicate '#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