Platform detection
A program that runs on Windows, Linux and macOS sometimes has to do things differently on each: a path separator, the name of an environment variable, a system call that exists on only one of them. The compiler predefines a symbol for the platform it is building for, and conditional compilation picks the code for it.
'' One source, three platforms: the compiler predefines a symbol for the
'' platform it builds for, and the branches for the others are never
'' compiled.
#if defined( __FB_WIN32__ )
const PLATFORM = "Windows"
const PATH_SEP = "\"
const TEMP_VAR = "TEMP"
#elseif defined( __FB_LINUX__ )
const PLATFORM = "Linux"
const PATH_SEP = "/"
const TEMP_VAR = "TMPDIR"
#elseif defined( __FB_DARWIN__ )
const PLATFORM = "macOS"
const PATH_SEP = "/"
const TEMP_VAR = "TMPDIR"
#else
#error "this program supports Windows, Linux and macOS only"
#endif
print "platform: "; PLATFORM
print "a path: logs"; PATH_SEP; "today.txt"
print "temp variable: "; TEMP_VAR
#ifdef __FB_UNIX__
print "a Unix-like system"
#endif
#ifdef __FB_64BIT__
print "pointers: "; sizeof( any ptr ) * 8; " bits"
#endif
#ifdef __TIKO_COMPILER__
print "compiled by tiko"
#endif
This is the one kind of program whose output should differ between the two targets.
Output on windows-x86_64
platform: Windows
a path: logs\today.txt
temp variable: TEMP
pointers: 64 bits
compiled by tiko
Output on linux-x86_64
platform: Linux
a path: logs/today.txt
temp variable: TMPDIR
a Unix-like system
pointers: 64 bits
compiled by tiko
Output on macos-arm64
platform: macOS
a path: logs/today.txt
temp variable: TMPDIR
a Unix-like system
pointers: 64 bits
compiled by tiko
| Symbol | Defined when building for |
|---|---|
__FB_WIN32__ | Windows (the name is historical: it is defined for 64-bit Windows) |
__FB_LINUX__ | Linux |
__FB_DARWIN__ | macOS |
__FB_UNIX__ | Linux, macOS, and other Unix-like systems |
__FB_64BIT__ | every 64-bit target, which today is every target |
__TIKO_COMPILER__ | always, by tiko |
The #else branch ends in #error, so a build for any other platform stops
with a clear message instead of failing later on a constant that was never
declared. A branch for the platform you are not building on is never
compiled there, so a typo in it goes unnoticed until someone builds for that
platform: build every target you claim to support.
Test platform symbols with #ifdef or defined( ), never by value: on the
other platform the name does not exist at all.
Activities
- Add a
constfor the end-of-line sequence each platform uses in text files, and print its length. - Build with
-target linux-x86_64on Windows using-c, which compiles without linking, and check that the Linux branch compiles.