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
whenandelse when, and why the branches it skips may name things that do not exist. - Branching on the machine being built for with
#target.osand#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
#Errorand#Warn, and silencing one lint rule with#Allow. - Handing the build values of your own with
--defineand[Build.Defines], and reading them with#config. - How
int8,#targetandAssertreach a program throughintrinsicdeclarations.
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… | Read | Lesson |
|---|---|---|
| the compiler doing the build | #compiler | When |
| the machine being built for | #target | Target |
| debug or release | #build | Build mode |
| where this expression is | #source | Source location |
| a value you passed in | #config | Define |
Lessons
| Lesson | What you will learn | |
|---|---|---|
| 23.1 | When | select code at compile time with when |
| 23.2 | Target | the operating system and architecture being compiled for |
| 23.3 | Build mode | tell debug builds from release builds |
| 23.4 | Source location | the file and line of an expression |
| 23.5 | Compile error | stop the build with #Error, or warn with #Warn |
| 23.6 | Define | values passed to the build from the manifest or the command line |
| 23.7 | Intrinsic | declarations 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.