Directives
Builder lets you use directives in your R files and via the command line.
Command line
You can pass definitions via the command line using
-D flags. This is useful for setting build-time
constants without modifying your source files.
Syntax: -D<NAME> for
boolean flags, or -D<NAME> <value>
for valued definitions.
./builder -input srcr -output R -DDEBUG -DTEST '"a string"' -DXXX 42Note: Command-line definitions override file-based
#> define directives.
#> define
Define constants that will be replaced throughout your code. All occurrences of the defined name will be replaced with the specified value.
Syntax:
#> define NAME value
#> define PI 3.14159
#> define STRING "hello world!"
x <- PI # becomes: x <- 3.14159
print(STRING) # becomes: print("hello world!")Note: For function-like macros with
parameters, use #> macro instead. See Macros for details.
#> ifdef
Include a code block only if the specified name is defined
(either via #> define or command-line
-D flag).
Syntax:
#> ifdef NAME ... #> endif
#> ifdef DEBUG
cat("debugging!\n")
#> endif
# With #> else for alternative path
#> ifdef DEBUG
cat("debug!")
#> else
cat("world!")
#> endif#> ifndef
Include a code block only if the specified name is NOT
defined. This is the opposite of #> ifdef.
Syntax:
#> ifndef NAME ... #> endif
#> ifndef PROD
cat("Not in production mode")
#> endif#> if
Evaluate an R expression and include the code block if the result is TRUE. The expression is evaluated using the embedded R interpreter and supports any valid R expression that returns a logical value.
Syntax:
#> if R_EXPRESSION ... #> endif
#> define VERSION 3
#> if VERSION > 2
cat("Using new API\n")
#> endif
#> if XXX > 1
cat("it's 1!\n")
#> endif#> elif
Chain multiple conditions together. Only the first matching branch is included.
Syntax:
#> ifdef|#> ifndef|#> if ... #> elif NAME ... #> else ... #> endif
#> ifdef BACKEND_POSTGRES
db <- connect_postgres()
#> elif BACKEND_SQLITE
db <- connect_sqlite()
#> else
db <- connect_default()
#> endif#> else
Provide an alternative code path for conditional blocks.
Used with #> ifdef, #> ifndef,
or #> if to specify code that should be
included when the condition is false.
See the #> ifdef example above for
usage.
#> endif
Close a conditional compilation block. Required for all
conditional directives (#> ifdef,
#> ifndef, #> if).
#> error
You can use #> error to stop compilation
and print an error message.
#> ifdef DEBUG
#> error "DEBUG mode is not supported"
#> endif#> warning
Print a warning message during compilation without stopping the build. Useful for alerting developers about potential issues or non-critical concerns.
Syntax:
#> warning message text
#> ifdef LEGACY_API
#> warning Using legacy API - consider migrating to v2
#> endif#> deprecated
Print a deprecation notice during compilation without stopping the build. Useful for marking features that will be removed in future versions.
Syntax:
#> deprecated message text
#> ifdef OLD_PARSER
#> deprecated Old parser will be removed in version 3.0
#> endif#> assert
Validate conditions at build time. If the assertion fails, compilation stops with an error message.
Syntax:
#> assert (expression)
#> define VERSION 2
#> assert (VERSION > 1)
# Build continues - assertion passes
#> assert (VERSION > 5)
# Build fails: Assertion failed: (VERSION > 5)#> for
Generate repetitive code by iterating over a numeric range.
The loop variable is replaced using the
..variable.. syntax within the loop body.
Syntax:
#> for VARIABLE in START:END ... #> endfor
#> for i in 1:5
validate_col_..i.. <- function(x) check(x$col..i..)
#> endforExpands to:
validate_col_1 <- function(x) check(x$col1)
validate_col_2 <- function(x) check(x$col2)
validate_col_3 <- function(x) check(x$col3)
validate_col_4 <- function(x) check(x$col4)
validate_col_5 <- function(x) check(x$col5)The range is inclusive on both ends. Multiple occurrences
of ..variable.. in each line are all
replaced.
Nesting Limitation
Nested conditionals are not supported.
Each
#> ifdef/#> ifndef/#> if
block must be independent:
# NOT supported
#> ifdef A
#> ifdef B
code
#> endif
#> endif
# Use combined conditions instead
#> if A && B
code
#> endifBuilt-in directives
..FILE..
A directive that is automatically replaced with the current source file path. Useful for debugging and logging to track which file generated specific code.
cat("Processing file: ..FILE..\n")
# If in srcr/analysis.R, becomes: cat("Processing file: srcr/analysis.R \n")..LINE..
A directive that is automatically replaced with the current line number in the source file. Useful for debugging and error tracking to identify the exact location of code execution.
cat("Executing line ..LINE..\n")
# If on line 42, becomes: cat("Executing line 42\n")..OS..
A directive that is automatically populated with the current operating system. Useful for conditionally compiling code based on the current OS.
cat("Running on: ..OS..\n")
# becomes: cat("Running on: Linux\n")..DATE..
A directive that is automatically populated with the current date (compile time).
cat("Running on: ..DATE..\n")
# becomes: cat("Running on: 2026-01-01\n")..TIME..
A directive that is automatically populated with the current time (compile time).
cat("Running on: ..TIME..\n")
# becomes: cat("Running on: 12:00:00\n")..COUNTER..
A directive that is automatically replaced with a unique
incrementing integer, starting at 0. Each occurrence of
..COUNTER.. in the source code is replaced with
the next value in the sequence. Useful for generating unique
identifiers or labels.
x <- ..COUNTER.. # becomes: x <- 0
y <- ..COUNTER.. # becomes: y <- 1
z <- ..COUNTER.. # becomes: z <- 2