I’ve completed the implementation which is available as a toolchain and updated the proposal.
Here is the current version of the introduction:
Introduction
At present, the Swift compiler frontend is able to accept "custom compiler flags" on invocation using the -DFLAG_NAME
option. These flags are currently used only in #if
conditionals and it is not possible to supply values. This proposal puts forward a simple implementation where values can be supplied using the established -DFLAG_NAME=VALUE
convention where VALUE can be integer, float, string or boolean literals. To support this, comparison operators ==
, !=
, >
etc. are added to the implementation of the conditional compilation directive and the following are now valid statements.
#if TOLERANCE > 0.9
#if THRESHOLD != 0.0
#if VERSION == "4.2" && TOLERANCE
When the compiler is invoked using these options, a new construct #flagValue("FLAG_NAME"[, default: <expression>])
can be used in Swift expressions to refer to the literal value of the option as if it had been typed at that position in the source. As an example, it would be possible to invoke the compiler as follows:
$ swift -DBUILD_NUMBER=1234 -DTOLERANCE=0.9 -DBUILD_DATE='"Sun 23 Sep 2018"’ file.swift
One can then refer to these variables from the code:
print("Build number \(#flagValue("BUILD_NUMBER")), built on \(#flagValue("BUILD_DATE"))")
Finally, as a refinement for embedding larger resources in executables, if the FLAG_NAME
argument (or the option's value) starts with an @
the value of the flag will be used as the path to a file which contains utf-8 encoded string data that will be read in during compilation and used the body of a raw string literal as if the file was read in. For example:
let sql = #flagValue(“@LONG_SQL_FILE")
For a binary resource you could use:
let image = Data(base64Encoded: #flagValue(“@IMAGE_BASE64_FILE"))
These simple changes combine to provide a powerful bridge between the build system/command line and the Swift language.