summaryrefslogtreecommitdiff
path: root/rules/CC/auto
diff options
context:
space:
mode:
Diffstat (limited to 'rules/CC/auto')
-rw-r--r--rules/CC/auto/RULES1379
-rw-r--r--rules/CC/auto/TARGETS1
-rwxr-xr-xrules/CC/auto/runner162
3 files changed, 1542 insertions, 0 deletions
diff --git a/rules/CC/auto/RULES b/rules/CC/auto/RULES
new file mode 100644
index 0000000..34886d8
--- /dev/null
+++ b/rules/CC/auto/RULES
@@ -0,0 +1,1379 @@
+{ "config":
+ { "doc":
+ [ "Generate a C/C++ config header"
+ , ""
+ , "Generate a C/C++ configuration header using defines specified via the"
+ , "target configuration. In the usual case, a target using this rule is"
+ , "configured by depending on it from a target that uses the built-in"
+ , "\"configure\" rule."
+ ]
+ , "field_doc":
+ { "name": ["Name of the header file to generate (incl. file name ext)."]
+ , "guard": ["The include guard. Multiple segments are joined with \"_\"."]
+ , "stage":
+ ["The location of the header. Path segments are joined with \"/\"."]
+ , "hdrs":
+ [ "Additional header files to be available in the include path. Useful"
+ , "for providing additional header files to values given in"
+ , "\"have_{cfile,cxxfile,ctype,cxxtype,csymbol,cxxsymbol}\"."
+ ]
+ , "deps":
+ [ "Additional public header files from targets to be available in the"
+ , "include path. Useful for providing additional header files to values"
+ , "given in \"have_{cfile,cxxfile,ctype,cxxtype,csymbol,cxxsymbol}\"."
+ ]
+ , "defaults": ["The C/C++ toolchain to use"]
+ , "shell defaults": ["The shell toolchain to use"]
+ }
+ , "config_doc":
+ { "CC":
+ [ "The name of the C compiler to be used by checks. If None, the"
+ , "respective value from [\"CC\", \"defaults\"] will be taken."
+ ]
+ , "CXX":
+ [ "The name of the C++ compiler to be used by checks. If None, the"
+ , "respective value from [\"CC\", \"defaults\"] will be taken."
+ ]
+ , "CFLAGS":
+ [ "The flags for CXX to be used instead of the default ones"
+ , "taken from the [\"CC\", \"defaults\"] target"
+ ]
+ , "CXXFLAGS":
+ [ "The flags for CXX to be used instead of the default ones"
+ , "taken from the [\"CC\", \"defaults\"] target"
+ ]
+ , "ADD_CFLAGS":
+ [ "The flags to add to the default ones for CC"
+ , "taken from the [\"CC\", \"defaults\"] target"
+ ]
+ , "ADD_CXXFLAGS":
+ [ "The flags to add to the default ones for CXX"
+ , "taken from the [\"CC\", \"defaults\"] target"
+ ]
+ , "ENV": ["The environment for running file/symbol/type/size checks."]
+ , "defines":
+ [ "Set a define to a specific value unless its value is \"null\". Must"
+ , "contain a list of pairs. The first element of each pair is the define"
+ , "name and the second argument is the value to set. Strings must be"
+ , "properly escaped. Defines generated from this field are added last,"
+ , "so that they can refer to defines from other \"defines*\", "
+ , "\"have_*\", and \"size_*\" values."
+ ]
+ , "defines1":
+ [ "Set a define to \"1\" unless its value is untrue. Must contain a list"
+ , "of pairs. The first element of each pair is the define name and the"
+ , "second argument is the value."
+ ]
+ , "defines01":
+ [ "Set a define to \"0\" or \"1\" depending on its value being true."
+ , "Must contain a list of pairs. The first element of each pair is the"
+ , "define name and the second argument is the value."
+ ]
+ , "have_cfile":
+ [ "Set a define to \"1\" if the specified C header is in the include"
+ , "path. Must contain a list of pairs. The first element of each pair is"
+ , "the define name and the second argument is the C header file name."
+ ]
+ , "have_cxxfile":
+ [ "Set a define to \"1\" if the specified C++ header is in the include"
+ , "path. Must contain a list of pairs. The first element of each pair is"
+ , "the define name and the second argument is the C++ header file name."
+ ]
+ , "have_ctype":
+ [ "Set a define to \"1\" if the specified C type is defined. Must"
+ , "contain a list of pairs. The first element of each pair is the define"
+ , "name and the second argument is name of the C type. If the specified"
+ , "C type is not a built-in type, additionally the headers"
+ , "\"sys/types.h\", \"stdint.h\", and \"stddef.h\" are checked as well."
+ ]
+ , "have_cxxtype":
+ [ "Set a define to \"1\" if the specified C++ type is defined. Must"
+ , "contain a list of pairs. The first element of each pair is the define"
+ , "name and the second argument is name of the C++ type. If the specified"
+ , "C++ type is not a built-in type, additionally the headers"
+ , "\"sys/types.h\", \"stdint.h\", and \"stddef.h\" are checked as well."
+ ]
+ , "have_csymbol":
+ [ "Set a define to \"1\" if the specified C symbol is defined by one of"
+ , "the specified headers in the include path. Must contain a list of"
+ , "pairs. The first element of each pair is the define name and the"
+ , "second argument is another pair. This pair's first value is the C"
+ , "symbol to search for and the second value is a list with the header"
+ , "file names to consider for searching. If the header file defines the"
+ , "symbol as a macro it is considered available and assumed to work."
+ ]
+ , "have_cxxsymbol":
+ [ "Set a define to \"1\" if the specified C++ symbol is defined by one of"
+ , "the specified headers in the include path. Must contain a list of"
+ , "pairs. The first element of each pair is the define name and the"
+ , "second argument is another pair. This pair's first value is the C++"
+ , "symbol to search for and the second value is a list with the header"
+ , "file names to consider for searching. If the header file defines the"
+ , "symbol as a macro it is considered available and assumed to work."
+ ]
+ , "size_ctype":
+ [ "Set a define to size of the specified C type. Must contain a list of"
+ , "pairs. The first element of each pair is the define name and the"
+ , "second argument is another pair. This pair's first value is the C"
+ , "type to check for and the second value is a list with possible sizes"
+ , "as numbers. If none of the specified sizes matches, the action fails."
+ ]
+ , "size_cxxtype":
+ [ "Set a define to size of the specified C++ type. Must contain a list of"
+ , "pairs. The first element of each pair is the define name and the"
+ , "second argument is another pair. This pair's first value is the C++"
+ , "type to check for and the second value is a list with possible sizes"
+ , "as numbers. If none of the specified sizes matches, the action fails."
+ ]
+ }
+ , "string_fields": ["name", "stage", "guard"]
+ , "target_fields": ["hdrs", "deps"]
+ , "config_vars":
+ [ "CC"
+ , "CXX"
+ , "CFLAGS"
+ , "CXXFLAGS"
+ , "ADD_CFLAGS"
+ , "ADD_CXXFLAGS"
+ , "ENV"
+ , "defines"
+ , "defines1"
+ , "defines01"
+ , "have_cfile"
+ , "have_cxxfile"
+ , "have_ctype"
+ , "have_cxxtype"
+ , "have_csymbol"
+ , "have_cxxsymbol"
+ , "size_ctype"
+ , "size_cxxtype"
+ ]
+ , "imports":
+ { "artifacts": ["./", "../..", "field_artifacts"]
+ , "compile-deps": ["./", "..", "compile-deps"]
+ , "compiler-cc": ["./", "..", "compiler-cc"]
+ , "compiler-cxx": ["./", "..", "compiler-cxx"]
+ , "flags-cc": ["./", "..", "flags-cc"]
+ , "flags-cxx": ["./", "..", "flags-cxx"]
+ , "default-ENV": ["./", "..", "default-ENV"]
+ , "default-PATH": ["./", "..", "default-PATH"]
+ , "default-TOOLCHAIN": ["./", "..", "default-TOOLCHAIN"]
+ , "default-NON_SYSTEM_TOOLS": ["./", "..", "default-NON_SYSTEM_TOOLS"]
+ , "map_provider": ["./", "../..", "field_map_provider"]
+ , "list_provider": ["./", "../..", "field_list_provider"]
+ , "sh": ["./", "../../shell", "sh"]
+ , "sh-PATH": ["./", "../../shell", "PATH"]
+ }
+ , "implicit":
+ { "defaults": [["./", "..", "defaults"]]
+ , "shell defaults": [["./", "../../shell", "defaults"]]
+ }
+ , "expression":
+ { "type": "let*"
+ , "bindings":
+ [ ["name", {"type": "join", "$1": {"type": "FIELD", "name": "name"}}]
+ , [ "stage"
+ , { "type": "join"
+ , "separator": "/"
+ , "$1": {"type": "FIELD", "name": "stage"}
+ }
+ ]
+ , [ "guard"
+ , { "type": "assert_non_empty"
+ , "msg": "Config header include guard may not be empty"
+ , "$1":
+ { "type": "join"
+ , "separator": "_"
+ , "$1": {"type": "FIELD", "name": "guard"}
+ }
+ }
+ ]
+ , [ "includes"
+ , { "type": "to_subdir"
+ , "subdir": "include"
+ , "$1":
+ { "type": "disjoint_map_union"
+ , "msg": "Includes may not overlap"
+ , "$1":
+ [ { "type": "let*"
+ , "bindings": [["fieldname", "hdrs"]]
+ , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"}
+ }
+ , { "type": "let*"
+ , "bindings": [["deps-fieldnames", ["deps"]]]
+ , "body": {"type": "CALL_EXPRESSION", "name": "compile-deps"}
+ }
+ ]
+ }
+ }
+ ]
+ , ["TOOLCHAIN_DIR", "toolchain"]
+ , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}]
+ , [ "shell TOOLCHAIN"
+ , { "type": "let*"
+ , "bindings":
+ [ ["fieldname", "shell defaults"]
+ , ["provider", "TOOLCHAIN"]
+ , ["default", {"type": "empty_map"}]
+ ]
+ , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"}
+ }
+ ]
+ , [ "TOOLCHAIN"
+ , { "type": "disjoint_map_union"
+ , "msg": "Shell and CC toolchain must not conflict"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "var", "name": "shell TOOLCHAIN"}
+ ]
+ }
+ ]
+ , [ "TOOLCHAIN"
+ , { "type": "to_subdir"
+ , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"}
+ , "$1": {"type": "var", "name": "TOOLCHAIN"}
+ }
+ ]
+ , [ "sh"
+ , { "type": "let*"
+ , "bindings": [["fieldname", "shell defaults"]]
+ , "body": {"type": "CALL_EXPRESSION", "name": "sh"}
+ }
+ ]
+ , [ "bin dirs"
+ , { "type": "let*"
+ , "bindings":
+ [["fieldname", "shell defaults"], ["provider", "bin dirs"]]
+ , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"}
+ }
+ ]
+ , [ "bin dirs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "bin dirs"}
+ , "body":
+ { "type": "join"
+ , "$1":
+ [ "./"
+ , {"type": "var", "name": "TOOLCHAIN_DIR"}
+ , "/"
+ , {"type": "var", "name": "_"}
+ ]
+ }
+ }
+ ]
+ , [ "NON_SYSTEM_TOOLS"
+ , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"}
+ ]
+ , ["CC", {"type": "CALL_EXPRESSION", "name": "compiler-cc"}]
+ , ["CXX", {"type": "CALL_EXPRESSION", "name": "compiler-cxx"}]
+ , ["CFLAGS", {"type": "CALL_EXPRESSION", "name": "flags-cc"}]
+ , ["CXXFLAGS", {"type": "CALL_EXPRESSION", "name": "flags-cxx"}]
+ , [ "ENV"
+ , { "type": "map_union"
+ , "$1":
+ [ {"type": "CALL_EXPRESSION", "name": "default-ENV"}
+ , {"type": "var", "name": "ENV", "default": {"type": "empty_map"}}
+ ]
+ }
+ ]
+ , [ "ENV_PATH"
+ , { "type": "lookup"
+ , "map": {"type": "var", "name": "ENV"}
+ , "key": "PATH"
+ }
+ ]
+ , [ "ENV"
+ , { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "ENV"}
+ , { "type": "singleton_map"
+ , "key": "PATH"
+ , "value":
+ { "type": "join"
+ , "separator": ":"
+ , "$1":
+ { "type": "++"
+ , "$1":
+ [ {"type": "CALL_EXPRESSION", "name": "default-PATH"}
+ , { "type": "if"
+ , "cond": {"type": "var", "name": "ENV_PATH"}
+ , "then": [{"type": "var", "name": "ENV_PATH"}]
+ }
+ , { "type": "let*"
+ , "bindings": [["fieldname", "shell defaults"]]
+ , "body": {"type": "CALL_EXPRESSION", "name": "sh-PATH"}
+ }
+ , {"type": "var", "name": "bin dirs"}
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ , [ "c.flags"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1": {"type": "var", "name": "CFLAGS"}
+ }
+ }
+ ]
+ , [ "cxx.flags"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1": {"type": "var", "name": "CXXFLAGS"}
+ }
+ }
+ ]
+ , [ "file_check.sh"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1":
+ [ "set -eu"
+ , "[ $# -ge 4 ]"
+ , "CC=$1"
+ , "LANG=$2"
+ , "DEF=$3"
+ , "HDR=$4"
+ , "DEFINE=\"/* #undef $DEF */\""
+ , "echo \"#include \\\"$HDR\\\"\" > test.$LANG"
+ , "if $CC @$LANG.flags -c test.$LANG -I ./include 2>/dev/null; then DEFINE=\"#define $DEF 1\"; fi"
+ , "echo \"$DEFINE\n\" > out.def"
+ ]
+ }
+ }
+ ]
+ , [ "type_check.sh"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1":
+ [ "set -eu"
+ , "[ $# -ge 4 ]"
+ , "CC=$1"
+ , "LANG=$2"
+ , "DEF=$3"
+ , "TYPE=$4"
+ , "INC=\"\""
+ , "DEFINE=\"/* #undef $DEF */\""
+ , "for HDR in \"\" \"sys/types.h\" \"stdint.h\" \"stddef.h\"; do"
+ , " if [ -n \"$HDR\" ]; then INC=\"#include \\\"$HDR\\\"\"; fi"
+ , " cat > test.$LANG << EOF"
+ , "$INC"
+ , "$TYPE* __test;"
+ , "EOF"
+ , " if $CC @$LANG.flags -c test.$LANG -I ./include 2>/dev/null; then"
+ , " DEFINE=\"#define $DEF 1\""
+ , " break"
+ , " fi"
+ , "done"
+ , "echo \"$DEFINE\n\" > out.def"
+ ]
+ }
+ }
+ ]
+ , [ "symbol_check.sh"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1":
+ [ "set -eu"
+ , "[ $# -ge 4 ]"
+ , "CC=$1"
+ , "shift"
+ , "LANG=$1"
+ , "shift"
+ , "DEF=$1"
+ , "shift"
+ , "SYMBOL=$1"
+ , "shift"
+ , "DEFINE=\"/* #undef $DEF */\""
+ , "for INC in \"$@\"; do"
+ , " cat > test_symbol.$LANG << EOF"
+ , "#include \"$INC\""
+ , "void* __test = &$SYMBOL;"
+ , "EOF"
+ , " if $CC @$LANG.flags -c test_symbol.$LANG -I ./include 2>/dev/null; then"
+ , " DEFINE=\"#define $DEF 1\""
+ , " break"
+ , " fi"
+ , " cat > test_macro.$LANG << EOF"
+ , "#include \"$INC\""
+ , "#ifndef $SYMBOL"
+ , "#error not defined as macro"
+ , "#endif"
+ , "EOF"
+ , " if $CC @$LANG.flags -c test_macro.$LANG -I ./include 2>/dev/null; then"
+ , " DEFINE=\"#define $DEF 1\""
+ , " break"
+ , " fi"
+ , "done"
+ , "echo \"$DEFINE\n\" > out.def"
+ ]
+ }
+ }
+ ]
+ , [ "size_check.sh"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1":
+ [ "set -eu"
+ , "[ $# -ge 4 ]"
+ , "CC=$1"
+ , "shift"
+ , "LANG=$1"
+ , "shift"
+ , "DEF=$1"
+ , "shift"
+ , "TYPE=$1"
+ , "shift"
+ , "INC=\"\""
+ , "for HDR in \"\" \"sys/types.h\" \"stdint.h\" \"stddef.h\"; do"
+ , " if [ -n \"$HDR\" ]; then INC=\"#include \\\"$HDR\\\"\"; fi"
+ , " for SIZE in \"$@\"; do"
+ , " SIZE=$(printf %.0f $SIZE)"
+ , " cat > test.$LANG << EOF"
+ , "$INC"
+ , "char __test[(sizeof($TYPE) == $SIZE) ? 1 : -1];"
+ , "EOF"
+ , " if $CC @$LANG.flags -c test.$LANG -I ./include 2>/dev/null; then"
+ , " DEFINE=\"#define $DEF $SIZE\""
+ , " echo \"$DEFINE\n\" > out.def"
+ , " exit 0"
+ , " fi"
+ , " done"
+ , "done"
+ , "exit 1"
+ ]
+ }
+ }
+ ]
+ , [ "guard.def"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "separator": "\n"
+ , "$1":
+ [ { "type": "join"
+ , "separator": " "
+ , "$1": ["#ifndef", {"type": "var", "name": "guard"}]
+ }
+ , { "type": "join"
+ , "separator": " "
+ , "$1": ["#define", {"type": "var", "name": "guard"}]
+ }
+ , "\n\n"
+ ]
+ }
+ }
+ ]
+ , [ "plain.def"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "$1":
+ { "type": "foreach"
+ , "range": {"type": "var", "name": "defines", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'defines' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "join"
+ , "separator": " "
+ , "$1":
+ { "type": "case*"
+ , "expr": {"type": "var", "name": "val"}
+ , "case":
+ [ [ null
+ , [ "/* #undef"
+ , {"type": "var", "name": "def"}
+ , "*/\n\n"
+ ]
+ ]
+ ]
+ , "default":
+ [ "#define"
+ , {"type": "var", "name": "def"}
+ , { "type": "join"
+ , "$1": [{"type": "var", "name": "val"}, "\n\n"]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ , [ "int1.def"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "$1":
+ { "type": "foreach"
+ , "range": {"type": "var", "name": "defines1", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'defines1' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "join"
+ , "separator": " "
+ , "$1":
+ { "type": "if"
+ , "cond": {"type": "var", "name": "val"}
+ , "then":
+ ["#define", {"type": "var", "name": "def"}, "1\n\n"]
+ , "else":
+ ["/* #undef", {"type": "var", "name": "def"}, "*/\n\n"]
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ , [ "int01.def"
+ , { "type": "BLOB"
+ , "data":
+ { "type": "join"
+ , "$1":
+ { "type": "foreach"
+ , "range": {"type": "var", "name": "defines01", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'defines01' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "join"
+ , "separator": " "
+ , "$1":
+ [ "#define"
+ , {"type": "var", "name": "def"}
+ , { "type": "if"
+ , "cond": {"type": "var", "name": "val"}
+ , "then": "1\n\n"
+ , "else": "0\n\n"
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ , [ "cfile-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_cfile", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_cfile' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["file_check.sh", "c.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ [ {"type": "var", "name": "sh"}
+ , "./file_check.sh"
+ , {"type": "var", "name": "CC"}
+ , "c"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "val"}
+ ]
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "cxxfile-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_cxxfile", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_cxxfile' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["file_check.sh", "cxx.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ [ {"type": "var", "name": "sh"}
+ , "./file_check.sh"
+ , {"type": "var", "name": "CXX"}
+ , "cxx"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "val"}
+ ]
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "ctype-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_ctype", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_ctype' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "type"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["type_check.sh", "c.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ [ {"type": "var", "name": "sh"}
+ , "./type_check.sh"
+ , {"type": "var", "name": "CC"}
+ , "c"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "type"}
+ ]
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "cxxtype-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_cxxtype", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_cxxtype' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "type"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["type_check.sh", "cxx.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ [ {"type": "var", "name": "sh"}
+ , "./type_check.sh"
+ , {"type": "var", "name": "CXX"}
+ , "cxx"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "type"}
+ ]
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "csymbol-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_csymbol", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_csymbol' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "sym, hdrs"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ , [ "sym"
+ , { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "sym, hdrs"}
+ }
+ ]
+ , [ "hdrs"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "sym, hdrs"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["symbol_check.sh", "c.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ { "type": "++"
+ , "$1":
+ [ [ {"type": "var", "name": "sh"}
+ , "./symbol_check.sh"
+ , {"type": "var", "name": "CC"}
+ , "c"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "sym"}
+ ]
+ , {"type": "var", "name": "hdrs"}
+ ]
+ }
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "cxxsymbol-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "have_cxxsymbol", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_csymbol' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "sym, hdrs"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ , [ "sym"
+ , { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "sym, hdrs"}
+ }
+ ]
+ , [ "hdrs"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "sym, hdrs"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["symbol_check.sh", "cxx.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ { "type": "++"
+ , "$1":
+ [ [ {"type": "var", "name": "sh"}
+ , "./symbol_check.sh"
+ , {"type": "var", "name": "CXX"}
+ , "cxx"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "sym"}
+ ]
+ , {"type": "var", "name": "hdrs"}
+ ]
+ }
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "csize-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "size_ctype", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_csymbol' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "type, sizes"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ , [ "type"
+ , { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "type, sizes"}
+ }
+ ]
+ , [ "sizes"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "type, sizes"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["size_check.sh", "c.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ { "type": "++"
+ , "$1":
+ [ [ {"type": "var", "name": "sh"}
+ , "./size_check.sh"
+ , {"type": "var", "name": "CC"}
+ , "c"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "type"}
+ ]
+ , { "type": "foreach"
+ , "var": "size"
+ , "range": {"type": "var", "name": "sizes"}
+ , "body":
+ { "type": "json_encode"
+ , "$1": {"type": "var", "name": "size"}
+ }
+ }
+ ]
+ }
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , [ "cxxsize-defs"
+ , { "type": "foreach"
+ , "range": {"type": "var", "name": "size_cxxtype", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "def"
+ , { "type": "assert_non_empty"
+ , "msg": "Define name in 'have_csymbol' may not be empty"
+ , "$1":
+ { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ }
+ ]
+ , [ "type, sizes"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ , [ "type"
+ , { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "type, sizes"}
+ }
+ ]
+ , [ "sizes"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "type, sizes"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "lookup"
+ , "key": "out.def"
+ , "map":
+ { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "env", "vars": ["size_check.sh", "cxx.flags"]}
+ , {"type": "var", "name": "includes"}
+ ]
+ }
+ , "cmd":
+ { "type": "++"
+ , "$1":
+ [ [ {"type": "var", "name": "sh"}
+ , "./size_check.sh"
+ , {"type": "var", "name": "CXX"}
+ , "cxx"
+ , {"type": "var", "name": "def"}
+ , {"type": "var", "name": "type"}
+ ]
+ , { "type": "foreach"
+ , "var": "size"
+ , "range": {"type": "var", "name": "sizes"}
+ , "body":
+ { "type": "json_encode"
+ , "$1": {"type": "var", "name": "size"}
+ }
+ }
+ ]
+ }
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out.def"]
+ }
+ }
+ }
+ }
+ ]
+ , ["end.def", {"type": "BLOB", "data": "\n#endif\n"}]
+ , [ "definitions"
+ , { "type": "enumerate"
+ , "$1":
+ { "type": "++"
+ , "$1":
+ [ [ {"type": "var", "name": "guard.def"}
+ , {"type": "var", "name": "int1.def"}
+ , {"type": "var", "name": "int01.def"}
+ ]
+ , {"type": "var", "name": "cfile-defs"}
+ , {"type": "var", "name": "cxxfile-defs"}
+ , {"type": "var", "name": "ctype-defs"}
+ , {"type": "var", "name": "cxxtype-defs"}
+ , {"type": "var", "name": "csymbol-defs"}
+ , {"type": "var", "name": "cxxsymbol-defs"}
+ , {"type": "var", "name": "csize-defs"}
+ , {"type": "var", "name": "cxxsize-defs"}
+ , [ {"type": "var", "name": "plain.def"}
+ , {"type": "var", "name": "end.def"}
+ ]
+ ]
+ }
+ }
+ ]
+ , [ "outfile"
+ , { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "TOOLCHAIN"}
+ , {"type": "var", "name": "definitions"}
+ ]
+ }
+ , "cmd":
+ [ {"type": "var", "name": "sh"}
+ , "-c"
+ , { "type": "join"
+ , "separator": " "
+ , "$1":
+ [ "cat"
+ , { "type": "join_cmd"
+ , "$1":
+ { "type": "keys"
+ , "$1": {"type": "var", "name": "definitions"}
+ }
+ }
+ , "> out"
+ ]
+ }
+ ]
+ , "outs": ["out"]
+ , "env": {"type": "var", "name": "ENV"}
+ }
+ ]
+ , [ "outfile"
+ , { "type": "to_subdir"
+ , "subdir": {"type": "var", "name": "stage"}
+ , "$1":
+ { "type": "singleton_map"
+ , "key": {"type": "var", "name": "name"}
+ , "value":
+ { "type": "lookup"
+ , "key": "out"
+ , "map": {"type": "var", "name": "outfile"}
+ }
+ }
+ }
+ ]
+ ]
+ , "body":
+ { "type": "RESULT"
+ , "artifacts": {"type": "var", "name": "outfile"}
+ , "runfiles": {"type": "var", "name": "outfile"}
+ }
+ }
+ }
+, "config_file":
+ { "doc":
+ [ "Generate a C/C++ config header from a given template"
+ , ""
+ , "Generate a C/C++ configuration header using defines specified via the"
+ , "target configuration. In the usual case, a target using this rule is"
+ , "configured by depending on it from a target that uses the built-in"
+ , "\"configure\" rule."
+ , ""
+ , "The actual generation of the header file from the template"
+ , "is done by the implicit dependency on the \"runner\" target which"
+ , "can be changed globally by setting this target in the"
+ , "target layer of this repository."
+ ]
+ , "field_doc":
+ { "output":
+ [ "Name of the header file to generate (incl. file name ext). Components are joined with /."
+ ]
+ , "input": ["The input configuration file, used as template."]
+ , "magic_string":
+ [ "The magic string (e.g., \"cmakedefine\") which identifies in which line"
+ , "we have to \"#define\" or \"#undef\" variables according to what is"
+ , "defined in the config field \"defines\"."
+ ]
+ , "@only": ["If set, only replace @VAR@ and not ${VAR}"]
+ , "runner": ["The program generating the header file from the template."]
+ }
+ , "config_doc":
+ { "defines":
+ [ "Set a define to a specific value unless its value is \"null\". Must"
+ , "contain a list of pairs. The first element of each pair is the define"
+ , "name and the second argument is the value to set. Strings must be"
+ , "properly escaped. Defines generated from this field are added last,"
+ , "so that they can refer to defines from other \"defines*\" values."
+ ]
+ }
+ , "string_fields": ["magic_string", "@only", "output"]
+ , "target_fields": ["input"]
+ , "config_vars": ["defines"]
+ , "imports":
+ { "stage_singleton_field": ["", "stage_singleton_field"]
+ , "default-PATH": ["./", "..", "default-PATH"]
+ }
+ , "implicit": {"runner": ["runner"], "defaults": [["./", "..", "defaults"]]}
+ , "expression":
+ { "type": "let*"
+ , "bindings":
+ [ [ "runner"
+ , { "type": "let*"
+ , "bindings": [["fieldname", "runner"], ["location", "runner"]]
+ , "body":
+ {"type": "CALL_EXPRESSION", "name": "stage_singleton_field"}
+ }
+ ]
+ , [ "dict-defines"
+ , { "type": "map_union"
+ , "$1":
+ { "type": "foreach"
+ , "range": {"type": "var", "name": "defines", "default": []}
+ , "var": "pair"
+ , "body":
+ { "type": "let*"
+ , "bindings":
+ [ [ "key"
+ , { "type": "[]"
+ , "index": 0
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ , [ "val"
+ , { "type": "[]"
+ , "index": -1
+ , "list": {"type": "var", "name": "pair"}
+ }
+ ]
+ ]
+ , "body":
+ { "type": "singleton_map"
+ , "key": {"type": "var", "name": "key"}
+ , "value": {"type": "var", "name": "val"}
+ }
+ }
+ }
+ }
+ ]
+ , [ "magic_string"
+ , { "type": "assert_non_empty"
+ , "msg": "A non-empty string has to be provided for magic_string"
+ , "$1":
+ {"type": "join", "$1": {"type": "FIELD", "name": "magic_string"}}
+ }
+ ]
+ , [ "@only"
+ , { "type": "if"
+ , "cond": {"type": "FIELD", "name": "@only"}
+ , "then": "true"
+ , "else": "false"
+ }
+ ]
+ , [ "param-blob"
+ , { "type": "singleton_map"
+ , "key": "param-file"
+ , "value":
+ { "type": "BLOB"
+ , "data":
+ { "type": "json_encode"
+ , "$1": {"type": "var", "name": "dict-defines"}
+ }
+ }
+ }
+ ]
+ , [ "input-blob"
+ , { "type": "let*"
+ , "bindings": [["fieldname", "input"], ["location", "input-file"]]
+ , "body":
+ {"type": "CALL_EXPRESSION", "name": "stage_singleton_field"}
+ }
+ ]
+ , ["PATH", {"type": "CALL_EXPRESSION", "name": "default-PATH"}]
+ , [ "ENV"
+ , { "type": "if"
+ , "cond": {"type": "var", "name": "PATH"}
+ , "then":
+ { "type": "singleton_map"
+ , "key": "PATH"
+ , "value":
+ { "type": "join"
+ , "separator": ":"
+ , "$1": {"type": "var", "name": "PATH"}
+ }
+ }
+ , "else": {"type": "empty_map"}
+ }
+ ]
+ , [ "outfile"
+ , { "type": "ACTION"
+ , "inputs":
+ { "type": "map_union"
+ , "$1":
+ [ {"type": "var", "name": "param-blob"}
+ , {"type": "var", "name": "input-blob"}
+ , {"type": "var", "name": "runner"}
+ ]
+ }
+ , "cmd":
+ [ "./runner"
+ , "input-file"
+ , "param-file"
+ , {"type": "var", "name": "magic_string"}
+ , {"type": "var", "name": "@only"}
+ ]
+ , "env": {"type": "var", "name": "ENV"}
+ , "outs": ["out"]
+ }
+ ]
+ , [ "outfile"
+ , { "type": "singleton_map"
+ , "key":
+ { "type": "join"
+ , "separator": "/"
+ , "$1": {"type": "FIELD", "name": "output"}
+ }
+ , "value":
+ { "type": "lookup"
+ , "key": "out"
+ , "map": {"type": "var", "name": "outfile"}
+ }
+ }
+ ]
+ ]
+ , "body":
+ { "type": "RESULT"
+ , "artifacts": {"type": "var", "name": "outfile"}
+ , "runfiles": {"type": "var", "name": "outfile"}
+ }
+ }
+ }
+}
diff --git a/rules/CC/auto/TARGETS b/rules/CC/auto/TARGETS
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/rules/CC/auto/TARGETS
@@ -0,0 +1 @@
+{}
diff --git a/rules/CC/auto/runner b/rules/CC/auto/runner
new file mode 100755
index 0000000..2da44af
--- /dev/null
+++ b/rules/CC/auto/runner
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+
+# Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import re
+from sys import argv
+from typing import Union
+
+
+def get_tokens(line: str, magic_string: str) -> tuple[Union[re.Match[str], None], bool]:
+ """Tokenize lines (strings) like the following
+ #cmakedefine FOO bar
+ #cmakedefine FOO @FOO@
+ #cmakedefine FOO ${FOO}
+ #cmakedefine01 FOO
+
+ where "cmakedefine" is the magic_string. Let us name "FOO" as the token_key,
+ and the corresponding value (i.e., bar, @FOO@, ${FOO}, the empty string) as
+ the token_value. The function handles any combination of spaces around the
+ magic_string, the token_key and the token_value.
+ """
+ x = re.search(
+ r"#(.*)(" + magic_string + r"[01]*" + r")([\s]*)([a-zA-Z0-9_]+)([\s]*)(.*)",
+ line,
+ )
+ if x:
+ return x, x.groups()[1] == f"{magic_string}01"
+ return None, False
+
+
+def handle01(line: str, tokens: re.Match[str], defined: bool) -> str:
+ groups = tokens.groups()
+ return re.sub(
+ tokens.group()[1:],
+ groups[0] # spaces
+ + "define"
+ + groups[2] # spaces
+ + groups[3] # token_key
+ + " "
+ + str(1 if defined else 0),
+ line,
+ )
+
+
+def undefine(tokens: re.Match[str]) -> str:
+ groups = tokens.groups()
+ return "/* #" + groups[0] + "undef" + groups[2] + groups[3] + " */"
+
+
+def replace_value(tokens: re.Match[str], key: str, value: str) -> str:
+ groups = tokens.groups()
+ return f"#{groups[0]}define{groups[2]}{key}{groups[4]}{value}"
+
+
+def compute_value(token_value: str, at_only: bool, param: dict[str, str]):
+ # example of possible token_values
+ # - foo (a simple string)
+ # - @FOO@
+ # - ${FOO}
+ # - any combination of the above
+
+ def replace_pattern_in_string(
+ pattern: str, line: str, param: dict[str, str]
+ ) -> str:
+
+ def get_value_for_match(match: re.Match[str]) -> str:
+ key = match.group(1)
+ return param.get(key, "")
+
+ return re.sub(pattern, get_value_for_match, line)
+
+ token_value = replace_pattern_in_string(r"@([A-Za-z0-9_]+)@", token_value, param)
+ if at_only:
+ return token_value
+ return replace_pattern_in_string(r"\${([A-Za-z0-9_]+)}", token_value, param)
+
+
+if __name__ == "__main__":
+ input_file = argv[1]
+ param_file = argv[2]
+ magic_string = argv[3]
+ at_only = argv[4] == "true"
+
+ with open(param_file) as f:
+ param = json.loads(f.read())
+
+ # In many cases, CMake simply defines some variables (without any associated
+ # value). We handle this situation by assigning to the boolean True the empty
+ # string. Note that no False value should be found, because the right way to set
+ # a variable to False in the TARGETS file is to *do not mention* that variable
+ # at all.
+ # If a value is deliberately set to null, we will drop that key
+ drop_keys: list[str] = []
+ for k, v in param.items():
+ if isinstance(v, bool):
+ param[k] = ""
+ if v == None:
+ drop_keys.append(k)
+ for k in drop_keys:
+ del param[k]
+
+ with open(input_file) as i:
+ with open("out", "w") as o:
+ for line in i.readlines():
+ # drop trailing '\n'
+ line = line[:-1]
+
+ tokens, is_01 = get_tokens(line, magic_string)
+ # no magic string
+ if not tokens:
+ # it can be a simple comment, or a line without the magic string but with the @KEY@ or ${KEY} pattern
+ line = compute_value(line, at_only, param)
+ print(line, file=o)
+ continue
+
+ # line contains magic_string
+ groups = tokens.groups()
+
+ token_key: str = groups[3]
+
+ if is_01:
+ line = handle01(line, tokens, token_key in param)
+ print(line, file=o)
+ continue
+
+ if token_key not in param:
+ line = undefine(tokens)
+ print(line, file=o)
+ continue
+
+ # we are in one of this situations
+ # cmakedefine FOO
+ # cmakedefine FOO "foo"
+ # cmakedefine FOO @FOO@${FOO}foo
+
+ # i.e., the token_value can be any combination of keys (defined
+ # as @key@ or ${key}) and strings
+
+ # therefore, we need to further tokenize the token_value
+
+ # it is convenient to first tokenize
+
+ token_value: str = groups[5]
+
+ value = compute_value(token_value, at_only, param)
+
+ line = replace_value(tokens, token_key, value)
+
+ print(line, file=o)