Part 23: Compile time

Everything so far has happened while the program runs: an if tests a value, a loop counts, a function is called. But some questions are settled before the program exists at all — which compiler is building it, which operating system and processor it is for, whether it is a debug or a release build, which switches you passed on the command line. This part is about asking those questions in the source and letting the answers decide which code is compiled in. By the end you can write one program that builds differently for Windows and Linux, for debug and release, and refuses — with a message of your choosing — to build where it cannot work.

What you will learn

  • Choosing code while compiling with when and else when, and why the branches it skips may name things that do not exist.
  • Branching on the machine being built for with #target.os and #target.arch, and building for another one with --target.
  • Telling a debug build from a release build with #build.mode, and checks that vanish from a release build.
  • Reading the file, line and function of an expression with #source, and which place it really describes.
  • Stopping or warning a build from the source with #Error and #Warn, and silencing one lint rule with #Allow.
  • Handing the build values of your own with --define and [Build.Defines], and reading them with #config.
  • How int8, #target and Assert reach a program through intrinsic declarations.

How when shapes a program

Most lessons in this part feed the same machine. The compiler knows some facts before it starts; when turns them into a choice; only the chosen code is compiled:

flowchart LR
    subgraph known ["Known while compiling"]
        cv["#compiler<br/>version · 23.1"]
        tg["#target<br/>os, arch · 23.2"]
        bd["#build<br/>mode · 23.3"]
        cf["#config<br/>your defines · 23.6"]
    end
    known --> w{"when"}
    w -- "the taken branch" --> keep["resolved, type-checked<br/>and compiled in"]
    w -- "the other branches" --> drop["discarded unread"]
    w -- "a branch holding #Error · 23.5" --> stop(["the build stops<br/>with your message"])

#source (23.4) is known while compiling too, but it describes a place in the code rather than the build, so it is read as a value rather than branched on. All of them come from Core as intrinsic declarations — Intrinsic (23.7) shows what that means by declaring a few of them in a package of its own.

Ask about…ReadLesson
the compiler doing the build#compilerWhen
the machine being built for#targetTarget
debug or release#buildBuild mode
where this expression is#sourceSource location
a value you passed in#configDefine

Lessons

LessonWhat you will learn
23.1Whenselect code at compile time with when
23.2Targetthe operating system and architecture being compiled for
23.3Build modetell debug builds from release builds
23.4Source locationthe file and line of an expression
23.5Compile errorstop the build with #Error, or warn with #Warn
23.6Definevalues passed to the build from the manifest or the command line
23.7Intrinsicdeclarations the compiler implements itself

Before you start

The early lessons need little beyond Parts 1–4 — Const, If, Match and Function — plus Enum from Part 6 and Assert from Part 9. The last two lean on Part 22: Packages: Compile error uses rux lint from Tooling, and Intrinsic is a two-package lesson built on Dependency. Each lesson's package is in the Examples repository's CompileTime/ folder:

cd Examples/CompileTime/When
rux run

Several lessons are worth running more than once — with --release, with --define, or built for another system with --target — and each says which.

After this part

Part 24: Platform puts when #target to work: calling the operating system's own libraries with extern, talking to C, choosing calling conventions and writing assembly, each guarded so that a build for the wrong system stops with a clear #Error. Its checkpoint project, Melody, plays a tune through the Windows console speaker.

For the full rules behind this part, see Compile-time programming, Conditional compilation, Build context and Attributes in the Rux Reference.