Part 24: Platform

Under every Rux program sits an operating system, full of functions written in C long before your program existed, and a processor that runs nothing but its own instructions. The standard packages usually stand between you and both. This part removes them: you declare and call a system function yourself, use the C runtime directly with its own types and conventions, let C call a Rux function back, and finally write function bodies in assembly for two different processors. Nothing here is everyday code — but after this part you will know what every Io::PrintLine eventually turns into, and how to reach a library no package covers yet.

What you will learn

  • Declaring a function from a system library with extern, and naming the library with #Link.
  • Why the compiler takes such a declaration on trust, and what happens when it is wrong.
  • Calling the C runtime through the C package: C's own types, opaque pointers, C structs and variadic calls.
  • Checking C's failure values — null pointers and negative counts — because nothing panics for you.
  • Giving a foreign function a Rux name of its own, and choosing a calling convention with #Abi.
  • Writing an asm func in x86-64 assembly, and its AArch64 version, selected with when #target.arch.

The path of a foreign call

From the call site, a foreign function looks like any other. Underneath, each lesson adds one piece of the agreement between the two sides:

flowchart LR
    call["A Rux call<br/>GetCurrentProcessId()"] --> decl["extern declaration<br/>name and types,<br/>taken on trust · 24.1"]
    decl --> conv["calling convention<br/>which registers carry<br/>the arguments · 24.3"]
    conv --> link["#Link<br/>library and symbol<br/>24.1, 24.3"]
    link --> lib(["at run time:<br/>the function in Kernel32.dll<br/>or the C runtime · 24.2"])
    lib -.->|"a callback, such as<br/>qsort's comparison · 24.3"| back["a Rux function<br/>marked #Abi(.C)"]
    asm["A call to an asm func<br/>24.4, 24.5"] --> pin["#Abi: the convention<br/>the body was written for"]
    pin --> body(["your instructions,<br/>emitted as written"])
SituationToolLesson
a system function no package declaresextern and #LinkExtern
anything in the C runtimethe C packageC interop
a C name you would rather not spell#Link's second argumentABI
a Rux function that C calls back#Abi(.C)ABI
an instruction the language cannot expressasm funcAssembly

Lessons

LessonWhat you will learn
24.1Externcall a platform API directly through an extern declaration and #Link
24.2C interopC-compatible types, pointers and handles
24.3ABIchoose a calling convention with #Abi
24.4Assemblywrite a function body in assembly
24.5ARM assemblythe same function in AArch64 assembly, chosen with when

Before you start

Finish Part 23: Compile time first: every lesson here uses when #target to keep platform code out of builds it cannot work in, and #Error to explain why. The C lessons also lean on Part 15: Memory — Pointer, Pointer slice and Layout — and on Defer.

Not every lesson runs everywhere. Extern calls Kernel32.dll and is Windows only; Assembly needs an x86-64 processor; the assembly in ARM assembly runs only on AArch64, though the lesson builds anywhere. C interop and ABI run on Windows, Linux, macOS and FreeBSD. Each lesson's package is in the Examples repository's Platform/ folder:

cd Examples/Platform/Extern
rux run

After this part

That completes the tour of the language and its standard packages. Part 25: Projects puts it all together in complete small programs, and this part's checkpoint, Melody, plays the opening of Ode to Joy through the console speaker by calling the Windows Beep function with extern — so it, too, is Windows only.

For the full rules behind this part, see Foreign function interface, Link, Abi and Assembler functions in the Rux Reference, and the C package in the API reference.