Skip to content

The template format

Jakub Antonín Štigler edited this page May 7, 2024 · 8 revisions

Expressions

Expressions are enclosed in ${ and }. Expressions can contain builtin function calls, variables, literals, parenthesis (( and )), the conditional operators ?: and ?? and the == operator. Expressions are divided into 'blocks' that are than joined together.

The last expression in the file can optionally leave out the closing }. This can be used to avoid newline at the end of the expansion in editors that automatically add newline at the end of each file.

Operator precedence table (lower precedence means that it is evaluated first):

precedence operator description asociativity
1 concatination left to right
2 == equals left to right
3 ?? null check left to right
3 ? : condition left to right

Functions

Function calls start with the character # followed by the name of the function and arguments in parenthesis separated by commas. Arguments to the function may be one of the follwing:

  • expression: Any expression that expands to value.
  • variable definition: You can define or redefine any variable for the context of the function by using the syntax <variable>=<expression>.
  • variable undefinition: You can undefine any variable of the context of the function by using the syntax -<variable>

Builtin functions

  • #include(<filename>): Expands to the contents of the file specified by the expression filaname. If the file doesn't exist, expands to undefined value (_).
  • #make(<filename> [, <variable definition> | <variable undefinition> [, ...]]): Expands to the contents of the file specified by the expression filename. It also expands expressions inside the file. You can define/redefine variables for the expressions inside the file. Expands to _ if the file doesn't exist.
  • #exists(<filename>): Expands to '' if file exists, otherwise expands to '_'.

Variables

Variables in expressions are expanded. For example if you have variable name defined as main, ${name} will expand to main. Single variable is single block. Variable names can contain almost any character, the first character should be a letter or _ and the following characters can be alphanumeric. You should not use any other characters in the names of variables because when new features are added, the characters may get other meaning.

Internal variables

  • _<OS>: variable defined based on the os, possible variables:
    • _LINUX
    • _WINDOWS
    • _MACOS
    • _IOS
    • _FREEBSD
  • _OS: expands to the name of the operating system
  • _: always not defined
  • _PDIR: name of the directory in which the template is created.

naming conventions:

  • normal variables use the snake case: variable_name
  • variables that should not be edited from the CLI start with underscore: _variable_name
  • all internal variables will be uppercase snake case: _VARIABLE_NAME
    • defining existing internal variables in makemake.json will have no effect as they will be overwriten
    • internal variables can be define from the CLI to load specific version of the template (e.g.: -D_WINDOWS to load the windows version even on other os)

Literals

Literals are enclosed in the ' and ' characters. They expand into the literal string. For example ${'name'} will expand to name. In literals you can escape literals with \. For example ${'\''} will expand to '. Possible escape sequences are:

  • \n: newline
  • \r: carrige return
  • \t: tabulator
  • \\: the \ character
  • \': the ' character

You can escape almost any character and it will escape to that character, but you should use only the above because in the future more escape sequences may be added.

The ?: operator

The ?: operator is evaluated last - all blocks are joined before. It is used as: ${q ? t : f} where q, t and f are any combinations of variables or literals. If any of the expressions are empty (e.g.: ${name ? ' ' name : }) it is as if that expression was undefined variable - its expansion is empty string. If q expands to something defined t is inserted, otherwise f is inserted. You can use multiple ?: operators in single expression. They interpreted as follows: : belongs to the last ? without a :. So ${e1 ? e2 ? e3 : e4 : e5 ? e6 : e7} would be interpreted as ${e1 ? (e2 ? e3 : e4) : (e5 ? e6 : e7)}.

The joining by example

  • name is main and ext is .exe => ${name ext} evaluates to main.exe
  • name is main => ${name '.exe'} evaluates to main.exe

The == operator

Compares the two operands. The two operands must be same in every way: they both must be defined/undefined and they both must have the same value. If the two operands are equal, the expression expands to a defined value with value of one of the operands (the values are same so it doesn't matter which operand this is). If they are not equal the expression expands to undefined value with no value.

Comments

MakeMake doesn't have support for comments, but you can simulate them with conditions: ${'code here' (? 'comment here' :) 'code here'}.

Examples

${'hi' == 'hi'} expands to 'hello'
${'hi' == 'hi' ? 'true' : 'false'} expands to 'true'
${'hi' == 'hi' == 'hi' ? 'true' : 'false'} expands to 'true'
${'hi' == 'hello'} expands to _
${'hi' == 'hello' ? 'true' : 'false'} expands to 'false'
${'hi' == 'hello' == _ ? 'true' : 'false'} expands to 'true'
${_ == _ == _ ? 'true' : 'false'} expands to 'false'

The last example may be confusing, the reason is: condition of the ?: operator is _ == _ == _ which is the same as (_ == _) == _, _ and _ are equal so _ == _ expands to '' (empty literal) but '' and _ are not equal so '' == _ expands to _ and so _ == _ == _ expands to _.

makemake.json

makemake.json is a configuration file for a template. It must be at the root of the template. If makemake.json is not present the template is just copied. Everything in makemake.json is optional. Example of a makemake.json:

{
    "$schema": "https://raw.githubusercontent.com/BonnyAD9/makemake-rs/master/useful_stuff/json-schema/makemake-schema.json",
    "expandVariables": true,
    "files": {
        "makemake.json": "Ignore",
        "README.md": "Ignore",
        "RM.md": {
            "action": "Make",
            "name": "${rm ? 'README.md' : }"
        },
        "main.c": {
            "action": "Make",
            "name": "${mname ? mname : 'main'}.c"
        },
        "Makefile": "Make",
        ".vscode/launch.json": "Make"
    },
    "vars": {
        "cc": "cc",
        "dflags": "-g -Wall -std=c17 -fsanitize=address ${adflags}",
        "rflags": "-std=c17 -DNDEBUG -O3 ${arflags}"
    }
}

schema

Optional field that allows your editor to validate the file.

files

Dictionary of files and their properties. The key is filename relative to the template root and the value may be eaither action (enum value) or object with more information. The action may be one of the follwing values:

  • Copy: copy the file
  • Ignore: don't create the file
  • Make: expand variables in the file

If the value is object it can have any or none of the folowing fields:

  • action: the same action enum as above
  • name: how the file will be named (without path), can contain expressions
    • if the name is empty or the expressions expand to empty string, the file is ignored

preCommand and postCommand

They may be included to run the given command either before the template is copied or after.

vars

Dictionary of variable names and their values. The names cannot contain expressions, but the values can. For backwards compatibility this is a opt-in feature that you can enable by setting expandVariables in the makemake.json file to true (by default it is false). The expressions in variables are expanded only with global variables and variables from the CLI and vars are expanded before the global and CLI variables are mereged with vars so in the case of for example rflags, if arflags is defined in the CLI but rflags is not defined in the CLI, the value of rflags will be just expanded. In case that rflags is defined in the CLI, the value will be expanded but it will overwritten by the variable from the CLI, so the final value of rflags will be the one from the CLI.

Examples

You can see BonnyAD9/makemake-templates.