Compiler
Cross-compilation: --target and per-target runtimes
Building executables for another operating system or processor, what the build needs for each target, and what a target can reject.
since 0.1.0-alpha.1linuxwindowswasm
Description
The LLVM backend can generate code for a machine other than the one the compiler runs on. You
name the target with --target <triple>, where the triple has the usual LLVM form such as
x86_64-pc-windows-gnu or aarch64-linux-gnu. The compiler runs on Linux; its targets are Linux,
Windows and WebAssembly (see lang.wasm-target).
leviathan --build-native <out> --target <triple> [--runtime <archive>] <source-file>
An executable is the program plus the runtime library, a small C library that provides memory management, the event loop and the system services. Generating the program's object file for another machine needs nothing but the compiler. Linking needs three more things for that machine, and the compiler reports which one is missing:
- A runtime library built for the target. The compiler looks for
<triple>/liblvrt.abeside theleviathanprogram and then forruntime/<triple>/liblvrt.ain a source checkout. In a source checkout,runtime/build-triple.sh <triple>builds it with a cross C compiler for the target:clang(setLVRT_SYSROOTto a sysroot for the target) or the distribution's cross GCC, which for Windows is the MinGW-w64 package whose compiler is calledx86_64-w64-mingw32-gcc.--runtime <path>names an archive explicitly. A cross runtime is built without TLS by default, so the program is plain-text only. - A cross linker. The compiler tries
clang++ -target <triple>first and then the distribution's<prefix>-g++and<prefix>-gcc, where the prefix is the triple (andx86_64-w64-mingw32for the Windows triple). - For WebAssembly,
wasm-ld. Seelang.wasm-target.
The error messages say exactly what was looked for, for example
cannot locate the x86_64-pc-windows-gnu runtime archive (looked next to 'leviathan' and in runtime/x86_64-pc-windows-gnu/).
On a Windows target the compiler adds .exe to the output name if it is not already there, and
links the Windows socket library. The result is an ordinary Windows console program.
--native-obj <out.o> --target <triple> writes the object file for the target and stops, which
is useful to check that a program compiles for a target before its runtime is available.
A triple that LLVM does not know is an error: No available targets are compatible with triple.
The target seen by the program
A program can ask what it is being built for with three compile-time constants,
target::os ("linux", "windows", "wasm" and so on), target::arch and target::triple.
They describe the target you named with --target, not the machine the compiler runs on, and they
only exist at compile time, so they are used in comptime declarations and comptime if.
The branch that is not taken is not compiled at all, so each target only compiles the code written
for it.
Code that depends on the target
comptime string os = target::os;
console.writeln("compiled for ${os}");
comptime if (target::os == "windows") {
console.writeln("path separator is a backslash");
} else {
console.writeln("path separator is a slash");
}
compiled for linux
path separator is a slash
Built for Windows from a Linux machine and run there, the same source prints compiled for windows
and path separator is a backslash:
runtime/build-triple.sh x86_64-pc-windows-gnu
leviathan --build-native hello --target x86_64-pc-windows-gnu hello.lev
That command leaves hello.exe. Because the constants describe the target, --run with a
--target also folds them to the target's values, which lets you test the choice of branch without
building anything:
leviathan --run --target x86_64-pc-windows-gnu hello.lev
What a target can refuse
A target that lacks a system service rejects, at compile time, a program that uses it. The
diagnostic names the construct. On Windows, starting a child process is not available: a program
that constructs a Process stops with a diagnostic that begins process spawn: unsupported on Windows. Files, timers, threads, sockets, async and await, and reading standard input all
compile for Windows. The browser target rejects many more services; see lang.wasm-target.
Fine on Linux, rejected for a Windows target
Process p = Process("/bin/echo", ["hello"]);
console.writeln("started process ${p.pid}");
Rules
--targetnames the machine for--native-objand--build-native, and the value thetarget::constants report in every mode.- Linking for a target needs that target's runtime library and a linker that can produce its executables. A missing one is a compile-time error that says what was searched for.
- On a Windows target the output file name ends in
.exe; on a WebAssembly target it ends in.wasm. The compiler adds the suffix when you leave it out. - If your program uses a construct the target cannot support, the compile fails with a diagnostic; the program is not built.
- The
target::constants are not available outside compile-time contexts.
Examples
Checking that a program compiles for an architecture before its runtime exists:
leviathan --native-obj app_arm.o --target aarch64-linux-gnu app.lev
A complete Windows build with an explicit runtime archive:
LVRT_OUT_DIR=/tmp/rt-win runtime/build-triple.sh x86_64-pc-windows-gnu
leviathan --build-native app --target x86_64-pc-windows-gnu --runtime /tmp/rt-win/liblvrt.a app.lev
The trident build driver passes --target through, so trident build --target x86_64-pc-windows-gnu builds a whole project the same way (see trident.commands).
Notes
Support for a target is a matter of the runtime library having a platform layer for it. The
targets exercised by the project's tests are x86_64-pc-windows-gnu, aarch64-linux-gnu and
wasm32-unknown-unknown.
See also
- The leviathan command line — Every option of the
leviathancompiler, grouped by what it does, with the exit statuses and how arguments reach your program. - Native backends: LLVM and C++ — The two ways to turn a program into a native executable, what each one covers, and the runtime limits of natively built programs.
- The WebAssembly (browser) target — Building a program as a WebAssembly module for the browser, what it can use, what it cannot, and how it reaches the page.
- target:: — the compilation-target constants —
target::os,target::archandtarget::tripleare compile-time strings that describe the platform being compiled for. - comptime — run the language at compile time —
comptimevariables, expressions andifstatements evaluate ordinary code during compilation and fold the result into the program.