Repository navigation
The template format
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 |
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>
-
#include(<filename>): Expands to the contents of the file specified by the expressionfilaname. 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 expressionfilename. 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 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.
-
_<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.
- 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.jsonwill 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_WINDOWSto load the windows version even on other os)
- defining existing internal variables in
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 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)}.
-
nameismainandextis.exe=>${name ext}evaluates tomain.exe -
nameismain=>${name '.exe'}evaluates tomain.exe
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.
MakeMake doesn't have support for comments, but you can simulate them with conditions: ${'code here' (? 'comment here' :) 'code here'}.
${'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 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}"
}
}Optional field that allows your editor to validate the file.
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
They may be included to run the given command either before the template is copied or after.
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.
You can see BonnyAD9/makemake-templates.