diff options
Diffstat (limited to 'rules')
48 files changed, 14000 insertions, 0 deletions
diff --git a/rules/CC/EXPRESSIONS b/rules/CC/EXPRESSIONS new file mode 100644 index 0000000..938c342 --- /dev/null +++ b/rules/CC/EXPRESSIONS @@ -0,0 +1,2586 @@ +{ "default-CC": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "CC"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["CC", {"type": "CALL_EXPRESSION", "name": "list_provider"}] + , [ "CC" + , { "type": "if" + , "cond": {"type": "var", "name": "CC"} + , "then": {"type": "var", "name": "CC"} + , "else": ["cc"] + } + ] + ] + , "body": {"type": "var", "name": "CC"} + } + } +, "default-CXX": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "CXX"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["CXX", {"type": "CALL_EXPRESSION", "name": "list_provider"}] + , [ "CXX" + , { "type": "if" + , "cond": {"type": "var", "name": "CXX"} + , "then": {"type": "var", "name": "CXX"} + , "else": ["c++"] + } + ] + ] + , "body": {"type": "var", "name": "CXX"} + } + } +, "default-AR": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "AR"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["AR", {"type": "CALL_EXPRESSION", "name": "list_provider"}] + , [ "AR" + , { "type": "if" + , "cond": {"type": "var", "name": "AR"} + , "then": {"type": "var", "name": "AR"} + , "else": ["ar"] + } + ] + ] + , "body": {"type": "var", "name": "AR"} + } + } +, "default-CFLAGS": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "CFLAGS"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-CXXFLAGS": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "CXXFLAGS"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-LDFLAGS": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "LDFLAGS"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-ENV": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "ENV"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-PATH": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "PATH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-TOOLCHAIN": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "defaults"] + , ["provider", "TOOLCHAIN"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-NON_SYSTEM_TOOLS": + { "vars": ["defaults-transition"] + , "expression": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": "defaults"} + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": "NON_SYSTEM_TOOLS" + , "transition": + { "type": "var" + , "name": "defaults-transition" + , "default": {"type": "empty_map"} + } + , "default": {"type": "empty_map"} + } + } + } + } +, "defaults-base-provides-list": + { "doc": ["Query list of providers from 'base' targets"] + , "vars": ["provider", "default"] + , "vars_doc": + { "provider": ["The name of the provider in the provides map."] + , "default": ["The default if provider is missing (default: [])."] + } + , "imports": {"provider_list": ["./", "..", "field_provider_list"]} + , "expression": + { "type": "let*" + , "bindings": [["fieldname", "base"]] + , "body": {"type": "CALL_EXPRESSION", "name": "provider_list"} + } + } +, "defaults-base-provides-++": + { "doc": ["Query flattend list of providers from 'base' targets"] + , "vars": ["provider", "default"] + , "vars_doc": + { "provider": ["The name of the provider in the provides map."] + , "default": ["The default if provider is missing (default: [])."] + } + , "imports": {"base-provides-list": "defaults-base-provides-list"} + , "expression": + { "type": "++" + , "$1": {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + } + } +, "defaults-base-provides": + { "doc": ["Query provider from 'base' targets (last wins)"] + , "vars": ["provider", "default"] + , "vars_doc": + { "provider": ["The name of the provider in the provides map."] + , "default": ["The default if provider is missing (default: [])."] + } + , "imports": {"base-provides-list": "defaults-base-provides-list"} + , "expression": + { "type": "foldl" + , "var": "next" + , "start": {"type": "var", "name": "default", "default": []} + , "accum_var": "curr" + , "range": {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "next"} + , "then": {"type": "var", "name": "next"} + , "else": {"type": "var", "name": "curr"} + } + } + } +, "debug-deps": + { "doc": + ["Collect debug dependencies (sources/headers) from given target_fields"] + , "vars": ["deps-provider", "deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-provider": ["Name of provider to use (debug-srcs/debug-hdrs)."] + , "deps-fieldnames": + ["List of target_field names to collect dependencies from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"provider_list": ["./", "..", "field_provider_list"]} + , "expression": + { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "++" + , "$1": + { "type": "let*" + , "bindings": + [ ["provider", {"type": "var", "name": "deps-provider"}] + , ["transition", {"type": "var", "name": "deps-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": [{"type": "CALL_EXPRESSION", "name": "provider_list"}] + } + } + } + } + } + } +, "compile-deps": + { "doc": ["Collect compile dependencies (headers) from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect dependencies from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": + { "runfiles_list": ["./", "..", "field_runfiles_list"] + , "provider_list": ["./", "..", "field_provider_list"] + } + , "expression": + { "type": "disjoint_map_union" + , "$1": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "++" + , "$1": + { "type": "let*" + , "bindings": + [ ["provider", "compile-deps"] + , ["transition", {"type": "var", "name": "deps-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": + [ {"type": "CALL_EXPRESSION", "name": "provider_list"} + , {"type": "CALL_EXPRESSION", "name": "runfiles_list"} + ] + } + } + } + } + } + } +, "compile-args-deps": + { "doc": ["Collect compile arguments from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect arguments from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "compile-args"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } + } + } +, "link-deps": + { "doc": ["Collect link dependencies (libraries) from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect dependencies from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": + { "artifacts_list": ["./", "..", "field_artifacts_list"] + , "provider_list": ["./", "..", "field_provider_list"] + } + , "expression": + { "type": "disjoint_map_union" + , "$1": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "++" + , "$1": + { "type": "let*" + , "bindings": + [ ["provider", "link-deps"] + , ["default", {"type": "empty_map"}] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": + [ {"type": "CALL_EXPRESSION", "name": "provider_list"} + , {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + ] + } + } + } + } + } + } +, "link-args-deps": + { "doc": ["Collect linker arguments from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect arguments from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "link-args"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } + } + } +, "run-libs-deps": + { "doc": ["Collect runtime libraries from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect dependencies from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"provider_list": ["./", "..", "field_provider_list"]} + , "expression": + { "type": "to_subdir" + , "flat": true + , "$1": + { "type": "disjoint_map_union" + , "$1": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "run-libs"] + , ["default", {"type": "empty_map"}] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "provider_list"} + } + } + } + } + } + } +, "run-libs-args-deps": + { "doc": + ["Collect runtime libraries link arguments from given target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": + ["List of target_field names to collect arguments from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "run-libs-args"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } + } + } +, "pkg-map-provider-deps": + { "doc": ["Collect maps from provider \"package\" for given target_fields"] + , "vars": ["pkg-key", "deps-fieldnames", "deps-transition"] + , "vars_doc": + { "pkg-key": ["Key to lookup in provider \"package\"."] + , "deps-fieldnames": ["List of target_field names to collect maps from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"provider_list": ["./", "..", "field_provider_list"]} + , "expression": + { "type": "disjoint_map_union" + , "$1": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "deps-fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "package"] + , ["default", {"type": "empty_map"}] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": + { "type": "foreach" + , "range": {"type": "CALL_EXPRESSION", "name": "provider_list"} + , "var": "map" + , "body": + { "type": "lookup" + , "key": {"type": "var", "name": "pkg-key"} + , "map": {"type": "var", "name": "map"} + , "default": {"type": "empty_map"} + } + } + } + } + } + } + } +, "cflags-files-deps": + { "doc": ["Collect cflags files from target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": ["List of target_field names to collect files from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"pkg-provider": "pkg-map-provider-deps"} + , "expression": + { "type": "let*" + , "bindings": [["pkg-key", "cflags-files"]] + , "body": {"type": "CALL_EXPRESSION", "name": "pkg-provider"} + } + } +, "ldflags-files-deps": + { "doc": ["Collect cflags files from target_fields"] + , "vars": ["deps-fieldnames", "deps-transition"] + , "vars_doc": + { "deps-fieldnames": ["List of target_field names to collect files from."] + , "deps-transition": + ["The optional configuration transition for the targets."] + } + , "imports": {"pkg-provider": "pkg-map-provider-deps"} + , "expression": + { "type": "let*" + , "bindings": [["pkg-key", "ldflags-files"]] + , "body": {"type": "CALL_EXPRESSION", "name": "pkg-provider"} + } + } +, "pkg-prefix-lib-paths": + { "doc": ["Detect ldflags referring to local libs and prefix them."] + , "vars": ["pkg-ldflags", "pkg-libs", "flat-libs", "lib-prefix"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "libs set" + , { "type": "set" + , "$1": {"type": "keys", "$1": {"type": "var", "name": "pkg-libs"}} + } + ] + ] + , "body": + { "type": "foreach" + , "var": "item" + , "range": {"type": "var", "name": "pkg-ldflags"} + , "body": + { "type": "if" + , "cond": + { "type": "lookup" + , "key": {"type": "var", "name": "item"} + , "map": {"type": "var", "name": "libs set"} + } + , "then": + { "type": "join" + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "flat-libs"} + , "then": + [ "-l:" + , {"type": "basename", "$1": {"type": "var", "name": "item"}} + ] + , "else": + [ {"type": "var", "name": "lib-prefix"} + , "/" + , {"type": "var", "name": "item"} + ] + } + } + , "else": {"type": "var", "name": "item"} + } + } + } + } +, "pkg-prefix-flag-paths": + { "doc": ["Detect flags referring to local flag files and prefix them."] + , "vars": ["flags", "pkg-flag-files", "flag-prefix"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "pkg-flag-files unprefix map" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "name" + , "range": + {"type": "keys", "$1": {"type": "var", "name": "pkg-flag-files"}} + , "body": + { "type": "singleton_map" + , "key": + {"type": "join", "$1": ["@", {"type": "var", "name": "name"}]} + , "value": {"type": "var", "name": "name"} + } + } + } + ] + ] + , "body": + { "type": "foreach" + , "var": "item" + , "range": {"type": "var", "name": "flags"} + , "body": + { "type": "let*" + , "bindings": + [ [ "flag-file" + , { "type": "lookup" + , "map": {"type": "var", "name": "pkg-flag-files unprefix map"} + , "key": {"type": "var", "name": "item"} + } + ] + ] + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "flag-file"} + , "then": + { "type": "join" + , "$1": + [ "@" + , {"type": "var", "name": "flag-prefix"} + , "/" + , {"type": "var", "name": "flag-file"} + ] + } + , "else": {"type": "var", "name": "item"} + } + } + } + } + } +, "pkg-config": + { "vars": + [ "pkg-name" + , "pkg-prefix" + , "pkg-version" + , "pkg-cflags" + , "pkg-ldflags" + , "pkg-flag-files" + , "pkg-libs" + , "flat-libs" + , "pc-install-dir" + ] + , "imports": + { "pkg-prefix-lib-paths": "pkg-prefix-lib-paths" + , "pkg-prefix-flag-paths": "pkg-prefix-flag-paths" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["lib-prefix", "${libdir}"] + , [ "pkg-ldflags" + , {"type": "CALL_EXPRESSION", "name": "pkg-prefix-lib-paths"} + ] + , [ "flag-prefix" + , { "type": "join" + , "$1": ["${prefix}/", {"type": "var", "name": "pc-install-dir"}] + } + ] + , ["flags", {"type": "var", "name": "pkg-cflags"}] + , [ "pkg-cflags" + , {"type": "CALL_EXPRESSION", "name": "pkg-prefix-flag-paths"} + ] + , ["flags", {"type": "var", "name": "pkg-ldflags"}] + , [ "pkg-ldflags" + , {"type": "CALL_EXPRESSION", "name": "pkg-prefix-flag-paths"} + ] + ] + , "body": + { "type": "singleton_map" + , "key": + {"type": "join", "$1": [{"type": "var", "name": "pkg-name"}, ".pc"]} + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + [ { "type": "join" + , "$1": + [ "prefix=" + , {"type": "var", "name": "pkg-prefix", "default": "/"} + ] + } + , "libdir=${prefix}/lib" + , "includedir=${prefix}/include" + , { "type": "join" + , "$1": ["Name: ", {"type": "var", "name": "pkg-name"}] + } + , { "type": "join" + , "$1": + [ "Version: " + , {"type": "var", "name": "pkg-version", "default": "unknown"} + ] + } + , { "type": "join" + , "$1": + [ "Description: Pkg-config for " + , {"type": "var", "name": "pkg-name"} + , ", generated by JustBuild" + ] + } + , "URL: unknown" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ ["Cflags:", "-I${includedir}"] + , {"type": "var", "name": "pkg-cflags"} + ] + } + } + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ ["Libs:"] + , { "type": "if" + , "cond": {"type": "var", "name": "flat-libs"} + , "then": ["-L${libdir}"] + } + , {"type": "var", "name": "pkg-ldflags"} + ] + } + } + , "" + ] + } + } + } + } + } +, "objects": + { "vars": + [ "COMPILER" + , "COMPILE_FLAGS" + , "ENV" + , "TOOLCHAIN" + , "srcs" + , "hdrs" + , "private-hdrs" + , "compile-deps" + , "cflags-files" + ] + , "expression": + { "type": "let*" + , "bindings": + [ [ "include tree" + , { "type": "singleton_map" + , "key": "include" + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "compile-deps"}} + } + ] + , [ "all hdrs" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "include tree"} + , { "type": "to_subdir" + , "subdir": "work" + , "$1": + { "type": "disjoint_map_union" + , "$1": + [ {"type": "var", "name": "hdrs"} + , {"type": "var", "name": "private-hdrs"} + ] + } + } + ] + } + ] + ] + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "var_key": "src_name" + , "var_val": "src_val" + , "range": {"type": "var", "name": "srcs"} + , "body": + { "type": "let*" + , "bindings": + [ [ "work src_name" + , { "type": "join" + , "separator": "/" + , "$1": ["work", {"type": "var", "name": "src_name"}] + } + ] + , [ "inputs" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "all hdrs"} + , { "type": "singleton_map" + , "key": {"type": "var", "name": "work src_name"} + , "value": {"type": "var", "name": "src_val"} + } + , { "type": "var" + , "name": "cflags-files" + , "default": {"type": "empty_map"} + } + , { "type": "var" + , "name": "TOOLCHAIN" + , "default": {"type": "empty_map"} + } + ] + } + ] + , [ "out" + , { "type": "change_ending" + , "$1": {"type": "var", "name": "src_name"} + , "ending": ".o" + } + ] + , [ "work out" + , { "type": "join" + , "separator": "/" + , "$1": ["work", {"type": "var", "name": "out"}] + } + ] + , [ "action output" + , { "type": "ACTION" + , "outs": [{"type": "var", "name": "work out"}] + , "inputs": {"type": "var", "name": "inputs"} + , "env": + { "type": "var" + , "name": "ENV" + , "default": {"type": "empty_map"} + } + , "cmd": + { "type": "++" + , "$1": + [ [{"type": "var", "name": "COMPILER"}] + , {"type": "var", "name": "COMPILE_FLAGS"} + , ["-I", "work", "-isystem", "include"] + , ["-c", {"type": "var", "name": "work src_name"}] + , ["-o", {"type": "var", "name": "work out"}] + ] + } + } + ] + , [ "staged output artifact" + , { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "range": {"type": "var", "name": "action output"} + , "var_val": "object" + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "out"} + , "value": {"type": "var", "name": "object"} + } + } + } + ] + ] + , "body": {"type": "var", "name": "staged output artifact"} + } + } + } + } + } +, "compiler-cc": + { "vars": ["CC", "TOOLCHAIN_DIR", "NON_SYSTEM_TOOLS", "defaults-transition"] + , "imports": {"default-CC": "default-CC"} + , "expression": + { "type": "var" + , "name": "CC" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CC" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-CC"} + ] + } + } + } + } +, "compiler-cxx": + { "vars": ["CXX", "TOOLCHAIN_DIR", "NON_SYSTEM_TOOLS", "defaults-transition"] + , "imports": {"default-CXX": "default-CXX"} + , "expression": + { "type": "var" + , "name": "CXX" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CXX" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-CXX"} + ] + } + } + } + } +, "compiler": + { "vars": + [ "CC" + , "CXX" + , "pure C" + , "TOOLCHAIN_DIR" + , "NON_SYSTEM_TOOLS" + , "defaults-transition" + ] + , "imports": {"compiler-cc": "compiler-cc", "compiler-cxx": "compiler-cxx"} + , "expression": + { "type": "if" + , "cond": {"type": "var", "name": "pure C"} + , "then": {"type": "CALL_EXPRESSION", "name": "compiler-cc"} + , "else": {"type": "CALL_EXPRESSION", "name": "compiler-cxx"} + } + } +, "flags-cc": + { "vars": + [ "CFLAGS" + , "ADD_CFLAGS" + , "BUILD_POSITION_INDEPENDENT" + , "defaults-transition" + ] + , "imports": {"default-CFLAGS": "default-CFLAGS"} + , "expression": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": {"type": "var", "name": "BUILD_POSITION_INDEPENDENT"} + , "then": ["-fPIC"] + } + , { "type": "var" + , "name": "CFLAGS" + , "default": {"type": "CALL_EXPRESSION", "name": "default-CFLAGS"} + } + , {"type": "var", "name": "ADD_CFLAGS", "default": []} + ] + } + } +, "flags-cxx": + { "vars": + [ "CXXFLAGS" + , "ADD_CXXFLAGS" + , "BUILD_POSITION_INDEPENDENT" + , "defaults-transition" + ] + , "imports": {"default-CXXFLAGS": "default-CXXFLAGS"} + , "expression": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": {"type": "var", "name": "BUILD_POSITION_INDEPENDENT"} + , "then": ["-fPIC"] + } + , { "type": "var" + , "name": "CXXFLAGS" + , "default": {"type": "CALL_EXPRESSION", "name": "default-CXXFLAGS"} + } + , {"type": "var", "name": "ADD_CXXFLAGS", "default": []} + ] + } + } +, "flags": + { "vars": + [ "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "BUILD_POSITION_INDEPENDENT" + , "pure C" + , "defaults-transition" + ] + , "imports": {"flags-cc": "flags-cc", "flags-cxx": "flags-cxx"} + , "expression": + { "type": "if" + , "cond": {"type": "var", "name": "pure C"} + , "then": {"type": "CALL_EXPRESSION", "name": "flags-cc"} + , "else": {"type": "CALL_EXPRESSION", "name": "flags-cxx"} + } + } +, "lib artifact": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "AR" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "stage" + , "compile-deps" + , "compile-args" + , "cflags-files" + , "defaults-transition" + ] + , "imports": + { "compiler": "compiler" + , "flags": "flags" + , "objects": "objects" + , "default-AR": "default-AR" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , ["COMPILER", {"type": "CALL_EXPRESSION", "name": "compiler"}] + , [ "COMPILE_FLAGS" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "flags"} + , {"type": "var", "name": "compile-args"} + ] + } + ] + , [ "AR" + , { "type": "var" + , "name": "AR" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-AR"} + ] + } + } + } + ] + , [ "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"}] + } + ] + } + } + } + ] + } + ] + , ["objects", {"type": "CALL_EXPRESSION", "name": "objects"}] + , [ "base name" + , { "type": "if" + , "cond": {"type": "var", "name": "objects"} + , "then": + { "type": "assert_non_empty" + , "msg": "A name has to be provided for non-header-only libraries" + , "$1": {"type": "var", "name": "name"} + } + , "else": {"type": "var", "name": "name"} + } + ] + , [ "libname" + , { "type": "join" + , "$1": ["lib", {"type": "var", "name": "base name"}, ".a"] + } + ] + , [ "libpath" + , { "type": "if" + , "cond": {"type": "var", "name": "stage"} + , "then": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "stage"} + , {"type": "var", "name": "libname"} + ] + } + , "else": {"type": "var", "name": "libname"} + } + ] + , [ "lib" + , { "type": "if" + , "cond": {"type": "var", "name": "objects"} + , "else": {"type": "empty_map"} + , "then": + { "type": "ACTION" + , "outs": [{"type": "var", "name": "libpath"}] + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "objects"} + ] + } + , "env": + {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + , "cmd": + { "type": "++" + , "$1": + [ [ {"type": "var", "name": "AR", "default": "ar"} + , "cqs" + , {"type": "var", "name": "libpath"} + ] + , {"type": "keys", "$1": {"type": "var", "name": "objects"}} + ] + } + } + } + ] + ] + , "body": {"type": "var", "name": "lib"} + } + } +, "lib result": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "AR" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "DEBUG" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "cflags" + , "private-cflags" + , "ldflags" + , "private-ldflags" + , "stage" + , "pkg-name" + , "extra-provides" + , "public-fieldnames" + , "private-fieldnames" + ] + , "imports": + { "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "cflags-files-deps": "cflags-files-deps" + , "ldflags-files-deps": "ldflags-files-deps" + , "lib artifact": "lib artifact" + , "debug-deps": "debug-deps" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["deps-fieldnames", {"type": "var", "name": "private-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "var", "name": "private-cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["lib", {"type": "CALL_EXPRESSION", "name": "lib artifact"}] + , [ "link-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "keys", "$1": {"type": "var", "name": "lib"}} + , {"type": "var", "name": "ldflags", "default": []} + , {"type": "var", "name": "private-ldflags", "default": []} + , {"type": "CALL_EXPRESSION", "name": "link-args-deps"} + ] + } + } + ] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , { "type": "nub_right" + , "$1": {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + } + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "srcs"} + , {"type": "var", "name": "private-hdrs"} + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , ["deps-fieldnames", {"type": "var", "name": "public-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , [ "package" + , { "type": "let*" + , "bindings": [["name", {"type": "var", "name": "pkg-name"}]] + , "body": + {"type": "env", "vars": ["name", "cflags-files", "ldflags-files"]} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "lib"} + , "runfiles": {"type": "var", "name": "hdrs"} + , "provides": + { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + , "debug-srcs" + , "debug-hdrs" + ] + } + , { "type": "var" + , "name": "extra-provides" + , "default": {"type": "empty_map"} + } + ] + } + } + } + } +, "shared artifact": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "soversion" + , "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "cflags-files" + , "ldflags-files" + , "defaults-transition" + ] + , "imports": + { "compiler": "compiler" + , "flags": "flags" + , "objects": "objects" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-LDFLAGS": "default-LDFLAGS" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["BUILD_POSITION_INDEPENDENT", true] + , ["TOOLCHAIN_DIR", "toolchain"] + , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , ["COMPILER", {"type": "CALL_EXPRESSION", "name": "compiler"}] + , [ "COMPILE_FLAGS" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "flags"} + , {"type": "var", "name": "compile-args"} + ] + } + ] + , [ "LDFLAGS" + , { "type": "++" + , "$1": + [ { "type": "var" + , "name": "LDFLAGS" + , "default": + {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + } + , {"type": "var", "name": "ADD_LDFLAGS", "default": []} + ] + } + ] + , [ "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"}] + } + ] + } + } + } + ] + } + ] + , ["objects", {"type": "CALL_EXPRESSION", "name": "objects"}] + , [ "base name" + , { "type": "if" + , "cond": + { "type": "or" + , "$1": + [ {"type": "var", "name": "objects"} + , {"type": "var", "name": "link-deps"} + ] + } + , "then": + { "type": "assert_non_empty" + , "msg": "A name has to be provided for non-header-only libraries" + , "$1": {"type": "var", "name": "name"} + } + , "else": {"type": "var", "name": "name"} + } + ] + , [ "libname" + , { "type": "join" + , "$1": ["lib", {"type": "var", "name": "base name"}, ".so"] + } + ] + , [ "libname" + , { "type": "join" + , "separator": "." + , "$1": + { "type": "++" + , "$1": + [ [{"type": "var", "name": "libname"}] + , {"type": "var", "name": "soversion"} + ] + } + } + ] + , [ "lib" + , { "type": "if" + , "cond": + { "type": "or" + , "$1": + [ {"type": "var", "name": "objects"} + , {"type": "var", "name": "link-deps"} + ] + } + , "else": {"type": "empty_map"} + , "then": + { "type": "ACTION" + , "outs": [{"type": "var", "name": "libname"}] + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "objects"} + , {"type": "var", "name": "link-deps"} + , {"type": "var", "name": "run-libs"} + , { "type": "var" + , "name": "cflags-files" + , "default": {"type": "empty_map"} + } + , { "type": "var" + , "name": "ldflags-files" + , "default": {"type": "empty_map"} + } + ] + } + , "env": + {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + , "cmd": + { "type": "++" + , "$1": + [ [ {"type": "var", "name": "COMPILER"} + , "-shared" + , "-Wl,-rpath,$ORIGIN" + , "-Wl,-rpath,$ORIGIN/../lib" + , { "type": "join" + , "$1": + ["-Wl,-soname,", {"type": "var", "name": "libname"}] + } + ] + , {"type": "var", "name": "COMPILE_FLAGS"} + , ["-o", {"type": "var", "name": "libname"}] + , {"type": "keys", "$1": {"type": "var", "name": "objects"}} + , {"type": "var", "name": "link-args"} + , {"type": "var", "name": "run-libs-args"} + , {"type": "var", "name": "LDFLAGS"} + ] + } + } + } + ] + ] + , "body": {"type": "var", "name": "lib"} + } + } +, "shared result": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "DEBUG" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "cflags" + , "private-cflags" + , "ldflags" + , "private-ldflags" + , "soversion" + , "pkg-name" + , "extra-provides" + , "defaults-transition" + , "deps-transition" + , "public-fieldnames" + , "private-fieldnames" + ] + , "imports": + { "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "cflags-files-deps": "cflags-files-deps" + , "ldflags-files-deps": "ldflags-files-deps" + , "shared artifact": "shared artifact" + , "debug-deps": "debug-deps" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["deps-fieldnames", {"type": "var", "name": "private-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "var", "name": "private-cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["link-args", {"type": "CALL_EXPRESSION", "name": "link-args-deps"}] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "ldflags", "default": []} + , {"type": "var", "name": "private-ldflags", "default": []} + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + } + } + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , ["lib", {"type": "CALL_EXPRESSION", "name": "shared artifact"}] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "srcs"} + , {"type": "var", "name": "private-hdrs"} + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , ["deps-fieldnames", {"type": "var", "name": "public-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["link-args", {"type": "CALL_EXPRESSION", "name": "link-args-deps"}] + , [ "run-libs" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "lib"} + , {"type": "var", "name": "run-libs"} + ] + } + ] + , [ "run-libs-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "keys", "$1": {"type": "var", "name": "lib"}} + , {"type": "var", "name": "ldflags", "default": []} + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + } + } + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , [ "package" + , { "type": "let*" + , "bindings": + [ ["name", {"type": "var", "name": "pkg-name"}] + , [ "version" + , { "type": "if" + , "cond": {"type": "var", "name": "soversion"} + , "then": + { "type": "join" + , "separator": "." + , "$1": {"type": "var", "name": "soversion"} + } + , "else": null + } + ] + ] + , "body": + { "type": "env" + , "vars": ["name", "version", "cflags-files", "ldflags-files"] + } + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "lib"} + , "runfiles": {"type": "var", "name": "hdrs"} + , "provides": + { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + , "debug-srcs" + , "debug-hdrs" + ] + } + , { "type": "var" + , "name": "extra-provides" + , "default": {"type": "empty_map"} + } + ] + } + } + } + } +, "object artifacts": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "AR" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "stage" + , "compile-deps" + , "compile-args" + , "cflags-files" + , "defaults-transition" + ] + , "imports": + { "compiler": "compiler" + , "flags": "flags" + , "objects": "objects" + , "default-AR": "default-AR" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , ["COMPILER", {"type": "CALL_EXPRESSION", "name": "compiler"}] + , [ "COMPILE_FLAGS" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "flags"} + , {"type": "var", "name": "compile-args"} + ] + } + ] + , [ "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"}] + } + ] + } + } + } + ] + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "objects"} + } + } +, "object result": + { "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "AR" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "DEBUG" + , "name" + , "pure C" + , "srcs" + , "hdrs" + , "private-hdrs" + , "cflags" + , "private-cflags" + , "ldflags" + , "private-ldflags" + , "stage" + , "pkg-name" + , "extra-provides" + , "public-fieldnames" + , "private-fieldnames" + ] + , "imports": + { "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "cflags-files-deps": "cflags-files-deps" + , "ldflags-files-deps": "ldflags-files-deps" + , "object artifacts": "object artifacts" + , "debug-deps": "debug-deps" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["deps-fieldnames", {"type": "var", "name": "private-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "var", "name": "private-cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["objects", {"type": "CALL_EXPRESSION", "name": "object artifacts"}] + , [ "link-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "keys", "$1": {"type": "var", "name": "objects"}} + , {"type": "var", "name": "ldflags", "default": []} + , {"type": "var", "name": "private-ldflags", "default": []} + , {"type": "CALL_EXPRESSION", "name": "link-args-deps"} + ] + } + } + ] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , { "type": "nub_right" + , "$1": {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + } + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "srcs"} + , {"type": "var", "name": "private-hdrs"} + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , ["deps-fieldnames", {"type": "var", "name": "public-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , [ "package" + , { "type": "let*" + , "bindings": [["name", {"type": "var", "name": "pkg-name"}]] + , "body": + {"type": "env", "vars": ["name", "cflags-files", "ldflags-files"]} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "objects"} + , "runfiles": {"type": "var", "name": "hdrs"} + , "provides": + { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + , "debug-srcs" + , "debug-hdrs" + ] + } + , { "type": "var" + , "name": "extra-provides" + , "default": {"type": "empty_map"} + } + ] + } + } + } + } +, "bin artifact": + { "doc": ["Produces the binary artifact."] + , "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "name" + , "pure C" + , "srcs" + , "private-hdrs" + , "stage" + , "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "cflags-files" + , "ldflags-files" + , "defaults-transition" + ] + , "imports": + { "compiler": "compiler" + , "flags": "flags" + , "objects": "objects" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-LDFLAGS": "default-LDFLAGS" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , ["COMPILER", {"type": "CALL_EXPRESSION", "name": "compiler"}] + , [ "COMPILE_FLAGS" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "flags"} + , {"type": "var", "name": "compile-args"} + ] + } + ] + , [ "LDFLAGS" + , { "type": "++" + , "$1": + [ { "type": "var" + , "name": "LDFLAGS" + , "default": + {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + } + , {"type": "var", "name": "ADD_LDFLAGS", "default": []} + ] + } + ] + , [ "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"}] + } + ] + } + } + } + ] + } + ] + , ["hdrs", {"type": "empty_map"}] + , ["objects", {"type": "CALL_EXPRESSION", "name": "objects"}] + , [ "link-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "keys", "$1": {"type": "var", "name": "objects"}} + , {"type": "var", "name": "link-args"} + ] + } + } + ] + , [ "binpath" + , { "type": "if" + , "cond": {"type": "var", "name": "stage"} + , "then": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "stage"} + , {"type": "var", "name": "name"} + ] + } + , "else": {"type": "var", "name": "name"} + } + ] + , [ "binary" + , { "type": "ACTION" + , "outs": [{"type": "var", "name": "binpath"}] + , "inputs": + { "type": "disjoint_map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "objects"} + , {"type": "var", "name": "link-deps"} + , {"type": "var", "name": "run-libs"} + , { "type": "var" + , "name": "cflags-files" + , "default": {"type": "empty_map"} + } + , { "type": "var" + , "name": "ldflags-files" + , "default": {"type": "empty_map"} + } + ] + } + , "cmd": + { "type": "++" + , "$1": + [ [ {"type": "var", "name": "COMPILER"} + , "-Wl,-rpath,$ORIGIN" + , "-Wl,-rpath,$ORIGIN/../lib" + , "-o" + , {"type": "var", "name": "binpath"} + ] + , {"type": "var", "name": "COMPILE_FLAGS"} + , {"type": "var", "name": "link-args"} + , {"type": "var", "name": "run-libs-args"} + , {"type": "var", "name": "LDFLAGS"} + ] + } + , "env": {"type": "var", "name": "ENV"} + } + ] + ] + , "body": {"type": "var", "name": "binary"} + } + } +, "bin result": + { "doc": ["Produces the binary target result."] + , "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "DEBUG" + , "name" + , "pure C" + , "srcs" + , "private-hdrs" + , "private-cflags" + , "private-ldflags" + , "stage" + , "private-fieldnames" + ] + , "imports": + { "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "cflags-files-deps": "cflags-files-deps" + , "ldflags-files-deps": "ldflags-files-deps" + , "binary": "bin artifact" + , "debug-deps": "debug-deps" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["deps-fieldnames", {"type": "var", "name": "private-fieldnames"}] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + , {"type": "var", "name": "private-cflags"} + ] + } + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , [ "link-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "private-ldflags"} + , {"type": "CALL_EXPRESSION", "name": "link-args-deps"} + ] + } + } + ] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , ["package", {"type": "singleton_map", "key": "to_bin", "value": true}] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "srcs"} + , {"type": "var", "name": "private-hdrs"} + ] + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "compile-deps"} + ] + } + , "else": {"type": "empty_map"} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "CALL_EXPRESSION", "name": "binary"} + , "provides": + { "type": "env" + , "vars": ["run-libs", "package", "debug-srcs", "debug-hdrs"] + } + } + } + } +, "install-with-deps stage": + { "vars": + [ "pc-install-dir" + , "targets" + , "prefix" + , "flat-libs" + , "hdrs-only" + , "skip-debug-stage" + ] + , "imports": + { "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "pkg-config": "pkg-config" + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "install-stage" + , { "type": "disjoint_map_union" + , "msg": "install stages may not overlap" + , "$1": + { "type": "foreach" + , "var": "target" + , "range": {"type": "var", "name": "targets"} + , "body": + { "type": "let*" + , "bindings": + [ [ "runfiles" + , { "type": "DEP_RUNFILES" + , "dep": {"type": "var", "name": "target"} + , "default": {"type": "empty_map"} + } + ] + , [ "compile-deps" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "compile-deps" + , "default": {"type": "empty_map"} + } + ] + , [ "headers" + , { "type": "disjoint_map_union" + , "msg": "headers may not overlap" + , "$1": + [ {"type": "var", "name": "runfiles"} + , {"type": "var", "name": "compile-deps"} + ] + } + ] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "skip-debug-stage"} + , "then": {"type": "empty_map"} + , "else": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "debug-srcs" + , "default": {"type": "empty_map"} + } + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "skip-debug-stage"} + , "then": {"type": "empty_map"} + , "else": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "debug-hdrs" + , "default": {"type": "empty_map"} + } + } + ] + ] + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "hdrs-only"} + , "then": {"type": "var", "name": "headers"} + , "else": + { "type": "let*" + , "bindings": + [ [ "artifacts" + , { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "target"} + , "default": {"type": "empty_map"} + } + ] + , [ "link-deps" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "link-deps" + , "default": {"type": "empty_map"} + } + ] + , [ "run-libs" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "run-libs" + , "default": {"type": "empty_map"} + } + ] + , [ "package" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "package" + , "default": {"type": "empty_map"} + } + ] + , [ "to_bin" + , { "type": "lookup" + , "key": "to_bin" + , "map": {"type": "var", "name": "package"} + } + ] + , [ "binaries" + , { "type": "if" + , "cond": {"type": "var", "name": "to_bin"} + , "then": {"type": "var", "name": "artifacts"} + , "else": {"type": "empty_map"} + } + ] + , [ "libraries" + , { "type": "disjoint_map_union" + , "msg": "libraries may not overlap" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": {"type": "var", "name": "to_bin"} + , "then": [] + , "else": [{"type": "var", "name": "artifacts"}] + } + , [{"type": "var", "name": "link-deps"}] + , [{"type": "var", "name": "run-libs"}] + ] + } + } + ] + , [ "pkg-name" + , { "type": "lookup" + , "key": "name" + , "map": {"type": "var", "name": "package"} + } + ] + , [ "pkg-config" + , { "type": "if" + , "cond": {"type": "var", "name": "pkg-name"} + , "then": + { "type": "let*" + , "bindings": + [ ["pkg-prefix", {"type": "var", "name": "prefix"}] + , [ "pkg-version" + , { "type": "lookup" + , "key": "version" + , "map": {"type": "var", "name": "package"} + } + ] + , [ "pkg-cflags" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "compile-args" + , "default": [] + } + ] + , [ "pkg-ldflags" + , { "type": "++" + , "$1": + [ { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "link-args" + , "default": [] + } + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "target"} + , "provider": "run-libs-args" + , "default": [] + } + ] + } + ] + , [ "pkg-flag-files" + , { "type": "map_union" + , "$1": + [ { "type": "lookup" + , "key": "cflags-files" + , "map": {"type": "var", "name": "package"} + , "default": {"type": "empty_map"} + } + , { "type": "lookup" + , "key": "ldflags-files" + , "map": {"type": "var", "name": "package"} + , "default": {"type": "empty_map"} + } + ] + } + ] + , [ "pkg-libs" + , {"type": "var", "name": "libraries"} + ] + , [ "flat-libs" + , {"type": "var", "name": "flat-libs"} + ] + ] + , "body": + { "type": "map_union" + , "$1": + [ { "type": "CALL_EXPRESSION" + , "name": "pkg-config" + } + , {"type": "var", "name": "pkg-flag-files"} + ] + } + } + , "else": {"type": "empty_map"} + } + ] + ] + , "body": + { "type": "map_union" + , "$1": + [ { "type": "to_subdir" + , "subdir": "bin" + , "flat": true + , "msg": "install binaries may not overlap" + , "$1": {"type": "var", "name": "binaries"} + } + , { "type": "to_subdir" + , "subdir": "include" + , "$1": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "headers"} + , {"type": "var", "name": "debug-hdrs"} + ] + } + } + , { "type": "to_subdir" + , "subdir": "lib" + , "flat": {"type": "var", "name": "flat-libs"} + , "msg": "install libraries may not overlap" + , "$1": {"type": "var", "name": "libraries"} + } + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "pc-install-dir"} + , "$1": {"type": "var", "name": "pkg-config"} + } + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "debug-srcs"} + } + ] + } + } + } + } + } + } + ] + ] + , "body": {"type": "var", "name": "install-stage"} + } + } +, "install-with-deps result": + { "vars": + [ "pc-install-dir" + , "targets" + , "prefix" + , "flat-libs" + , "hdrs-only" + , "skip-debug-stage" + ] + , "imports": {"install stage": "install-with-deps stage"} + , "expression": + { "type": "RESULT" + , "artifacts": {"type": "CALL_EXPRESSION", "name": "install stage"} + } + } +} diff --git a/rules/CC/RULES b/rules/CC/RULES new file mode 100644 index 0000000..e5d887a --- /dev/null +++ b/rules/CC/RULES @@ -0,0 +1,950 @@ +{ "defaults": + { "doc": + [ "A rule to provide defaults." + , "All CC targets take their defaults for CC, CXX, flags, etc from" + , "the target [\"CC\", \"defaults\"]. This is probably the only sensible" + , "use of this rule. As targets form a different root, the defaults" + , "can be provided without changing this directory." + ] + , "target_fields": ["base", "toolchain", "deps"] + , "string_fields": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_COMPILE_FLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "AR" + , "PATH" + , "SYSTEM_TOOLS" + ] + , "config_vars": ["ARCH", "HOST_ARCH", "TARGET_ARCH", "DEBUG"] + , "field_doc": + { "base": ["Other targets (using the same rule) to inherit values from."] + , "toolchain": + [ "Optional toolchain directory. A collection of artifacts that provide" + , "the tools CC, CXX, and AR (if needed). Note that only artifacts of" + , "the specified targets are considered (no runfiles etc.). Specifying" + , "this field extends artifacts from \"base\". If the toolchain" + , "supports cross-compilation, it should perform a dispatch on the" + , "configuration variable \"BUILD_ARCH\" to determine for which" + , "architecture to generate code for." + ] + , "deps": + [ "Optional CC libraries any CC library and CC binary implicitly depend" + , "on. Those are typically \"libstdc++\" or \"libc++\" for C++ targets." + , "Specifying this field extends dependencies from \"base\"." + ] + , "CC": ["The C compiler to use"] + , "CXX": ["The C++ compiler to use"] + , "AR": ["The archiver tool to use"] + , "SYSTEM_TOOLS": + [ "List of tools (\"CC\", \"CXX\", or \"AR\") that should be taken from" + , "the system instead of from \"toolchain\" (if specified)." + ] + , "CFLAGS": + [ "Flags for C compilation. Specifying this field overwrites" + , "values from \"base\"." + ] + , "CXXFLAGS": + [ "Flags for C++ compilation. Specifying this field overwrites" + , "values from \"base\"." + ] + , "LDFLAGS": + [ "Linker flags for linking the final CC library. Specifying this field" + , "overwrites values from \"base\"." + ] + , "ADD_COMPILE_FLAGS": + [ "Additional compilation flags for C and C++. Specifying this field" + , "extends values from \"base\" for both, \"CFLAGS\" and \"CXXFLAGS\"." + ] + , "ADD_CFLAGS": + [ "Additional compilation flags specific for C. Specifying this field" + , "extends values from \"base\"." + ] + , "ADD_CXXFLAGS": + [ "Additional compilation flags specific for C++. Specifying this field" + , "extends values from \"base\"." + ] + , "ADD_LDFLAGS": + [ "Additional linker flags for linking the final CC library. Specifying" + , "this field extends values from \"base\"." + ] + , "PATH": + [ "Path for looking up the compilers. Individual paths are joined" + , "with \":\". Specifying this field extends values from \"base\"." + ] + } + , "config_doc": + { "ARCH": + [ "The unqualified architecture. Is taken as a default for \"HOST_ARCH\"" + , "and \"TARGET_ARCH\" if not set." + ] + , "HOST_ARCH": + ["The architecture on which the build actions are carried out."] + , "TARGET_ARCH": ["The architecture for which to build."] + , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + } + , "imports": + { "base-provides": "defaults-base-provides" + , "base-provides-++": "defaults-base-provides-++" + , "base-provides-list": "defaults-base-provides-list" + , "artifacts_list": ["./", "..", "field_artifacts_list"] + , "nub_left": ["", "nub_left"] + , "compile-deps": "compile-deps" + , "compile-args-deps": "compile-args-deps" + , "link-deps": "link-deps" + , "link-args-deps": "link-args-deps" + , "run-libs-deps": "run-libs-deps" + , "run-libs-args-deps": "run-libs-args-deps" + , "cflags-files-deps": "cflags-files-deps" + , "ldflags-files-deps": "ldflags-files-deps" + , "for host": ["transitions", "for host"] + , "debug-deps": "debug-deps" + } + , "config_transitions": + {"toolchain": [{"type": "CALL_EXPRESSION", "name": "for host"}]} + , "expression": + { "type": "let*" + , "bindings": + [ ["CC", {"type": "FIELD", "name": "CC"}] + , ["CXX", {"type": "FIELD", "name": "CXX"}] + , ["CFLAGS", {"type": "FIELD", "name": "CFLAGS"}] + , ["CXXFLAGS", {"type": "FIELD", "name": "CXXFLAGS"}] + , ["LDFLAGS", {"type": "FIELD", "name": "LDFLAGS"}] + , ["AR", {"type": "FIELD", "name": "AR"}] + , ["PATH", {"type": "FIELD", "name": "PATH"}] + , ["provider", "CC"] + , [ "CC" + , { "type": "if" + , "cond": {"type": "var", "name": "CC"} + , "then": {"type": "var", "name": "CC"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "CXX"] + , [ "CXX" + , { "type": "if" + , "cond": {"type": "var", "name": "CXX"} + , "then": {"type": "var", "name": "CXX"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "CFLAGS"] + , [ "CFLAGS" + , { "type": "if" + , "cond": {"type": "var", "name": "CFLAGS"} + , "then": {"type": "var", "name": "CFLAGS"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + , ["provider", "CXXFLAGS"] + , [ "CXXFLAGS" + , { "type": "if" + , "cond": {"type": "var", "name": "CXXFLAGS"} + , "then": {"type": "var", "name": "CXXFLAGS"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + , ["provider", "LDFLAGS"] + , [ "LDFLAGS" + , { "type": "if" + , "cond": {"type": "var", "name": "LDFLAGS"} + , "then": {"type": "var", "name": "LDFLAGS"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + , ["provider", "AR"] + , [ "AR" + , { "type": "if" + , "cond": {"type": "var", "name": "AR"} + , "then": {"type": "var", "name": "AR"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "PATH"] + , [ "PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + , ["provider", "ENV"] + , ["default", {"type": "empty_map"}] + , ["ENV", {"type": "CALL_EXPRESSION", "name": "base-provides"}] + , ["provider", "NON_SYSTEM_TOOLS"] + , ["default", {"type": "empty_map"}] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ [{"type": "CALL_EXPRESSION", "name": "base-provides"}] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "CC"} + , "then": + [ { "type": "singleton_map" + , "key": "CC" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "if" + , "cond": {"type": "FIELD", "name": "CXX"} + , "then": + [ { "type": "singleton_map" + , "key": "CXX" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "if" + , "cond": {"type": "FIELD", "name": "AR"} + , "then": + [ { "type": "singleton_map" + , "key": "AR" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "SYSTEM_TOOLS"} + , "var": "tool" + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "tool"} + , "value": false + } + } + ] + } + } + ] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "toolchain artifacts may not overlap" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": + { "type": "let*" + , "bindings": + [ ["fieldname", "toolchain"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "for host"} + ] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + ] + } + } + ] + , [ "CFLAGS" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "CFLAGS"} + , {"type": "FIELD", "name": "ADD_COMPILE_FLAGS"} + , {"type": "FIELD", "name": "ADD_CFLAGS"} + ] + } + ] + , [ "CXXFLAGS" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "CXXFLAGS"} + , {"type": "FIELD", "name": "ADD_COMPILE_FLAGS"} + , {"type": "FIELD", "name": "ADD_CXXFLAGS"} + ] + } + ] + , [ "LDFLAGS" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "LDFLAGS"} + , {"type": "FIELD", "name": "ADD_LDFLAGS"} + ] + } + ] + , ["deps-fieldnames", ["base", "deps"]] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["link-args", {"type": "CALL_EXPRESSION", "name": "link-args-deps"}] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , ["package", {"type": "env", "vars": ["cflags-files", "ldflags-files"]}] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "compile-deps"} + ] + } + , "else": {"type": "empty_map"} + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "AR" + , "PATH" + , "ENV" + , "TOOLCHAIN" + , "NON_SYSTEM_TOOLS" + , "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + , "debug-srcs" + , "debug-hdrs" + ] + } + } + } + } +, "library": + { "doc": ["A C++ library"] + , "target_fields": + [ "srcs" + , "hdrs" + , "private-hdrs" + , "deps" + , "private-deps" + , "proto" + , "private-proto" + ] + , "string_fields": + [ "name" + , "stage" + , "pure C" + , "defines" + , "private-defines" + , "cflags" + , "private-cflags" + , "ldflags" + , "private-ldflags" + , "soversion" + , "pkg-name" + ] + , "config_fields": ["shared", "object_only"] + , "config_vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "AR" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "DEBUG" + ] + , "implicit": {"defaults": ["defaults"]} + , "field_doc": + { "name": + ["The name of the library (without leading \"lib\" or trailing \".a\")."] + , "srcs": ["The source files of the library."] + , "hdrs": ["Any public header files of the library."] + , "private-hdrs": + [ "Any header files that only need to be present when compiling the" + , "source files, but are not needed for any consumer of the library." + ] + , "stage": + [ "The logical location of all header and source files, as well as the" + , "resulting library file. Individual directory components are joined" + , "with \"/\"." + ] + , "pure C": + [ "If non-empty, compile as C sources rather than C++ sources." + , "In particular, CC is used to compile rather than CXX (or their" + , "respective defaults)." + ] + , "defines": + [ "List of defines set for this target and its consumers." + , "Each list entry will be prepended by \"-D\"." + ] + , "private-defines": + [ "List of defines set for source files local to this target." + , "Each list entry will be prepended by \"-D\"." + ] + , "cflags": + ["List of compile flags set for this target and its consumers."] + , "private-cflags": + ["List of compile flags set for source files local to this target."] + , "ldflags": + [ "Additional linker flags for linking external libraries for this" + , "target and its consumers (not built by this tool, typically system" + , "libraries)." + ] + , "private-ldflags": + [ "Additional linker flags for linking external libraries (not built" + , "by this tool, typically system libraries)." + ] + , "deps": ["Any other libraries this library depends upon."] + , "private-deps": + [ "Any other libraries this library depends upon but does not include" + , "in its public headers." + ] + , "proto": + [ "Any [\"proto\", \"library\"] this target depends upon directly." + , "The creation of C++ bindings for this proto library as well as of" + , "its dependencies will be taken care of (as anonymous targets, so no" + , "duplicate work will be carried out, even if the same proto library" + , "is used at various places)." + ] + , "private-proto": + [ "Any [\"proto\", \"library\"] this target depends upon privately." + , "The creation of C++ bindings for this proto library as well as of" + , "its dependencies will be taken care of (as anonymous targets, so no" + , "duplicate work will be carried out, even if the same proto library" + , "is used at various places)." + ] + , "shared": + [ "If non-empty, produce a shared instead of a static library. Setting" + , "this option is mutually exclusive to the \"object_only\" option." + ] + , "object_only": + [ "If non-empty, produce an object library, resulting in object files" + , "added to the linker line of all depending targets. Setting this option" + , "is mutually exclusive to the \"shared\" option." + ] + , "soversion": + [ "The SOVERSION for shared libraries. Individual version components are" + , "joined with \".\"." + ] + , "pkg-name": + [ "Name to use for pkg-config files. If this field is empty, the field" + , "\"name\" is used instead." + ] + , "defaults": ["The C/C++ toolchain to use"] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used (when compiling pure C code)." + , "If None, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If None, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + [ "The linker flags to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "AR": + [ "The archive tool to used for creating the library" + , "If None, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "ENV": ["The environment for any action generated."] + , "BUILD_POSITION_INDEPENDENT": ["Build with -fPIC."] + , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + } + , "artifacts_doc": + ["The actual library (libname.a) staged in the specified directory"] + , "runfiles_doc": ["The public headers of this library"] + , "provides_doc": + { "compile-deps": + [ "Map of artifacts specifying any additional files that, besides the runfiles," + , "have to be present in compile actions of targets depending on this library" + ] + , "link-deps": + [ "Map of artifacts specifying any additional files that, besides the artifacts," + , "have to be present in a link actions of targets depending on this library" + ] + , "link-args": + [ "List of strings that have to be added to the command line for linking actions" + , "in targets depending on this library" + ] + , "debug-srcs": ["Map of all sources needed for debugging."] + , "debug-hdrs": ["Map of all additional headers needed for debugging."] + } + , "anonymous": + { "proto-deps": + { "target": "proto" + , "provider": "proto" + , "rule_map": + { "library": ["./", "proto", "library"] + , "service library": ["./", "proto", "service library"] + } + } + , "private-proto-deps": + { "target": "private-proto" + , "provider": "proto" + , "rule_map": + { "library": ["./", "proto", "library"] + , "service library": ["./", "proto", "service library"] + } + } + } + , "imports": + { "artifacts": ["./", "..", "field_artifacts"] + , "static result": "lib result" + , "shared result": "shared result" + , "object result": "object result" + , "fPIC transition": ["transitions", "with fPIC"] + } + , "config_transitions": + { "deps": [{"type": "CALL_EXPRESSION", "name": "fPIC transition"}] + , "private-deps": [{"type": "CALL_EXPRESSION", "name": "fPIC transition"}] + , "proto-deps": [{"type": "CALL_EXPRESSION", "name": "fPIC transition"}] + , "private-proto-deps": + [{"type": "CALL_EXPRESSION", "name": "fPIC transition"}] + , "defaults": [{"type": "CALL_EXPRESSION", "name": "fPIC transition"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["name", {"type": "join", "$1": {"type": "FIELD", "name": "name"}}] + , ["pure C", {"type": "FIELD", "name": "pure C"}] + , [ "cflags" + , { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "cflags"} + , { "type": "foreach" + , "var": "def" + , "range": {"type": "FIELD", "name": "defines"} + , "body": + {"type": "join", "$1": ["-D", {"type": "var", "name": "def"}]} + } + ] + } + ] + , [ "private-cflags" + , { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "private-cflags"} + , { "type": "foreach" + , "var": "def" + , "range": {"type": "FIELD", "name": "private-defines"} + , "body": + {"type": "join", "$1": ["-D", {"type": "var", "name": "def"}]} + } + ] + } + ] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "srcs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , [ "hdrs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , [ "private-hdrs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "private-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , ["ldflags", {"type": "FIELD", "name": "ldflags"}] + , ["private-ldflags", {"type": "FIELD", "name": "private-ldflags"}] + , ["soversion", {"type": "FIELD", "name": "soversion"}] + , [ "pkg-name" + , { "type": "if" + , "cond": {"type": "FIELD", "name": "pkg-name"} + , "then": + {"type": "join", "$1": {"type": "FIELD", "name": "pkg-name"}} + , "else": {"type": "var", "name": "name"} + } + ] + , [ "defaults-transition" + , {"type": "CALL_EXPRESSION", "name": "fPIC transition"} + ] + , [ "deps-transition" + , {"type": "CALL_EXPRESSION", "name": "fPIC transition"} + ] + , ["public-fieldnames", ["deps", "proto-deps", "defaults"]] + , [ "private-fieldnames" + , [ "deps" + , "private-deps" + , "proto-deps" + , "private-proto-deps" + , "defaults" + ] + ] + ] + , "body": + { "type": "cond" + , "cond": + [ [ { "type": "and" + , "$1": + [ {"type": "FIELD", "name": "shared"} + , {"type": "FIELD", "name": "object_only"} + ] + } + , { "type": "fail" + , "msg": "Fields \"shared\" and \"object_only\" are mutually exclusive." + } + ] + , [ {"type": "FIELD", "name": "shared"} + , {"type": "CALL_EXPRESSION", "name": "shared result"} + ] + , [ {"type": "FIELD", "name": "object_only"} + , {"type": "CALL_EXPRESSION", "name": "object result"} + ] + ] + , "default": {"type": "CALL_EXPRESSION", "name": "static result"} + } + } + } +, "binary": + { "doc": ["A binary written in C++"] + , "target_fields": ["srcs", "private-hdrs", "private-deps", "private-proto"] + , "string_fields": + [ "name" + , "stage" + , "pure C" + , "private-defines" + , "private-cflags" + , "private-ldflags" + ] + , "config_vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "DEBUG" + ] + , "implicit": {"defaults": ["defaults"]} + , "field_doc": + { "name": ["The name of the binary"] + , "srcs": ["The source files of the library."] + , "private-hdrs": + [ "Any header files that need to be present when compiling the" + , "source files." + ] + , "stage": + [ "The logical location of all header and source files, as well as the" + , "resulting binary file. Individual directory components are joined" + , "with \"/\"." + ] + , "pure C": + [ "If non-empty, compile as C sources rathter than C++ sources." + , "In particular, CC is used to compile rather than CXX" + ] + , "private-defines": + [ "List of defines set for source files local to this target." + , "Each list entry will be prepended by \"-D\"." + ] + , "private-cflags": + ["List of compile flags set for source files local to this target."] + , "private-ldflags": + ["Additional linker flags for linking external libraries."] + , "private-deps": ["Any other libraries this binary depends upon."] + , "private-proto": + [ "Any [\"proto\", \"library\"] this target depends upon directly." + , "The creation of C++ bindings for this proto library as well as of" + , "is dependencies will be taken care of (as anonymous targets, so no" + , "duplicate work will be carried out, even if the same proto library" + , "is used at various places)." + ] + , "defaults": ["The C/C++ toolchain to use"] + } + , "config_doc": + { "CC": + ["The name of the C compiler to be used (when compiling pure C code)"] + , "CXX": ["The name of the C++ compiler to be used."] + , "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" + ] + , "LDFLAGS": + [ "The linker flags do 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" + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones" + , "taken from the [\"CC\", \"defaults\"] target" + ] + , "ENV": ["The environment for any action generated."] + , "BUILD_POSITION_INDEPENDENT": ["Build with -fPIC."] + , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + } + , "artifacts_doc": ["The final binary, staged to the given directory"] + , "runfiles_doc": ["None"] + , "provides_doc": + { "debug-srcs": ["Map of all sources needed for debugging."] + , "debug-hdrs": ["Map of all additional headers needed for debugging."] + } + , "anonymous": + { "private-proto-deps": + { "target": "private-proto" + , "provider": "proto" + , "rule_map": + { "library": ["./", "proto", "library"] + , "service library": ["./", "proto", "service library"] + } + } + } + , "imports": + {"artifacts": ["./", "..", "field_artifacts"], "bin result": "bin result"} + , "expression": + { "type": "let*" + , "bindings": + [ [ "name" + , { "type": "assert_non_empty" + , "msg": "A non-empty name has to be provided for binaries" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["pure C", {"type": "FIELD", "name": "pure C"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "srcs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , [ "private-hdrs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "private-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , [ "private-cflags" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "def" + , "range": {"type": "FIELD", "name": "private-defines"} + , "body": + {"type": "join", "$1": ["-D", {"type": "var", "name": "def"}]} + } + , {"type": "FIELD", "name": "private-cflags"} + ] + } + ] + , ["private-ldflags", {"type": "FIELD", "name": "private-ldflags"}] + , [ "private-fieldnames" + , ["private-deps", "private-proto-deps", "defaults"] + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "bin result"} + } + } +, "install-with-deps": + { "doc": + [ "Install target's artifacts with transitive dependencies. Depending on" + , "the target, artifacts and dependencies will be installed to" + , "subdirectories \"bin\", \"include\", and \"lib\". For library targets," + , "a pkg-config file is generated and provided in \"lib/pkgconfig\"." + , "In debug mode, depending on the target, additional artifacts needed for" + , "local debugging are gathered and installed, depending on target, to" + , "\"work\" and \"include\"." + ] + , "config_vars": ["PREFIX"] + , "target_fields": ["targets"] + , "string_fields": ["flat-libs", "prefix", "hdrs-only", "skip-debug-stage"] + , "imports": {"install result": "install-with-deps result"} + , "field_doc": + { "targets": ["Targets to install artifacts from."] + , "flat-libs": + [ "Install libraries flat to the \"lib\" subdirectory. Be aware that" + , "conflicts may occur if any of the (transitive) libraries happen to" + , "have the same base name." + ] + , "prefix": + [ "The prefix used for pkg-config files. The path will be made absolute" + , "and individual directory components are joined with \"/\". If no" + , "prefix is specified, the value from the config variable \"PREFIX\" is" + , "taken, with the default value being \"/\"." + ] + , "hdrs-only": ["Only collect headers from deps (without subdirectory)."] + , "skip-debug-stage": + [ "If in debug mode, skip installing additional artifacts gathered if no" + , "local debugging is needed, but debug targets are nonetheless desired." + ] + } + , "config_doc": + { "PREFIX": + [ "The absolute path that is used as prefix inside generated pkg-config" + , "files. The default value for this variable is \"/\". This variable" + , "is ignored if the field \"prefix\" is set." + ] + } + , "artifacts_doc": + ["Installed artifacts in subdirectories (\"bin\"/\"include\"/\"lib\")."] + , "expression": + { "type": "let*" + , "bindings": + [ ["pc-install-dir", "lib/pkgconfig"] + , ["targets", {"type": "FIELD", "name": "targets"}] + , [ "prefix" + , { "type": "if" + , "cond": {"type": "FIELD", "name": "prefix"} + , "then": + { "type": "join" + , "separator": "/" + , "$1": + {"type": "++", "$1": [[""], {"type": "FIELD", "name": "prefix"}]} + } + , "else": {"type": "var", "name": "PREFIX", "default": "/"} + } + ] + , ["flat-libs", {"type": "FIELD", "name": "flat-libs"}] + , ["hdrs-only", {"type": "FIELD", "name": "hdrs-only"}] + , ["skip-debug-stage", {"type": "FIELD", "name": "skip-debug-stage"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "install result"} + } + } +} diff --git a/rules/CC/TARGETS b/rules/CC/TARGETS new file mode 100644 index 0000000..8860e8b --- /dev/null +++ b/rules/CC/TARGETS @@ -0,0 +1,11 @@ +{ "defaults": + { "type": ["CC", "defaults"] + , "CC": ["cc"] + , "CXX": ["c++"] + , "CFLAGS": [] + , "CXXFLAGS": [] + , "LDFLAGS": [] + , "AR": ["ar"] + , "PATH": ["/bin", "/usr/bin"] + } +} diff --git a/rules/CC/auto/EXPRESSIONS b/rules/CC/auto/EXPRESSIONS new file mode 100644 index 0000000..9520975 --- /dev/null +++ b/rules/CC/auto/EXPRESSIONS @@ -0,0 +1,12 @@ +{ "last_list_entry": + { "vars": ["list"] + , "expression": + {"type": "[]", "index": -1, "list": {"type": "var", "name": "list"}} + } +, "first_list_entry": + { "vars": ["list"] + , "imports": {"last": "last_list_entry"} + , "expression": + {"type": "[]", "index": 0, "list": {"type": "var", "name": "list"}} + } +} diff --git a/rules/CC/auto/RULES b/rules/CC/auto/RULES new file mode 100644 index 0000000..debae9c --- /dev/null +++ b/rules/CC/auto/RULES @@ -0,0 +1,1228 @@ +{ "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": + { "first": "first_list_entry" + , "last": "last_list_entry" + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'defines' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'defines1' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'defines01' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_cfile' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_cxxfile' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_ctype' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["type", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_cxxtype' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["type", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_csymbol' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["list", {"type": "CALL_EXPRESSION", "name": "last"}] + , ["sym", {"type": "CALL_EXPRESSION", "name": "first"}] + , ["hdrs", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'have_cxxsymbol' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["list", {"type": "CALL_EXPRESSION", "name": "last"}] + , ["sym", {"type": "CALL_EXPRESSION", "name": "first"}] + , ["hdrs", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'size_ctype' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["list", {"type": "CALL_EXPRESSION", "name": "last"}] + , ["type", {"type": "CALL_EXPRESSION", "name": "first"}] + , ["sizes", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , [ "def" + , { "type": "assert_non_empty" + , "msg": "Define name in 'size_cxxtype' may not be empty" + , "$1": {"type": "CALL_EXPRESSION", "name": "first"} + } + ] + , ["list", {"type": "CALL_EXPRESSION", "name": "last"}] + , ["type", {"type": "CALL_EXPRESSION", "name": "first"}] + , ["sizes", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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": + { "first": "first_list_entry" + , "last": "last_list_entry" + , "stage_singleton_field": ["", "stage_singleton_field"] + } + , "implicit": {"runner": ["runner"]} + , "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": + [ ["list", {"type": "var", "name": "pair"}] + , ["key", {"type": "CALL_EXPRESSION", "name": "first"}] + , ["val", {"type": "CALL_EXPRESSION", "name": "last"}] + ] + , "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"} + } + ] + , [ "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"} + ] + , "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..47c2f94 --- /dev/null +++ b/rules/CC/auto/runner @@ -0,0 +1,76 @@ +#!/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 re import sub, match + +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. +for k, v in param.items(): + if isinstance(v, bool): + param[k] = "" + +with open(input_file) as i: + with open("out", "w") as o: + for line in i.readlines(): + if x := re.search( + r"#(.*)(" + magic_string + r" )([ \t]*)([a-zA-Z0-9_]+)", + line): + # get the VAR + key = x.groups()[-1] + if key in param: + line = sub( + f"{x.group()[1:]}", + f"{x.groups()[0]}define {x.groups()[2]}{key} {param[key]}", + line, + ) + else: + line = f"/* #undef {x.groups()[-1]} */\n" + if x := re.search( + r"#(.*)(" + magic_string + "01 )([ \t]*)([a-zA-Z0-9_]+)", + line): + # get the VAR + key = x.groups()[-1] + line = sub( + f"{x.group()[1:]}", + f"{x.groups()[0]}define {x.groups()[2]}{key} " + + str(1 if key in param else 0), + line, + ) + if match("#[ \t]*define", line): + if x := re.search(r"@([a-zA-Z0-9-_]+)@", line): + key = x.groups()[0] + line = sub(x.group(), param.get(key, ""), line) + if not at_only: + if x := re.search(r"\${([a-zA-Z0-9-_]+)}", line): + key = x.groups()[0] + line = sub(r"\${" + key + r"}", param.get(key, ""), + line) + + print(line, end="", file=o) diff --git a/rules/CC/foreign/EXPRESSIONS b/rules/CC/foreign/EXPRESSIONS new file mode 100644 index 0000000..2988b32 --- /dev/null +++ b/rules/CC/foreign/EXPRESSIONS @@ -0,0 +1,123 @@ +{ "default-MAKE": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "foreign-defaults"] + , ["provider", "MAKE"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-CMAKE": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "foreign-defaults"] + , ["provider", "CMAKE"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-ENV": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "foreign-defaults"] + , ["provider", "ENV"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-PATH": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "foreign-defaults"] + , ["provider", "PATH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-TOOLCHAIN": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "foreign-defaults"] + , ["provider", "TOOLCHAIN"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-NON_SYSTEM_TOOLS": + { "vars": ["defaults-transition"] + , "expression": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": "foreign-defaults"} + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": "NON_SYSTEM_TOOLS" + , "transition": + { "type": "var" + , "name": "defaults-transition" + , "default": {"type": "empty_map"} + } + , "default": {"type": "empty_map"} + } + } + } + } +, "strip-prefix": + { "doc": + [ "Returns list of artifact maps (each map contains a single artifact)" + , "with the given prefix being stripped from their path." + ] + , "vars": ["artifacts", "paths", "prefix"] + , "vars_doc": + { "artifacts": ["A single map containing all artifacts."] + , "paths": ["List of (unprefixed) artifacts paths to consider."] + , "prefix": ["Prefix to strip from the artifact's path."] + } + , "expression": + { "type": "foreach" + , "var": "path" + , "range": {"type": "var", "name": "paths"} + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "path"} + , "value": + { "type": "lookup" + , "key": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "prefix"} + , {"type": "var", "name": "path"} + ] + } + , "map": {"type": "var", "name": "artifacts"} + } + } + } + } +} diff --git a/rules/CC/foreign/RULES b/rules/CC/foreign/RULES new file mode 100644 index 0000000..935d477 --- /dev/null +++ b/rules/CC/foreign/RULES @@ -0,0 +1,166 @@ +{ "defaults": + { "doc": + [ "A rule to provide defaults for foreign rules." + , "All foreign rules take their defaults for MAKE, CMAKE, etc from" + , "the target [\"CC/foreign\", \"defaults\"]." + ] + , "target_fields": ["base", "toolchain"] + , "string_fields": ["MAKE", "CMAKE", "PATH", "SYSTEM_TOOLS"] + , "field_doc": + { "base": ["Other targets (using the same rule) to inherit values from."] + , "toolchain": + [ "Optional toolchain directory. A collection of artifacts that provide" + , "the tools MAKE, CMAKE. Note that only artifacts of" + , "the specified targets are considered (no runfiles etc.). Specifying" + , "this field extends artifacts from \"base\"." + ] + , "MAKE": ["The make binary to use"] + , "CMAKE": ["The cmake binary to use"] + , "SYSTEM_TOOLS": + [ "List of tools (\"MAKE\", \"CMAKE\") that should be taken from" + , "the system instead of from \"toolchain\" (if specified)." + ] + , "PATH": + [ "Path for looking up the tools. Individual paths are joined with" + , "with \":\". Specifying this field extends values from \"base\"." + ] + } + , "config_vars": ["ARCH", "HOST_ARCH"] + , "imports": + { "base-provides": ["./", "..", "defaults-base-provides"] + , "base-provides-++": ["./", "..", "defaults-base-provides-++"] + , "base-provides-list": ["./", "..", "defaults-base-provides-list"] + , "artifacts_list": ["./", "../..", "field_artifacts_list"] + , "nub_left": ["", "nub_left"] + , "for host": ["transitions", "for host"] + } + , "config_transitions": + {"toolchain": [{"type": "CALL_EXPRESSION", "name": "for host"}]} + , "expression": + { "type": "let*" + , "bindings": + [ ["MAKE", {"type": "FIELD", "name": "MAKE"}] + , ["CMAKE", {"type": "FIELD", "name": "CMAKE"}] + , ["PATH", {"type": "FIELD", "name": "PATH"}] + , ["provider", "MAKE"] + , [ "MAKE" + , { "type": "if" + , "cond": {"type": "var", "name": "MAKE"} + , "then": {"type": "var", "name": "MAKE"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "CMAKE"] + , [ "CMAKE" + , { "type": "if" + , "cond": {"type": "var", "name": "CMAKE"} + , "then": {"type": "var", "name": "CMAKE"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "PATH"] + , [ "PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + , ["provider", "ENV"] + , ["default", {"type": "empty_map"}] + , ["ENV", {"type": "CALL_EXPRESSION", "name": "base-provides"}] + , ["provider", "NON_SYSTEM_TOOLS"] + , ["default", {"type": "empty_map"}] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , { "type": "if" + , "cond": {"type": "FIELD", "name": "MAKE"} + , "then": + [ { "type": "singleton_map" + , "key": "MAKE" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "if" + , "cond": {"type": "FIELD", "name": "CMAKE"} + , "then": + [ { "type": "singleton_map" + , "key": "CMAKE" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "SYSTEM_TOOLS"} + , "var": "tool" + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "tool"} + , "value": false + } + } + ] + } + } + ] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "toolchain artifacts may not overlap" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": + { "type": "let*" + , "bindings": + [ ["fieldname", "toolchain"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "for host"} + ] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + ] + } + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": + ["MAKE", "CMAKE", "PATH", "ENV", "TOOLCHAIN", "NON_SYSTEM_TOOLS"] + } + } + } + } +} diff --git a/rules/CC/foreign/TARGETS b/rules/CC/foreign/TARGETS new file mode 100644 index 0000000..5fbb6a9 --- /dev/null +++ b/rules/CC/foreign/TARGETS @@ -0,0 +1,7 @@ +{ "defaults": + { "type": ["CC/foreign", "defaults"] + , "MAKE": ["make"] + , "CMAKE": ["cmake"] + , "PATH": ["/bin", "/usr/bin"] + } +} diff --git a/rules/CC/foreign/cmake/EXPRESSIONS b/rules/CC/foreign/cmake/EXPRESSIONS new file mode 100644 index 0000000..bf2385e --- /dev/null +++ b/rules/CC/foreign/cmake/EXPRESSIONS @@ -0,0 +1,494 @@ +{ "cmake-build": + { "vars": + [ "ARCH" + , "HOST_ARCH" + , "source_dir" + , "cmake_subdir" + , "localbase_dir" + , "cmake_options" + , "cmake_defines" + , "cmake_jobs" + , "cmake_targets" + , "pre_cmds" + , "post_cmds" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "BUILD_POSITION_INDEPENDENT" + , "defaults-transition" + , "expand_exec" + , "resolve_symlinks" + ] + , "imports": + { "artifacts": ["", "field_artifacts"] + , "nub_left": ["", "nub_left"] + , "flags-cc": ["CC", "flags-cc"] + , "flags-cxx": ["CC", "flags-cxx"] + , "compiler-cc": ["CC", "compiler-cc"] + , "compiler-cxx": ["CC", "compiler-cxx"] + , "default-LDFLAGS": ["CC", "default-LDFLAGS"] + , "default-AR": ["CC", "default-AR"] + , "default-ENV": ["CC", "default-ENV"] + , "default-PATH": ["CC", "default-PATH"] + , "default-TOOLCHAIN": ["CC", "default-TOOLCHAIN"] + , "default-NON_SYSTEM_TOOLS": ["CC", "default-NON_SYSTEM_TOOLS"] + , "foreign-MAKE": ["CC/foreign", "default-MAKE"] + , "foreign-CMAKE": ["CC/foreign", "default-CMAKE"] + , "foreign-ENV": ["CC/foreign", "default-ENV"] + , "foreign-PATH": ["CC/foreign", "default-PATH"] + , "foreign-TOOLCHAIN": ["CC/foreign", "default-TOOLCHAIN"] + , "foreign-NON_SYSTEM_TOOLS": ["CC/foreign", "default-NON_SYSTEM_TOOLS"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + , "sh-PATH": ["shell", "PATH"] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "Toolchain trees may not overlap" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-TOOLCHAIN"} + , {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"} + , {"type": "var", "name": "shell TOOLCHAIN"} + ] + } + ] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-NON_SYSTEM_TOOLS"} + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + } + ] + , [ "CMAKE_FLAGS" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "define" + , "range": {"type": "var", "name": "cmake_defines"} + , "body": + { "type": "join" + , "$1": ["-D", {"type": "var", "name": "define"}] + } + } + , {"type": "var", "name": "cmake_options"} + , { "type": "if" + , "cond": {"type": "var", "name": "BUILD_POSITION_INDEPENDENT"} + , "then": ["-DCMAKE_POSITION_INDEPENDENT_CODE=ON"] + } + , ["-DCMAKE_INSTALL_RPATH=$ORIGIN;$ORIGIN/../lib"] + ] + } + ] + , ["BUILD_POSITION_INDEPENDENT", null] + , [ "MAKE" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "foreign-MAKE"} + ] + } + } + ] + , [ "CMAKE" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CMAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "foreign-CMAKE"} + ] + } + } + ] + , ["CC", {"type": "CALL_EXPRESSION", "name": "compiler-cc"}] + , ["CXX", {"type": "CALL_EXPRESSION", "name": "compiler-cxx"}] + , [ "CFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cc"} + } + ] + , [ "CXXFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cxx"} + } + ] + , [ "LDFLAGS" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ { "type": "var" + , "name": "LDFLAGS" + , "default": + {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + } + , {"type": "var", "name": "ldflags", "default": []} + ] + } + } + ] + , [ "AR" + , { "type": "var" + , "name": "AR" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-AR"} + ] + } + } + } + ] + , [ "sh-PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh-PATH"} + } + } + ] + , [ "sh-ENV" + , { "type": "if" + , "cond": {"type": "var", "name": "sh-PATH"} + , "then": + { "type": "singleton_map" + , "key": "PATH" + , "value": {"type": "var", "name": "sh-PATH"} + } + , "else": {"type": "empty_map"} + } + ] + , [ "PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "let*" + , "bindings": + [ [ "list" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-PATH"} + , {"type": "CALL_EXPRESSION", "name": "default-PATH"} + ] + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + } + ] + , [ "ENV" + , { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "CC" + , "CXX" + , "CXXFLAGS" + , "CFLAGS" + , "LDFLAGS" + , "AR" + , "MAKE" + , "CMAKE" + ] + } + , {"type": "var", "name": "sh-ENV"} + , {"type": "CALL_EXPRESSION", "name": "default-ENV"} + , {"type": "CALL_EXPRESSION", "name": "foreign-ENV"} + , {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + ] + } + ] + , [ "CMAKE_JOBS" + , { "type": "if" + , "cond": {"type": "var", "name": "cmake_jobs"} + , "then": + [ { "type": "join" + , "$1": + [ "CMAKE_BUILD_PARALLEL_LEVEL=" + , { "type": "join_cmd" + , "$1": {"type": "var", "name": "cmake_jobs"} + } + ] + } + ] + } + ] + , [ "CMAKE_SUBDIR" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "var", "name": "cmake_subdir", "default": []} + } + ] + , [ "cmake_targets" + , { "type": "if" + , "cond": {"type": "var", "name": "cmake_targets"} + , "then": {"type": "var", "name": "cmake_targets"} + , "else": ["install"] + } + ] + , [ "script" + , { "type": "singleton_map" + , "key": "run_cmake.sh" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + { "type": "++" + , "$1": + [ [ "set -eu" + , "mkdir scratch" + , "readonly ROOT=\"$(pwd)\"" + , "export TMPDIR=\"$(pwd)/scratch\"" + , "export TOOLCHAIN=\"$(pwd)/toolchain\"" + , "export LOCALBASE=\"$(pwd)/localbase\"" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CC" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CC=$(pwd)/${CC}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CXX" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CXX=$(pwd)/${CXX}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export AR=$(pwd)/${AR}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export MAKE=$(pwd)/${MAKE}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CMAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CMAKE=$(pwd)/${CMAKE}" + , "else": "" + } + , { "type": "join" + , "$1": + [ "export PATH=\"$(./expand_exec TOOLCHAIN -- echo " + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "PATH"}] + } + , ")${PATH:+:}${PATH}\"" + ] + } + , { "type": "join" + , "$1": + [ "export PATH=\"$(./expand_exec TOOLCHAIN -- echo " + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "PATH"}] + } + , ")${PATH:+:}${PATH}\"" + ] + } + ] + , { "type": "if" + , "cond": {"type": "var", "name": "pre_cmds"} + , "then": + { "type": "++" + , "$1": + [ ["(", "set --", "cd ./source"] + , {"type": "var", "name": "pre_cmds"} + , [")"] + ] + } + } + , [ "readonly CMAKE_SUBDIR=\"$1\"" + , "readonly CMAKE_AR=$(command -v $2)" + , "shift 2" + ] + , [ { "type": "join" + , "separator": " " + , "$1": + [ "${ROOT}/expand_exec TMPDIR LOCALBASE CC CXX CFLAGS CXXFLAGS LDFLAGS AR" + , "--" + , "${CMAKE} -S\"source/${CMAKE_SUBDIR}\" -Bbuild" + , "-DCMAKE_MAKE_PROGRAM=${MAKE}" + , "-DCMAKE_AR=${CMAKE_AR}" + , "-DCMAKE_INSTALL_PREFIX=./install" + , "-DCMAKE_PREFIX_PATH=\"$(pwd)/localbase\"" + , "-DPKG_CONFIG_ARGN=--define-prefix" + , "--no-warn-unused-cli" + , "\"$@\"" + , ">configure.log 2>&1 || (cat configure.log && exit 1)" + ] + } + ] + , { "type": "foreach" + , "range": {"type": "var", "name": "cmake_targets"} + , "var": "target" + , "body": + { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "CMAKE_JOBS"} + , [ "${ROOT}/expand_exec TMPDIR LOCALBASE CC CXX CFLAGS CXXFLAGS LDFLAGS AR" + , "--" + , "${CMAKE} --build build --target" + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "target"}] + } + , ">>build.log 2>&1 || (cat configure.log build.log && exit 1)" + ] + ] + } + } + } + , { "type": "if" + , "cond": {"type": "var", "name": "resolve_symlinks"} + , "then": + [ "mv install install_with_symlinks" + , "cp -rL install_with_symlinks install >copy.log 2>&1 || (echo 'ERROR: symlink resolve failed with:' && cat copy.log && exit 1)" + ] + } + , { "type": "if" + , "cond": {"type": "var", "name": "post_cmds"} + , "then": + { "type": "++" + , "$1": + [ [ "(" + , "set --" + , "readonly CMAKE_SOURCE_DIR=\"$(pwd)/source\"" + , "readonly CMAKE_BINARY_DIR=\"$(pwd)/build\"" + , "cd ./install" + ] + , {"type": "var", "name": "post_cmds"} + , [")"] + ] + } + } + ] + } + } + } + } + ] + ] + , "body": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "source_dir"} + , {"type": "var", "name": "expand_exec"} + , { "type": "var" + , "name": "localbase_dir" + , "default": {"type": "empty_map"} + } + , {"type": "var", "name": "script"} + ] + } + , "cmd": + { "type": "++" + , "$1": + [ [ {"type": "var", "name": "sh"} + , "run_cmake.sh" + , {"type": "var", "name": "CMAKE_SUBDIR"} + , {"type": "var", "name": "AR"} + ] + , {"type": "var", "name": "CMAKE_FLAGS"} + ] + } + , "out_dirs": ["install"] + , "env": {"type": "var", "name": "ENV"} + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 10.0} + } + } + } +} diff --git a/rules/CC/foreign/cmake/RULES b/rules/CC/foreign/cmake/RULES new file mode 100644 index 0000000..b7fd406 --- /dev/null +++ b/rules/CC/foreign/cmake/RULES @@ -0,0 +1,764 @@ +{ "data": + { "doc": + [ "Data produced by CMake configure, build, and install." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"CC\", \"CXX\", \"CFLAGS\", \"CXXFLAGS\", \"LDFLAGS\"," + , "and \"AR\". \"LOCALBASE\" contains the path to the installed artifacts" + , "from \"deps\"." + ] + , "target_fields": ["project"] + , "string_fields": + [ "subdir" + , "options" + , "defines" + , "targets" + , "jobs" + , "pre_cmds" + , "post_cmds" + , "out_files" + , "out_dirs" + , "resolve_symlinks" + ] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + ["The CMake project directory. It should contain a single tree artifact"] + , "subdir": + [ "The subdirectory that contains the entry CMakeLists.txt. Individual" + , "directory components are joined with \"/\"." + ] + , "options": + [ "CMake options for the configuration phase." + , "(e.g., [\"-GNinja\", \"-Ax64\"])" + ] + , "defines": + [ "CMake defines for the configuration phase." + , "(e.g., [\"CMAKE_BUILD_TYPE=Release\"])" + ] + , "targets": + [ "The CMake targets to build in the specified order" + , "(default: [\"install\"])." + ] + , "jobs": + [ "Number of jobs to run simultaneously. If omitted, CMake's default" + , "number is used." + ] + , "pre_cmds": + [ "List of commands executed in the project directory before calling" + , "CMake. Useful for renaming files or directories. Note that data" + , "between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\" which is uniquely reserved for this action." + ] + , "post_cmds": + [ "List of commands executed in the install directory after successful" + , "installation but before the output files are collected. Useful for" + , "renaming files or directories. Note that data between \"pre_cmds\" and" + , "\"post_cmds\" can be exchanged via \"$TMPDIR\", which is uniquely" + , "reserved for this action. The CMake source and build directory can be" + , "accessed via \"$CMAKE_SOURCE_DIR\" and \"$CMAKE_BINARY_DIR\"," + , "respectively." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after the install, before \"post_cmds\" are run." + ] + , "out_files": + [ "Paths to the produced output files. The paths are considered relative" + , "to the install directory." + , "Note that \"out_files\" and \"out_dirs\" may not overlap." + ] + , "out_dirs": + [ "Paths to the produced output directories. The paths are considered" + , "relative to the install directory." + , "Note that \"out_files\" and \"out_dirs\" may not overlap." + ] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + [ "The linker flags to be used instead of the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "stage_field": ["", "stage_singleton_field"] + , "cmake-build": "cmake-build" + , "strip-prefix": ["./", "..", "strip-prefix"] + , "for host": ["transitions", "for host"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["install_prefix", "install"] + , [ "source_dir" + , { "type": "let*" + , "bindings": [["fieldname", "project"], ["location", "source"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "installed_out_files" + , { "type": "foreach" + , "var": "file_path" + , "range": {"type": "FIELD", "name": "out_files"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "file_path"} + ] + } + } + ] + , [ "installed_out_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "FIELD", "name": "out_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , ["cmake_subdir", {"type": "FIELD", "name": "subdir"}] + , ["cmake_options", {"type": "FIELD", "name": "options"}] + , ["cmake_defines", {"type": "FIELD", "name": "defines"}] + , ["cmake_targets", {"type": "FIELD", "name": "targets"}] + , ["cmake_jobs", {"type": "FIELD", "name": "jobs"}] + , ["pre_cmds", {"type": "FIELD", "name": "pre_cmds"}] + , ["post_cmds", {"type": "FIELD", "name": "post_cmds"}] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["defaults-transition", {"type": "empty_map"}] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "full_install_dir" + , {"type": "CALL_EXPRESSION", "name": "cmake-build"} + ] + , ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "install_dir" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "shell TOOLCHAIN"} + , {"type": "var", "name": "full_install_dir"} + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "-c", ":"] + , "outs": {"type": "var", "name": "installed_out_files"} + , "out_dirs": {"type": "var", "name": "installed_out_dirs"} + } + ] + , [ "out_files" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_files"}] + , ["prefix", {"type": "var", "name": "install_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "out_dirs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_dirs"}] + , ["prefix", {"type": "var", "name": "install_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": + { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "out_files"} + , {"type": "var", "name": "out_dirs"} + ] + } + } + } + } + } +, "library": + { "doc": + [ "Library produced by CMake configure, build, and install." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"CC\", \"CXX\", \"CFLAGS\", \"CXXFLAGS\", \"LDFLAGS\"," + , "and \"AR\". \"LOCALBASE\" contains the path to the installed artifacts" + , "from \"deps\"." + ] + , "target_fields": ["project", "deps"] + , "string_fields": + [ "subdir" + , "name" + , "version" + , "stage" + , "options" + , "defines" + , "jobs" + , "pre_cmds" + , "post_cmds" + , "out_hdrs" + , "out_hdr_dirs" + , "out_libs" + , "cflags" + , "ldflags" + , "pkg-config" + , "hdr_prefix" + , "lib_prefix" + , "pc_prefix" + , "resolve_symlinks" + ] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "config_reader": [["CC", "prebuilt/read_pkgconfig.py"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + ["The CMake project directory. It should contain a single tree artifact"] + , "subdir": + [ "The subdirectory that contains the entry CMakeLists.txt. Individual" + , "directory components are joined with \"/\"." + ] + , "name": + [ "The name of the library (without leading \"lib\" or trailing file name" + , "extension), also used as name for pkg-config files." + ] + , "version": + [ "The library version, used for pkg-config files. Individual version" + , "components are joined with \".\"." + ] + , "options": + [ "CMake options for the configuration phase" + , "(e.g., [\"-GNinja\", \"-Ax64\"]). Variables can be accessed via" + , "\"$(<varname>)\", e.g., \"$(TMPDIR)\" for variable \"$TMPDIR\"." + ] + , "defines": + [ "CMake defines for the configuration phase" + , "(e.g., [\"CMAKE_BUILD_TYPE=Release\"]). Variables can be accessed via" + , "\"$(<varname>)\", e.g., \"$(TMPDIR)\" for variable \"$TMPDIR\"." + ] + , "jobs": + [ "Number of jobs to run simultaneously. If omitted, CMake's default" + , "number is used." + ] + , "pre_cmds": + [ "List of commands executed in the project directory before calling" + , "CMake. Useful for renaming files or directories. Note that data" + , "between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\" which is uniquely reserved for this action." + ] + , "post_cmds": + [ "List of commands executed in the install directory after successful" + , "installation but before the output files are collected. Useful for" + , "renaming files or directories (e.g., in case of SONAME mismatch). Note" + , "that data between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\", which is uniquely reserved for this action. The CMake" + , "source and build directory can be accessed via \"$CMAKE_SOURCE_DIR\"" + , "and \"$CMAKE_BINARY_DIR\", respectively." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after the install, before \"post_cmds\" are run." + ] + , "out_hdrs": + [ "Paths to produced public header files. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_hdr_dirs": + [ "Paths to produced public header directories. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_libs": + [ "Paths to produced library files. The path is considered relative" + , "to the library directory, which be set via \"lib_prefix\"." + , "Order matters in the case of one library depending on another." + ] + , "cflags": + ["List of compile flags set for this target and its consumers."] + , "ldflags": + [ "Additional linker flags that are required for the consumer of the" + , "produced libraries." + ] + , "stage": + [ "The logical location of the public headers and library files." + , "Individual directory components are joined with \"/\"." + ] + , "deps": ["Public dependency on other CC libraries."] + , "pkg-config": + [ "Pkg-config file for optional infer of public cflags and ldflags. If" + , "multiple files are specified (e.g., one depends on the other), the" + , "first one is used as entry. Note that if this field is non-empty the" + , "tool \"pkg-config\" must be available in \"PATH\", which is taken" + , "from [\"CC\", \"defaults\"] or the \"ENV\" variable." + ] + , "hdr_prefix": + [ "Prefix where headers will be installed by CMake. Individual directory" + , "components are joined with \"/\". Defaults to \"include\" if not set." + ] + , "lib_prefix": + [ "Prefix where libraries will be installed by CMake. Individual" + , "directory components are joined with \"/\". Defaults to \"lib\" if" + , "not set." + ] + , "pc_prefix": + [ "Prefix where pkg-config files will be installed by CMake. Individual" + , "directory components are joined with \"/\". Defaults to" + , "\"lib/pkgconfig\" if not set." + ] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + ["Global ld flags, for common link args,such as -Wl,-z,noexecstack"] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library" + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "stage_field": ["", "stage_singleton_field"] + , "cmake-build": "cmake-build" + , "strip-prefix": ["./", "..", "strip-prefix"] + , "prebuilt result": ["CC/prebuilt", "prebuilt result"] + , "install-deps": ["CC", "install-with-deps stage"] + , "for host": ["transitions", "for host"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "hdr_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "hdr_prefix"} + , "then": {"type": "FIELD", "name": "hdr_prefix"} + , "else": ["include"] + } + ] + } + } + ] + , [ "lib_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "lib_prefix"} + , "then": {"type": "FIELD", "name": "lib_prefix"} + , "else": ["lib"] + } + ] + } + } + ] + , [ "pc_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "pc_prefix"} + , "then": {"type": "FIELD", "name": "pc_prefix"} + , "else": ["lib", "pkgconfig"] + } + ] + } + } + ] + , [ "source_dir" + , { "type": "let*" + , "bindings": [["fieldname", "project"], ["location", "source"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "localbase_dir" + , { "type": "to_subdir" + , "subdir": "localbase" + , "msg": "dependency installation files may not overlap" + , "$1": + { "type": "let*" + , "bindings": + [ ["pc-install-dir", "lib/pkgconfig"] + , ["targets", {"type": "FIELD", "name": "deps"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "install-deps"} + } + } + ] + , [ "installed_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "FIELD", "name": "out_hdr_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , [ "installed_files" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "lib_path" + , "range": {"type": "FIELD", "name": "out_libs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "lib_prefix"} + , {"type": "var", "name": "lib_path"} + ] + } + } + , { "type": "foreach" + , "var": "hdr_path" + , "range": {"type": "FIELD", "name": "out_hdrs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "hdr_path"} + ] + } + } + , { "type": "foreach" + , "var": "pc_path" + , "range": {"type": "FIELD", "name": "pkg-config"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "pc_prefix"} + , {"type": "var", "name": "pc_path"} + ] + } + } + ] + } + ] + , ["cmake_subdir", {"type": "FIELD", "name": "subdir"}] + , ["cmake_options", {"type": "FIELD", "name": "options"}] + , ["cmake_defines", {"type": "FIELD", "name": "defines"}] + , ["cmake_jobs", {"type": "FIELD", "name": "jobs"}] + , ["pre_cmds", {"type": "FIELD", "name": "pre_cmds"}] + , ["post_cmds", {"type": "FIELD", "name": "post_cmds"}] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["defaults-transition", {"type": "empty_map"}] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "full_install_dir" + , {"type": "CALL_EXPRESSION", "name": "cmake-build"} + ] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "install_dir" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "shell TOOLCHAIN"} + , {"type": "var", "name": "full_install_dir"} + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "-c", ":"] + , "outs": {"type": "var", "name": "installed_files"} + , "out_dirs": {"type": "var", "name": "installed_dirs"} + } + ] + , [ "hdrs" + , { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdrs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdr_dirs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + } + ] + , [ "libs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_libs"}] + , ["prefix", {"type": "var", "name": "lib_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "config_reader" + , { "type": "let*" + , "bindings": + [["fieldname", "config_reader"], ["location", "config_reader"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "pkg-configs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "pkg-config"}] + , ["prefix", {"type": "var", "name": "pc_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "name is required for cmake library" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["version", {"type": "FIELD", "name": "version"}] + , ["cflags", {"type": "FIELD", "name": "cflags"}] + , ["ldflags", {"type": "FIELD", "name": "ldflags"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , ["deps-fieldnames", ["deps", "defaults"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "prebuilt result"} + } + } +} diff --git a/rules/CC/foreign/expand_exec b/rules/CC/foreign/expand_exec new file mode 100755 index 0000000..32891ca --- /dev/null +++ b/rules/CC/foreign/expand_exec @@ -0,0 +1,133 @@ +#!/bin/sh +# Copyright 2023 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. + +set -e + +check_var_name() { + local NAME="$1" + if ! expr match "${NAME}" "[A-Z_a-z][0-9A-Z_a-z]*$" >/dev/null; then + echo "expand_exec error: invalid variable name '${NAME}'" + return 1 + fi + return 0 +} + +in_list() { + local NAME="$1" + local VAR_LIST="$2" + check_var_name "${NAME}" && expr match "${NAME}" "\(${VAR_LIST}\)$" >/dev/null +} + +EXPANDED_VAR= +expand_var() { + local NAME="$1" + check_var_name "${NAME}" && EXPANDED_VAR="$(eval "printf \"%s\" \"\${$NAME}\"")" +} + +PARSED_ARG= +parse_arg() { + local ARG="$1" + local VAR_LIST="$2" + local RESULT="" + local VAR_NAME="" + local PARSE_EXPR=false + local PARSE_VAR_NAME=false + + while [ ${#ARG} -gt 0 ]; do + local NEXT=${ARG#?} + c="${ARG%$NEXT}" + ARG=$NEXT + + if $PARSE_VAR_NAME; then + # parse <var> from $(<var>) + if [ "$c" = ")" ]; then + # expand var if in cases list + if in_list "${VAR_NAME}" "${VAR_LIST}" && expand_var "${VAR_NAME}"; then + RESULT="${RESULT}${EXPANDED_VAR}" + else + RESULT="${RESULT}\$(${VAR_NAME})" + fi + VAR_NAME="" + PARSE_VAR_NAME=false + else + # accumulate VAR_NAME + VAR_NAME="${VAR_NAME}$c" + if [ ${#ARG} -eq 0 ]; then + # flush unterminated var name + RESULT="${RESULT}\$(${VAR_NAME}" + fi + fi + else + # parse single char + if $PARSE_EXPR; then + if [ "$c" = "(" ]; then + # found "$(" + PARSE_VAR_NAME=true + else + RESULT="${RESULT}\$$c" + fi + PARSE_EXPR=false + elif [ "$c" = "$" ]; then + # found "$" + PARSE_EXPR=true + else + # append char + RESULT="${RESULT}$c" + fi + fi + done + + PARSED_ARG="'" + while [ ${#RESULT} -gt 0 ]; do + local NEXT=${RESULT#?} + c="${RESULT%$NEXT}" + RESULT=$NEXT + if [ "$c" = "'" ]; then + PARSED_ARG="${PARSED_ARG}'\\''" + else + PARSED_ARG="${PARSED_ARG}$c" + fi + done + PARSED_ARG="${PARSED_ARG}'" +} + +# usage: ./expand_exec [VARS...] -- ARGS... +expand_exec() { + local VAR_LIST="" + local VAR_SEP="" + local EXEC_VEC="" + local EXEC_SEP="" + local READ_ARGS=false + + while [ "$#" -ge 1 ]; do + local ARG="$1";shift + if $READ_ARGS; then + parse_arg "${ARG}" "${VAR_LIST}" + EXEC_VEC="${EXEC_VEC}${EXEC_SEP}${PARSED_ARG}" + EXEC_SEP=" " + else + if [ "${ARG}" = "--" ]; then + READ_ARGS=true + elif check_var_name "${ARG}"; then + VAR_LIST="${VAR_LIST}${VAR_SEP}${ARG}" + VAR_SEP="\|" + fi + fi + done + + exec /bin/sh -c "${EXEC_VEC}" +} + +expand_exec "$@" diff --git a/rules/CC/foreign/expand_exec.c b/rules/CC/foreign/expand_exec.c new file mode 100644 index 0000000..a4ff311 --- /dev/null +++ b/rules/CC/foreign/expand_exec.c @@ -0,0 +1,99 @@ +/* + * Copyright 2023 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. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* usage: ./expand_exec [VARS...] -- ARGS... */ +int main(int argc, const char *argv[]) { + char **outv; + const char **varv; + int i, j, varc, sep = 0, retval = 0; + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "--") == 0) { + sep = i; + break; + } + varc = sep - 1; + argc -= sep + 1; + if (sep == 0 || argc < 1) + return 1; /* error: missing sep or args */ + varv = &argv[1]; + argv = &argv[sep + 1]; + outv = (char **)calloc((size_t)(argc + 1), sizeof(char *)); + for (i = 0; i < argc; ++i) { /* iterate ARGS */ + const char *arg = argv[i]; + size_t arg_pos = 0, arg_len = strlen(arg); + size_t out_pos = 0, out_len = arg_len; + size_t str_pos = 0, str_len = 0; + char *out = (char *)calloc((size_t)(out_len + 1), sizeof(char)); + for (; arg_pos < arg_len; ++arg_pos) { + if (strncmp(&arg[arg_pos], "$(", 2) == 0) { + const char *start = &arg[arg_pos + 2]; + const char *end = strchr(start, ')'); + if (end == NULL) { + retval = 2; /* error: unterminated $(VAR) expression */ + free(out); + goto cleanup; + } + for (j = 0; j < varc; ++j) { /* lookup VAR */ + const char *var = varv[j]; + size_t len_var = strlen(var); + if ((size_t)(end - start) != len_var) + continue; + if (strncmp(&arg[arg_pos + 2], var, len_var) == 0) { + size_t val_len, out_len_new; + const char *val = getenv(var); + if (val == NULL) + val = ""; + val_len = strlen(val); + out_len_new = out_pos + str_len + val_len; + if (out_len_new > out_len) { + out = (char *)realloc(out, out_len_new + 1); + out_len = out_len_new; + } + strncat(out, &arg[str_pos], str_len); /* concat preceding substr */ + strncat(out, val, val_len); /* concat variable value */ + arg_pos += len_var + 2; + out_pos += str_len + val_len; + str_pos = arg_pos + 1; + str_len = 0; + break; + } + } + if (j != varc) + continue; /* success */ + } + ++str_len; + } + if (str_len > 0) { + if (out_pos + str_len > out_len) { + out = (char *)realloc(out, out_pos + str_len + 1); + } + strncat(out, &arg[str_pos], str_len); + } + outv[i] = out; + } + execvp(outv[0], outv); + retval = 3; /* error: exec failed */ +cleanup: + for (i = 0; i < argc; ++i) + if (outv[i] != NULL) + free(outv[i]); + free(outv); + return retval; +} diff --git a/rules/CC/foreign/make/EXPRESSIONS b/rules/CC/foreign/make/EXPRESSIONS new file mode 100644 index 0000000..bff8205 --- /dev/null +++ b/rules/CC/foreign/make/EXPRESSIONS @@ -0,0 +1,448 @@ +{ "make-build": + { "vars": + [ "source_dir" + , "subdir" + , "localbase_dir" + , "configure" + , "configure_options" + , "make_targets" + , "make_prefix" + , "make_options" + , "make_jobs" + , "pre_cmds" + , "post_cmds" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + , "defaults-transition" + , "expand_exec" + , "resolve_symlinks" + ] + , "imports": + { "artifacts": ["", "field_artifacts"] + , "nub_left": ["", "nub_left"] + , "flags-cc": ["CC", "flags-cc"] + , "flags-cxx": ["CC", "flags-cxx"] + , "compiler-cc": ["CC", "compiler-cc"] + , "compiler-cxx": ["CC", "compiler-cxx"] + , "default-LDFLAGS": ["CC", "default-LDFLAGS"] + , "default-AR": ["CC", "default-AR"] + , "default-ENV": ["CC", "default-ENV"] + , "default-PATH": ["CC", "default-PATH"] + , "default-TOOLCHAIN": ["CC", "default-TOOLCHAIN"] + , "default-NON_SYSTEM_TOOLS": ["CC", "default-NON_SYSTEM_TOOLS"] + , "foreign-MAKE": ["CC/foreign", "default-MAKE"] + , "foreign-ENV": ["CC/foreign", "default-ENV"] + , "foreign-PATH": ["CC/foreign", "default-PATH"] + , "foreign-TOOLCHAIN": ["CC/foreign", "default-TOOLCHAIN"] + , "foreign-NON_SYSTEM_TOOLS": ["CC/foreign", "default-NON_SYSTEM_TOOLS"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + , "sh-PATH": ["shell", "PATH"] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "Toolchain trees may not overlap" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-TOOLCHAIN"} + , {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"} + , {"type": "var", "name": "shell TOOLCHAIN"} + ] + } + ] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-NON_SYSTEM_TOOLS"} + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + } + ] + , [ "MAKE" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "foreign-MAKE"} + ] + } + } + ] + , ["CC", {"type": "CALL_EXPRESSION", "name": "compiler-cc"}] + , ["CXX", {"type": "CALL_EXPRESSION", "name": "compiler-cxx"}] + , [ "CFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cc"} + } + ] + , [ "CXXFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cxx"} + } + ] + , [ "LDFLAGS" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ ["-Wl,-rpath,$ORIGIN", "-Wl,-rpath,$ORIGIN/../lib"] + , { "type": "var" + , "name": "LDFLAGS" + , "default": + {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + } + , {"type": "var", "name": "ldflags", "default": []} + ] + } + } + ] + , [ "AR" + , { "type": "var" + , "name": "AR" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-AR"} + ] + } + } + } + ] + , [ "PREFIX" + , { "type": "if" + , "cond": {"type": "var", "name": "make_prefix"} + , "then": + { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": [[""], {"type": "var", "name": "make_prefix"}] + } + } + , "else": {"type": "var", "name": "PREFIX", "default": "/"} + } + ] + , [ "sh-PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh-PATH"} + } + } + ] + , [ "sh-ENV" + , { "type": "if" + , "cond": {"type": "var", "name": "sh-PATH"} + , "then": + { "type": "singleton_map" + , "key": "PATH" + , "value": {"type": "var", "name": "sh-PATH"} + } + , "else": {"type": "empty_map"} + } + ] + , [ "PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "let*" + , "bindings": + [ [ "list" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-PATH"} + , {"type": "CALL_EXPRESSION", "name": "default-PATH"} + ] + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + } + ] + , [ "ENV" + , { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "AR" + , "MAKE" + , "PREFIX" + ] + } + , {"type": "var", "name": "sh-ENV"} + , {"type": "CALL_EXPRESSION", "name": "default-ENV"} + , {"type": "CALL_EXPRESSION", "name": "foreign-ENV"} + , {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + ] + } + ] + , [ "SUBDIR" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "var", "name": "subdir", "default": []} + } + ] + , [ "configure_args" + , { "type": "if" + , "cond": {"type": "var", "name": "configure"} + , "then": + { "type": "++" + , "$1": + [ {"type": "var", "name": "configure_options", "default": []} + , [ { "type": "join" + , "$1": ["--prefix=", {"type": "var", "name": "PREFIX"}] + } + ] + ] + } + } + ] + , [ "make_targets" + , { "type": "if" + , "cond": {"type": "var", "name": "make_targets"} + , "then": {"type": "var", "name": "make_targets"} + , "else": ["install"] + } + ] + , [ "script" + , { "type": "singleton_map" + , "key": "run_make.sh" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + { "type": "++" + , "$1": + [ [ "set -eu" + , "mkdir scratch" + , "readonly ROOT=\"$(pwd)\"" + , "export TMPDIR=\"$(pwd)/scratch\"" + , "export DESTDIR=\"$(pwd)/install\"" + , "export TOOLCHAIN=\"$(pwd)/toolchain\"" + , "export LOCALBASE=\"$(pwd)/localbase\"" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CC" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CC=$(pwd)/${CC}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CXX" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CXX=$(pwd)/${CXX}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export AR=$(pwd)/${AR}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export MAKE=$(pwd)/${MAKE}" + , "else": "" + } + , { "type": "join" + , "$1": + [ "export PATH=\"$(./expand_exec TOOLCHAIN -- echo " + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "PATH"}] + } + , ")${PATH:+:}${PATH}\"" + ] + } + ] + , { "type": "if" + , "cond": {"type": "var", "name": "pre_cmds"} + , "then": + { "type": "++" + , "$1": + [ ["(", "set --", "cd ./source"] + , {"type": "var", "name": "pre_cmds"} + , [")"] + ] + } + } + , ["readonly SUBDIR=\"$1\"", "shift"] + , { "type": "if" + , "cond": {"type": "var", "name": "configure_args"} + , "then": + [ "( cd \"source/${SUBDIR}\"" + , { "type": "join" + , "$1": + [ "${ROOT}/expand_exec TMPDIR DESTDIR LOCALBASE CC CXX CFLAGS CXXFLAGS LDFLAGS AR PREFIX -- ./configure " + , { "type": "join_cmd" + , "$1": {"type": "var", "name": "configure_args"} + } + , " >\"${ROOT}/configure.log\" 2>&1 || (cat \"${ROOT}/configure.log\" && exit 1)" + ] + } + , ")" + ] + } + , { "type": "foreach" + , "range": {"type": "var", "name": "make_targets"} + , "var": "target" + , "body": + { "type": "join" + , "separator": " " + , "$1": + [ "${ROOT}/expand_exec TMPDIR DESTDIR LOCALBASE CC CXX CFLAGS CXXFLAGS LDFLAGS AR PREFIX" + , "--" + , "${MAKE} -C \"source/${SUBDIR}\" DESTDIR=${DESTDIR} \"$@\"" + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "target"}] + } + , ">>build.log 2>&1 || (cat build.log && exit 1)" + ] + } + } + , { "type": "if" + , "cond": {"type": "var", "name": "resolve_symlinks"} + , "then": + [ "mv install install_with_symlinks" + , "cp -rL install_with_symlinks install >copy.log 2>&1 || (echo 'ERROR: symlink resolve failed with:' && cat copy.log && exit 1)" + ] + } + , { "type": "if" + , "cond": {"type": "var", "name": "post_cmds"} + , "then": + { "type": "++" + , "$1": + [ ["(", "set --", "cd ./install"] + , {"type": "var", "name": "post_cmds"} + , [")"] + ] + } + } + ] + } + } + } + } + ] + ] + , "body": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "source_dir"} + , {"type": "var", "name": "expand_exec"} + , { "type": "var" + , "name": "localbase_dir" + , "default": {"type": "empty_map"} + } + , {"type": "var", "name": "script"} + ] + } + , "cmd": + { "type": "++" + , "$1": + [ [{"type": "var", "name": "sh"}, "run_make.sh"] + , [{"type": "var", "name": "SUBDIR"}] + , {"type": "var", "name": "make_options"} + , { "type": "if" + , "cond": {"type": "var", "name": "make_jobs"} + , "then": + [ { "type": "join" + , "$1": + { "type": "++" + , "$1": [["-j"], {"type": "var", "name": "make_jobs"}] + } + } + ] + } + ] + } + , "out_dirs": ["install"] + , "env": {"type": "var", "name": "ENV"} + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 10.0} + } + } + } +} diff --git a/rules/CC/foreign/make/RULES b/rules/CC/foreign/make/RULES new file mode 100644 index 0000000..cf67998 --- /dev/null +++ b/rules/CC/foreign/make/RULES @@ -0,0 +1,795 @@ +{ "data": + { "doc": + [ "Data produced by Configure and Make build and install." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"CC\", \"CXX\", \"CFLAGS\", \"CXXFLAGS\", \"LDFLAGS\"," + , "\"AR\", and \"PREFIX\". \"LOCALBASE\" contains the path to the" + , "installed artifacts from \"deps\"." + ] + , "target_fields": ["project"] + , "string_fields": + [ "subdir" + , "configure" + , "configure_options" + , "targets" + , "prefix" + , "options" + , "jobs" + , "pre_cmds" + , "post_cmds" + , "out_files" + , "out_dirs" + , "resolve_symlinks" + ] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + ["The Make project directory. It should contain a single tree artifact"] + , "subdir": + [ "The subdirectory that contains the configure and Makefile. Individual" + , "directory components are joined with \"/\"." + ] + , "configure": ["Run ./configure if non-empty."] + , "configure_options": + [ "The configure options (the \"--prefix\" option is automatically set." + , "Variables can be accessed via \"$(<varname>)\", e.g., \"$(TMPDIR)\"" + , "for variable \"$TMPDIR\"." + ] + , "targets": + [ "The Make targets to build in the specified order" + , "(default: [\"install\"])." + ] + , "prefix": + [ "The prefix used for the Make target. The path will be made absolute" + , "and individual directory components are joined with \"/\". If no" + , "prefix is specified, the value from the config variable \"PREFIX\" is" + , "taken, with the default value being \"/\"." + ] + , "options": + [ "Make options for the configuration phase" + , "(e.g., [\"-f\", \"Makefile\", \"ARCH=x86\", \"LD=$(CC)\"]). Variables" + , "can be accessed via \"$(<varname>)\", e.g., \"$(TMPDIR)\" for" + , "variable \"$TMPDIR\"." + ] + , "jobs": + [ "Number of jobs to run simultaneously. If omitted, Make's default" + , "number is used." + ] + , "pre_cmds": + [ "List of commands executed in the project directory before calling" + , "Configure or Make. Useful for renaming files or directories. Note" + , "that data between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\", which is uniquely reserved for this action." + ] + , "post_cmds": + [ "List of commands executed in the install directory after successful" + , "installation but before the output files are collected. Useful for" + , "renaming files or directories. Note that data between \"pre_cmds\" and" + , "\"post_cmds\" can be exchanged via \"$TMPDIR\", which is uniquely" + , "reserved for this action." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after the install, before \"post_cmds\" are run." + ] + , "out_files": + [ "Paths to the produced output files. The paths are considered relative" + , "to the install directory." + , "Note that \"out_files\" and \"out_dirs\" may not overlap." + ] + , "out_dirs": + [ "Paths to the produced output directories. The paths are considered" + , "relative to the install directory." + , "Note that \"out_files\" and \"out_dirs\" may not overlap." + ] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + [ "The linker flags to be used instead of the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "PREFIX": + [ "The absolute path that is used as prefix inside generated pkg-config" + , "files. The default value for this variable is \"/\". This variable" + , "is ignored if the field \"prefix\" is set." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "stage_field": ["", "stage_singleton_field"] + , "make-build": "make-build" + , "strip-prefix": ["./", "..", "strip-prefix"] + , "for host": ["transitions", "for host"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["install_prefix", "install"] + , [ "source_dir" + , { "type": "let*" + , "bindings": [["fieldname", "project"], ["location", "source"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "installed_out_files" + , { "type": "foreach" + , "var": "file_path" + , "range": {"type": "FIELD", "name": "out_files"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "file_path"} + ] + } + } + ] + , [ "installed_out_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "FIELD", "name": "out_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , ["subdir", {"type": "FIELD", "name": "subdir"}] + , ["configure", {"type": "FIELD", "name": "configure"}] + , ["configure_options", {"type": "FIELD", "name": "configure_options"}] + , ["make_targets", {"type": "FIELD", "name": "targets"}] + , ["make_prefix", {"type": "FIELD", "name": "prefix"}] + , ["make_options", {"type": "FIELD", "name": "options"}] + , ["make_jobs", {"type": "FIELD", "name": "jobs"}] + , ["pre_cmds", {"type": "FIELD", "name": "pre_cmds"}] + , ["post_cmds", {"type": "FIELD", "name": "post_cmds"}] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["defaults-transition", {"type": "empty_map"}] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , ["full_install_dir", {"type": "CALL_EXPRESSION", "name": "make-build"}] + , ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "install_dir" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "shell TOOLCHAIN"} + , {"type": "var", "name": "full_install_dir"} + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "-c", ":"] + , "outs": {"type": "var", "name": "installed_out_files"} + , "out_dirs": {"type": "var", "name": "installed_out_dirs"} + } + ] + , [ "out_files" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_files"}] + , ["prefix", {"type": "var", "name": "install_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "out_dirs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_dirs"}] + , ["prefix", {"type": "var", "name": "install_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": + { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "out_files"} + , {"type": "var", "name": "out_dirs"} + ] + } + } + } + } + } +, "library": + { "doc": + [ "Library produced by Configure and Make build and install." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"CC\", \"CXX\", \"CFLAGS\", \"CXXFLAGS\", \"LDFLAGS\"," + , "\"AR\", and \"PREFIX\". \"LOCALBASE\" contains the path to the" + , "installed artifacts from \"deps\"." + ] + , "target_fields": ["project", "deps"] + , "string_fields": + [ "subdir" + , "name" + , "version" + , "stage" + , "configure" + , "configure_options" + , "targets" + , "prefix" + , "options" + , "jobs" + , "pre_cmds" + , "post_cmds" + , "out_hdrs" + , "out_hdr_dirs" + , "out_libs" + , "cflags" + , "ldflags" + , "pkg-config" + , "hdr_prefix" + , "lib_prefix" + , "pc_prefix" + , "resolve_symlinks" + ] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "config_reader": [["CC", "prebuilt/read_pkgconfig.py"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + ["The Make project directory. It should contain a single tree artifact"] + , "subdir": + [ "The subdirectory that contains the configure and Makefile. Individual" + , "directory components are joined with \"/\"." + ] + , "name": + [ "The name of the library (without leading \"lib\" or trailing file name" + , "extension), also used as name for pkg-config files." + ] + , "version": + [ "The library version, used for pkg-config files. Individual version" + , "components are joined with \".\"." + ] + , "configure": ["Run ./configure if non-empty."] + , "configure_options": + ["The configure options (the \"--prefix\" option is automatically set."] + , "targets": + [ "The Make targets to build in the specified order" + , "(default: [\"install\"])." + ] + , "prefix": + [ "The prefix used for the Make target. The path will be made absolute" + , "and individual directory components are joined with \"/\". If no" + , "prefix is specified, the value from the config variable \"PREFIX\" is" + , "taken, with the default value being \"/\"." + ] + , "options": + [ "Make options for the build phase." + , "(e.g., [\"-f\", \"Makefile\", \"ARCH=x86\"])" + ] + , "jobs": + [ "Number of jobs to run simultaneously. If omitted, Make's default" + , "number is used." + ] + , "pre_cmds": + [ "List of commands executed in the project directory before calling" + , "Configure or Make. Useful for renaming files or directories. Note" + , "that data between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\", which is uniquely reserved for this action." + ] + , "post_cmds": + [ "List of commands executed in the install directory after successful" + , "installation but before the output files are collected. Useful for" + , "renaming files or directories (e.g., in case of SONAME mismatch). Note" + , "that data between \"pre_cmds\" and \"post_cmds\" can be exchanged via" + , "\"$TMPDIR\", which is uniquely reserved for this action." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after the install, before \"post_cmds\" are run." + ] + , "out_hdrs": + [ "Paths to produced public header files. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_hdr_dirs": + [ "Paths to produced public header directories. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_libs": + [ "Paths to produced library files. The path is considered relative" + , "to the library directory, which be set via \"lib_prefix\"." + , "Order matters in the case of one library depending on another." + ] + , "cflags": + ["List of compile flags set for this target and its consumers."] + , "ldflags": + [ "Additional linker flags that are required for the consumer of the" + , "produced libraries." + ] + , "stage": + [ "The logical location of the public headers and library files." + , "Individual directory components are joined with \"/\"." + ] + , "deps": ["Public dependency on other CC libraries."] + , "pkg-config": + [ "Pkg-config file for optional infer of public cflags and ldflags. If" + , "multiple files are specified (e.g., one depends on the other), the" + , "first one is used as entry. Note that if this field is non-empty the" + , "tool \"pkg-config\" must be available in \"PATH\", which is taken" + , "from [\"CC\", \"defaults\"] or the \"ENV\" variable." + ] + , "hdr_prefix": + [ "Prefix where headers will be installed by Make. Individual directory" + , "components are joined with \"/\". Defaults to \"include\" if not set." + ] + , "lib_prefix": + [ "Prefix where libraries will be installed by Make. Individual" + , "directory components are joined with \"/\". Defaults to \"lib\" if" + , "not set." + ] + , "pc_prefix": + [ "Prefix where pkg-config files will be installed by Make. Individual" + , "directory components are joined with \"/\". Defaults to" + , "\"lib/pkgconfig\" if not set." + ] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + ["Global ld flags, for common link args,such as -Wl,-z,noexecstack"] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library" + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "PREFIX": + [ "The absolute path that is used as prefix inside generated pkg-config" + , "files. The default value for this variable is \"/\". This variable" + , "is ignored if the field \"prefix\" is set." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "stage_field": ["", "stage_singleton_field"] + , "make-build": "make-build" + , "strip-prefix": ["./", "..", "strip-prefix"] + , "prebuilt result": ["CC/prebuilt", "prebuilt result"] + , "install-deps": ["CC", "install-with-deps stage"] + , "for host": ["transitions", "for host"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "hdr_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "hdr_prefix"} + , "then": {"type": "FIELD", "name": "hdr_prefix"} + , "else": ["include"] + } + ] + } + } + ] + , [ "lib_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "lib_prefix"} + , "then": {"type": "FIELD", "name": "lib_prefix"} + , "else": ["lib"] + } + ] + } + } + ] + , [ "pc_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "pc_prefix"} + , "then": {"type": "FIELD", "name": "pc_prefix"} + , "else": ["lib", "pkgconfig"] + } + ] + } + } + ] + , [ "source_dir" + , { "type": "let*" + , "bindings": [["fieldname", "project"], ["location", "source"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "localbase_dir" + , { "type": "to_subdir" + , "subdir": "localbase" + , "msg": "dependency installation files may not overlap" + , "$1": + { "type": "let*" + , "bindings": + [ ["pc-install-dir", "lib/pkgconfig"] + , ["targets", {"type": "FIELD", "name": "deps"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "install-deps"} + } + } + ] + , [ "installed_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "FIELD", "name": "out_hdr_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , [ "installed_files" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "lib_path" + , "range": {"type": "FIELD", "name": "out_libs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "lib_prefix"} + , {"type": "var", "name": "lib_path"} + ] + } + } + , { "type": "foreach" + , "var": "hdr_path" + , "range": {"type": "FIELD", "name": "out_hdrs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "hdr_path"} + ] + } + } + , { "type": "foreach" + , "var": "pc_path" + , "range": {"type": "FIELD", "name": "pkg-config"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "pc_prefix"} + , {"type": "var", "name": "pc_path"} + ] + } + } + ] + } + ] + , ["subdir", {"type": "FIELD", "name": "subdir"}] + , ["configure", {"type": "FIELD", "name": "configure"}] + , ["configure_options", {"type": "FIELD", "name": "configure_options"}] + , ["make_targets", {"type": "FIELD", "name": "targets"}] + , ["make_prefix", {"type": "FIELD", "name": "prefix"}] + , ["make_options", {"type": "FIELD", "name": "options"}] + , ["make_jobs", {"type": "FIELD", "name": "jobs"}] + , ["pre_cmds", {"type": "FIELD", "name": "pre_cmds"}] + , ["post_cmds", {"type": "FIELD", "name": "post_cmds"}] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["defaults-transition", {"type": "empty_map"}] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , ["full_install_dir", {"type": "CALL_EXPRESSION", "name": "make-build"}] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "install_dir" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "shell TOOLCHAIN"} + , {"type": "var", "name": "full_install_dir"} + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "-c", ":"] + , "outs": {"type": "var", "name": "installed_files"} + , "out_dirs": {"type": "var", "name": "installed_dirs"} + } + ] + , [ "hdrs" + , { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdrs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdr_dirs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + } + ] + , [ "libs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_libs"}] + , ["prefix", {"type": "var", "name": "lib_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "config_reader" + , { "type": "let*" + , "bindings": + [["fieldname", "config_reader"], ["location", "config_reader"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "pkg-configs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "pkg-config"}] + , ["prefix", {"type": "var", "name": "pc_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "name is required for make library" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["version", {"type": "FIELD", "name": "version"}] + , ["cflags", {"type": "FIELD", "name": "cflags"}] + , ["ldflags", {"type": "FIELD", "name": "ldflags"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , ["deps-fieldnames", ["deps", "defaults"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "prebuilt result"} + } + } +} diff --git a/rules/CC/foreign/shell/EXPRESSIONS b/rules/CC/foreign/shell/EXPRESSIONS new file mode 100644 index 0000000..a0a9a00 --- /dev/null +++ b/rules/CC/foreign/shell/EXPRESSIONS @@ -0,0 +1,367 @@ +{ "shell-build": + { "vars": + [ "cmds" + , "sources" + , "localbase" + , "installed_files" + , "installed_dirs" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + , "expand_exec" + , "resolve_symlinks" + ] + , "imports": + { "artifacts": ["", "field_artifacts"] + , "nub_left": ["", "nub_left"] + , "flags-cc": ["CC", "flags-cc"] + , "flags-cxx": ["CC", "flags-cxx"] + , "compiler-cc": ["CC", "compiler-cc"] + , "compiler-cxx": ["CC", "compiler-cxx"] + , "default-LDFLAGS": ["CC", "default-LDFLAGS"] + , "default-AR": ["CC", "default-AR"] + , "default-PATH": ["CC", "default-PATH"] + , "default-TOOLCHAIN": ["CC", "default-TOOLCHAIN"] + , "default-NON_SYSTEM_TOOLS": ["CC", "default-NON_SYSTEM_TOOLS"] + , "foreign-MAKE": ["CC/foreign", "default-MAKE"] + , "foreign-CMAKE": ["CC/foreign", "default-CMAKE"] + , "foreign-PATH": ["CC/foreign", "default-PATH"] + , "foreign-TOOLCHAIN": ["CC/foreign", "default-TOOLCHAIN"] + , "foreign-NON_SYSTEM_TOOLS": ["CC/foreign", "default-NON_SYSTEM_TOOLS"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + , "sh-PATH": ["shell", "PATH"] + , "sh prolog": ["shell", "prolog"] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "Toolchain trees may not overlap" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-TOOLCHAIN"} + , {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"} + , {"type": "var", "name": "shell TOOLCHAIN"} + ] + } + ] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-NON_SYSTEM_TOOLS"} + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + } + ] + , [ "MAKE" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "foreign-MAKE"} + ] + } + } + ] + , [ "CMAKE" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CMAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "foreign-CMAKE"} + ] + } + } + ] + , ["CC", {"type": "CALL_EXPRESSION", "name": "compiler-cc"}] + , ["CXX", {"type": "CALL_EXPRESSION", "name": "compiler-cxx"}] + , [ "CFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cc"} + } + ] + , [ "CXXFLAGS" + , { "type": "join" + , "separator": " " + , "$1": {"type": "CALL_EXPRESSION", "name": "flags-cxx"} + } + ] + , [ "LDFLAGS" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ ["-Wl,-rpath,$ORIGIN", "-Wl,-rpath,$ORIGIN/../lib"] + , { "type": "var" + , "name": "LDFLAGS" + , "default": + {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + } + , {"type": "var", "name": "ldflags", "default": []} + ] + } + } + ] + , [ "AR" + , { "type": "var" + , "name": "AR" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-AR"} + ] + } + } + } + ] + , [ "PREFIX" + , { "type": "if" + , "cond": {"type": "var", "name": "make_prefix"} + , "then": + { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": [[""], {"type": "var", "name": "make_prefix"}] + } + } + , "else": {"type": "var", "name": "PREFIX", "default": "/"} + } + ] + , [ "PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "let*" + , "bindings": + [ [ "list" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "foreign-PATH"} + , {"type": "CALL_EXPRESSION", "name": "default-PATH"} + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh-PATH"} + } + ] + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + } + ] + , [ "ENV" + , { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "MAKE" + , "CMAKE" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "AR" + , "PREFIX" + ] + } + , {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + ] + } + ] + , [ "localbase" + , { "type": "to_subdir" + , "subdir": "localbase" + , "$1": {"type": "var", "name": "localbase"} + } + ] + , [ "work_dir" + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "sources"} + } + ] + , [ "script" + , { "type": "singleton_map" + , "key": "run_cmds.sh" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh prolog"} + } + , [ "set -eu" + , "mkdir -p scratch work install" + , "export ACTION_DIR=\"$(pwd)\"" + , "export TMPDIR=\"$(pwd)/scratch\"" + , "export WORKDIR=\"$(pwd)/work\"" + , "export TOOLCHAIN=\"$(pwd)/toolchain\"" + , "export LOCALBASE=\"$(pwd)/localbase\"" + , "export DESTDIR=\"$(pwd)/install\"" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CC" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CC=$(pwd)/${CC}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CXX" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CXX=$(pwd)/${CXX}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "AR" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export AR=$(pwd)/${AR}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "MAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export MAKE=$(pwd)/${MAKE}" + , "else": "" + } + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "CMAKE" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": "export CMAKE=$(pwd)/${CMAKE}" + , "else": "" + } + , { "type": "join" + , "$1": + [ "export PATH=\"$(./expand_exec TOOLCHAIN -- echo " + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "PATH"}] + } + , ")${PATH:+:}${PATH}\"" + ] + } + ] + , ["(", "set --", "cd ./work"] + , {"type": "var", "name": "cmds"} + , [")"] + , { "type": "if" + , "cond": {"type": "var", "name": "resolve_symlinks"} + , "then": + [ "mv install install_with_symlinks" + , "cp -rL install_with_symlinks install >copy.log 2>&1 || (echo 'ERROR: symlink resolve failed with:' && cat copy.log && exit 1)" + ] + } + ] + } + } + } + } + ] + , [ "artifacts" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "work_dir"} + , {"type": "var", "name": "localbase"} + , {"type": "var", "name": "script"} + , {"type": "var", "name": "expand_exec"} + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "run_cmds.sh"] + , "outs": {"type": "var", "name": "installed_files"} + , "out_dirs": {"type": "var", "name": "installed_dirs"} + , "env": {"type": "var", "name": "ENV"} + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 10.0} + } + ] + ] + , "body": {"type": "var", "name": "artifacts"} + } + } +} diff --git a/rules/CC/foreign/shell/RULES b/rules/CC/foreign/shell/RULES new file mode 100644 index 0000000..6a5d8ec --- /dev/null +++ b/rules/CC/foreign/shell/RULES @@ -0,0 +1,638 @@ +{ "data": + { "doc": + [ "Data produced by generic shell commands with toolchain support." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"WORKDIR\", \"DESTDIR\", \"CC\", \"CXX\", \"CFLAGS\"," + , "\"CXXFLAGS\", \"LDFLAGS\", and \"AR\". \"LOCALBASE\" contains the path" + , "to the staged artifacts from \"localbase\" and the installed artifacts" + , "from \"deps\". Furthermore, the variable \"ACTION_DIR\" points to the" + , "current action directory, if needed for achieving reproducibility." + ] + , "target_fields": ["project", "localbase", "deps"] + , "string_fields": ["cmds", "outs", "out_dirs", "resolve_symlinks"] + , "config_vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + [ "The project directory. It should contain a single tree artifact." + , "It's path can be accessed via the \"WORKDIR\" variable." + ] + , "localbase": ["Artifacts to stage to \"LOCALBASE\"."] + , "deps": ["CC targets to install to \"LOCALBASE\"."] + , "cmds": + [ "List of commands to execute by \"sh\". Multiple commands will be" + , "joined with the newline character." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after \"cmds\" were executed." + ] + , "outs": ["Paths to the produced output files in \"DESTDIR\"."] + , "out_dirs": ["Paths to the produced output directories in \"DESTDIR\"."] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + [ "The linker flags to be used instead of the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "PREFIX": + [ "The absolute path that is used as prefix inside generated pkg-config" + , "files. The default value for this variable is \"/\". This variable" + , "is ignored if the field \"prefix\" is set." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "artifacts": ["", "field_artifacts"] + , "stage_field": ["", "stage_singleton_field"] + , "shell-build": "shell-build" + , "install-deps": ["CC", "install-with-deps stage"] + , "strip-prefix": ["CC/foreign", "strip-prefix"] + , "for host": ["transitions", "for host"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["cmds", {"type": "FIELD", "name": "cmds"}] + , [ "sources" + , { "type": "let*" + , "bindings": [["fieldname", "project"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + ] + , [ "localbase" + , { "type": "disjoint_map_union" + , "msg": "localbase and installed dependency files may not overlap" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["pc-install-dir", "lib/pkgconfig"] + , ["targets", {"type": "FIELD", "name": "deps"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "install-deps"} + } + , { "type": "let*" + , "bindings": [["fieldname", "localbase"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + ] + } + ] + , ["outs", {"type": "FIELD", "name": "outs"}] + , ["out_dirs", {"type": "FIELD", "name": "out_dirs"}] + , ["install_prefix", "install"] + , [ "installed_files" + , { "type": "foreach" + , "var": "file_path" + , "range": {"type": "var", "name": "outs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "file_path"} + ] + } + } + ] + , [ "installed_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "var", "name": "out_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "install_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["artifacts", {"type": "CALL_EXPRESSION", "name": "shell-build"}] + ] + , "body": + { "type": "RESULT" + , "artifacts": + { "type": "map_union" + , "$1": + { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "artifacts"}] + , [ "paths" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "outs"} + , {"type": "var", "name": "out_dirs"} + ] + } + ] + , ["prefix", {"type": "var", "name": "install_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + } + } + } + } +, "library": + { "doc": + [ "Library produced by generic shell commands with toolchain support." + , "" + , "All variables accessible to commands and options are: \"TMPDIR\"," + , "\"LOCALBASE\", \"WORKDIR\", \"DESTDIR\", \"CC\", \"CXX\", \"CFLAGS\"," + , "\"CXXFLAGS\", \"LDFLAGS\", and \"AR\". \"LOCALBASE\" contains the path" + , "to the staged artifacts from \"localbase\" and the installed artifacts" + , "from \"deps\". Furthermore, the variable \"ACTION_DIR\" points to the" + , "current action directory, if needed for achieving reproducibility." + ] + , "target_fields": ["project", "localbase", "deps"] + , "string_fields": + [ "name" + , "version" + , "stage" + , "cmds" + , "out_hdrs" + , "out_hdr_dirs" + , "out_libs" + , "cflags" + , "ldflags" + , "pkg-config" + , "hdr_prefix" + , "lib_prefix" + , "pc_prefix" + , "resolve_symlinks" + ] + , "config_vars": + [ "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "AR" + , "PREFIX" + , "BUILD_POSITION_INDEPENDENT" + , "TIMEOUT_SCALE" + ] + , "implicit": + { "defaults": [["CC", "defaults"]] + , "foreign-defaults": [["CC/foreign", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "config_reader": [["CC", "prebuilt/read_pkgconfig.py"]] + , "expand_exec": [["./", "..", "expand_exec"]] + } + , "field_doc": + { "project": + [ "The project directory. It should contain a single tree artifact." + , "It's path can be accessed via the \"WORKDIR\" variable." + ] + , "name": + [ "The name of the library (without leading \"lib\" or trailing file name" + , "extension), also used as name for pkg-config files." + ] + , "version": + [ "The library version, used for pkg-config files. Individual version" + , "components are joined with \".\"." + ] + , "localbase": ["Artifacts to stage to \"LOCALBASE\"."] + , "cmds": + [ "List of commands to execute by \"sh\". Multiple commands will be" + , "joined with the newline character." + ] + , "resolve_symlinks": + [ "Resolve all symlinks in the install directory. This operation is" + , "performed immediately after \"cmds\" were executed." + ] + , "out_hdrs": + [ "Paths to produced public header files. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_hdr_dirs": + [ "Paths to produced public header directories. The path is considered" + , "relative to the include directory, which be set via \"hdr_prefix\"." + , "Note that \"out_hdrs\" and \"out_hdr_dirs\" may not overlap." + ] + , "out_libs": + [ "Paths to produced library files. The path is considered relative" + , "to the library directory, which be set via \"lib_prefix\"." + , "Order matters in the case of one library depending on another." + ] + , "cflags": + ["List of compile flags set for this target and its consumers."] + , "ldflags": + [ "Additional linker flags that are required for the consumer of the" + , "produced libraries." + ] + , "stage": + [ "The logical location of the public headers and library files." + , "Individual directory components are joined with \"/\"." + ] + , "deps": ["Public dependency on other CC libraries."] + , "pkg-config": + [ "Pkg-config file for optional infer of public cflags and ldflags. If" + , "multiple files are specified (e.g., one depends on the other), the" + , "first one is used as entry. Note that if this field is non-empty the" + , "tool \"pkg-config\" must be available in \"PATH\", which is taken" + , "from [\"CC\", \"defaults\"] or the \"ENV\" variable." + ] + , "hdr_prefix": + [ "Prefix where headers will be installed by Make. Individual directory" + , "components are joined with \"/\". Defaults to \"include\" if not set." + ] + , "lib_prefix": + [ "Prefix where libraries will be installed by Make. Individual" + , "directory components are joined with \"/\". Defaults to \"lib\" if" + , "not set." + ] + , "pc_prefix": + [ "Prefix where pkg-config files will be installed by Make. Individual" + , "directory components are joined with \"/\". Defaults to" + , "\"lib/pkgconfig\" if not set." + ] + } + , "config_doc": + { "CC": + [ "The name of the C compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CXX": + [ "The name of the C++ compiler to be used." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "CFLAGS": + [ "The flags for CC to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "CXXFLAGS": + [ "The flags for CXX to be used instead of the default ones." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "LDFLAGS": + [ "The linker flags to be used instead of the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice" + ] + , "ADD_CFLAGS": + [ "The flags to add to the default ones for CC." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_CXXFLAGS": + [ "The flags to add to the default ones for CXX." + , "For libraries that should be built in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones." + , "For libraries that should be linked in a non-standard way; usually" + , "adapting the default target [\"CC\", \"defaults\"] is the better" + , "choice." + ] + , "ENV": + [ "The environment for any action generated." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "AR": + [ "The archive tool to used for creating the library." + , "If null, the respective value from [\"CC\", \"defaults\"] will be taken." + ] + , "PREFIX": + [ "The absolute path that is used as prefix inside generated pkg-config" + , "files. The default value for this variable is \"/\". This variable" + , "is ignored if the field \"prefix\" is set." + ] + , "BUILD_POSITION_INDEPENDENT": ["Build position independent code."] + , "TIMEOUT_SCALE": + [ "The scaling of the timeout for the invocation of the foreign build." + , "Defaults to 10." + ] + } + , "imports": + { "artifacts": ["", "field_artifacts"] + , "stage_field": ["", "stage_singleton_field"] + , "shell-build": "shell-build" + , "prebuilt result": ["CC/prebuilt", "prebuilt result"] + , "install-deps": ["CC", "install-with-deps stage"] + , "strip-prefix": ["CC/foreign", "strip-prefix"] + , "for host": ["transitions", "for host"] + } + , "config_transitions": + { "defaults": + [{"type": "empty_map"}, {"type": "CALL_EXPRESSION", "name": "for host"}] + , "expand_exec": [{"type": "CALL_EXPRESSION", "name": "for host"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "hdr_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "hdr_prefix"} + , "then": {"type": "FIELD", "name": "hdr_prefix"} + , "else": ["include"] + } + ] + } + } + ] + , [ "lib_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "lib_prefix"} + , "then": {"type": "FIELD", "name": "lib_prefix"} + , "else": ["lib"] + } + ] + } + } + ] + , [ "pc_prefix" + , { "type": "join" + , "separator": "/" + , "$1": + { "type": "++" + , "$1": + [ ["install"] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "pc_prefix"} + , "then": {"type": "FIELD", "name": "pc_prefix"} + , "else": ["lib", "pkgconfig"] + } + ] + } + } + ] + , [ "sources" + , { "type": "let*" + , "bindings": [["fieldname", "project"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + ] + , [ "localbase" + , { "type": "disjoint_map_union" + , "msg": "localbase and installed dependency files may not overlap" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["pc-install-dir", "lib/pkgconfig"] + , ["targets", {"type": "FIELD", "name": "deps"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "install-deps"} + } + , { "type": "let*" + , "bindings": [["fieldname", "localbase"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + ] + } + ] + , [ "installed_dirs" + , { "type": "foreach" + , "var": "dir_path" + , "range": {"type": "FIELD", "name": "out_hdr_dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "dir_path"} + ] + } + } + ] + , [ "installed_files" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "lib_path" + , "range": {"type": "FIELD", "name": "out_libs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "lib_prefix"} + , {"type": "var", "name": "lib_path"} + ] + } + } + , { "type": "foreach" + , "var": "hdr_path" + , "range": {"type": "FIELD", "name": "out_hdrs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "hdr_prefix"} + , {"type": "var", "name": "hdr_path"} + ] + } + } + , { "type": "foreach" + , "var": "pc_path" + , "range": {"type": "FIELD", "name": "pkg-config"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "pc_prefix"} + , {"type": "var", "name": "pc_path"} + ] + } + } + ] + } + ] + , ["cmds", {"type": "FIELD", "name": "cmds"}] + , ["resolve_symlinks", {"type": "FIELD", "name": "resolve_symlinks"}] + , ["defaults-transition", {"type": "empty_map"}] + , [ "expand_exec" + , { "type": "let*" + , "bindings": + [ ["fieldname", "expand_exec"] + , ["location", "expand_exec"] + , ["transition", {"type": "CALL_EXPRESSION", "name": "for host"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , ["install_dir", {"type": "CALL_EXPRESSION", "name": "shell-build"}] + , [ "hdrs" + , { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdrs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_hdr_dirs"}] + , ["prefix", {"type": "var", "name": "hdr_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + } + ] + , [ "libs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "out_libs"}] + , ["prefix", {"type": "var", "name": "lib_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "config_reader" + , { "type": "let*" + , "bindings": + [["fieldname", "config_reader"], ["location", "config_reader"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "pkg-configs" + , { "type": "let*" + , "bindings": + [ ["artifacts", {"type": "var", "name": "install_dir"}] + , ["paths", {"type": "FIELD", "name": "pkg-config"}] + , ["prefix", {"type": "var", "name": "pc_prefix"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "strip-prefix"} + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "name is required for make library" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["version", {"type": "FIELD", "name": "version"}] + , ["cflags", {"type": "FIELD", "name": "cflags"}] + , ["ldflags", {"type": "FIELD", "name": "ldflags"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , ["deps-fieldnames", ["deps", "defaults"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "prebuilt result"} + } + } +} diff --git a/rules/CC/pkgconfig/EXPRESSIONS b/rules/CC/pkgconfig/EXPRESSIONS new file mode 100644 index 0000000..8707f87 --- /dev/null +++ b/rules/CC/pkgconfig/EXPRESSIONS @@ -0,0 +1,296 @@ +{ "pkgconfig result": + { "vars": ["ENV", "name", "args", "stage"] + , "imports": + { "default-ENV": ["./", "..", "default-ENV"] + , "default-PATH": ["./", "..", "default-PATH"] + , "stage": ["", "stage_singleton_field"] + , "list_provider": ["", "field_list_provider"] + , "map_provider": ["", "field_map_provider"] + , "sh": ["shell", "sh"] + , "sh-PATH": ["shell", "PATH"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "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_PKG_CONFIG_PATH" + , { "type": "lookup" + , "map": {"type": "var", "name": "ENV"} + , "key": "PKG_CONFIG_PATH" + } + ] + , [ "sh-PATH" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh-PATH"} + } + ] + , [ "pkgconfig PATH" + , { "type": "let*" + , "bindings": + [["fieldname", "pkgconfig defaults"], ["provider", "PATH"]] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + ] + , [ "PKG_CONFIG_PATH" + , { "type": "let*" + , "bindings": + [ ["fieldname", "pkgconfig defaults"] + , ["provider", "PKG_CONFIG_PATH"] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + ] + , [ "final PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "pkgconfig PATH"} + , {"type": "CALL_EXPRESSION", "name": "default-PATH"} + , {"type": "var", "name": "sh-PATH"} + , { "type": "if" + , "cond": {"type": "var", "name": "ENV_PATH"} + , "then": [{"type": "var", "name": "ENV_PATH"}] + } + ] + } + } + ] + , [ "final PKG_CONFIG_PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "PKG_CONFIG_PATH"} + , { "type": "if" + , "cond": {"type": "var", "name": "ENV_PKG_CONFIG_PATH"} + , "then": [{"type": "var", "name": "ENV_PKG_CONFIG_PATH"}] + } + ] + } + } + ] + , [ "ENV" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "ENV"} + , { "type": "if" + , "cond": {"type": "var", "name": "final PATH"} + , "else": {"type": "empty_map"} + , "then": + { "type": "singleton_map" + , "key": "PATH" + , "value": {"type": "var", "name": "final PATH"} + } + } + , { "type": "if" + , "cond": {"type": "var", "name": "final PKG_CONFIG_PATH"} + , "else": {"type": "empty_map"} + , "then": + { "type": "singleton_map" + , "key": "PKG_CONFIG_PATH" + , "value": {"type": "var", "name": "final PKG_CONFIG_PATH"} + } + } + ] + } + ] + , ["TOOLCHAIN_DIR", "toolchain"] + , [ "shell TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": + { "type": "let*" + , "bindings": + [ ["fieldname", "shell defaults"] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } + ] + , [ "sh" + , { "type": "let*" + , "bindings": [["fieldname", "shell defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh"} + } + ] + , [ "pkg-config" + , { "type": "join" + , "$1": + { "type": "let*" + , "bindings": + [["fieldname", "pkgconfig defaults"], ["provider", "pkg-config"]] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } + ] + , [ "pkg-config" + , { "type": "if" + , "cond": {"type": "var", "name": "pkg-config"} + , "then": {"type": "var", "name": "pkg-config"} + , "else": "pkg-config" + } + ] + , [ "cflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".cflags"]} + ] + , [ "cflags-files" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "ACTION" + , "inputs": {"type": "var", "name": "shell TOOLCHAIN"} + , "cmd": + [ {"type": "var", "name": "sh"} + , "-c" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ [{"type": "var", "name": "pkg-config"}] + , [ { "type": "join_cmd" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "args", "default": []} + , ["--cflags", {"type": "var", "name": "name"}] + ] + } + } + ] + , [">"] + , [ { "type": "join_cmd" + , "$1": {"type": "var", "name": "cflags-filename"} + } + ] + ] + } + } + ] + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "cflags-filename"}] + } + } + ] + , [ "compile-args" + , { "type": "foreach_map" + , "var_key": "flag-file" + , "range": {"type": "var", "name": "cflags-files"} + , "body": + {"type": "join", "$1": ["@", {"type": "var", "name": "flag-file"}]} + } + ] + , [ "ldflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".ldflags"]} + ] + , [ "ldflags-files" + , { "type": "ACTION" + , "inputs": {"type": "var", "name": "shell TOOLCHAIN"} + , "cmd": + [ {"type": "var", "name": "sh"} + , "-c" + , { "type": "join" + , "separator": " " + , "$1": + { "type": "++" + , "$1": + [ [{"type": "var", "name": "pkg-config"}] + , [ { "type": "join_cmd" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "args", "default": []} + , ["--libs", {"type": "var", "name": "name"}] + ] + } + } + ] + , [">", "ldflags.raw"] + ] + } + } + ] + , "env": {"type": "var", "name": "ENV"} + , "outs": ["ldflags.raw"] + } + ] + , [ "add_rpath" + , { "type": "let*" + , "bindings": [["fieldname", "add_rpath"], ["location", "add_rpath"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , [ "ldflags-files" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "add_rpath"} + , {"type": "var", "name": "ldflags-files"} + , {"type": "var", "name": "shell TOOLCHAIN"} + ] + } + , "cmd": + [ {"type": "var", "name": "sh"} + , "-c" + , { "type": "join" + , "separator": " " + , "$1": + [ "./add_rpath $(cat ldflags.raw)" + , ">" + , { "type": "join_cmd" + , "$1": {"type": "var", "name": "ldflags-filename"} + } + ] + } + ] + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "ldflags-filename"}] + } + } + ] + , [ "link-args" + , { "type": "foreach_map" + , "var_key": "flag-file" + , "range": {"type": "var", "name": "ldflags-files"} + , "body": + {"type": "join", "$1": ["@", {"type": "var", "name": "flag-file"}]} + } + ] + , ["package", {"type": "env", "vars": ["cflags-files", "ldflags-files"]}] + , ["compile-deps", {"type": "empty_map"}] + , ["link-deps", {"type": "empty_map"}] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": + ["compile-deps", "compile-args", "link-deps", "link-args", "package"] + } + } + } + } +} diff --git a/rules/CC/pkgconfig/RULES b/rules/CC/pkgconfig/RULES new file mode 100644 index 0000000..363136f --- /dev/null +++ b/rules/CC/pkgconfig/RULES @@ -0,0 +1,131 @@ +{ "defaults": + { "doc": ["A rule to provide defaults for pkgconfig"] + , "string_fields": ["pkg-config", "PATH", "PKG_CONFIG_PATH"] + , "target_fields": ["base"] + , "field_doc": + { "pkg-config": + ["The name of the pkg-config binary to use, potentially with full path."] + , "PATH": ["Additional paths to add to \"PATH\" when calling pkg-config"] + , "PKG_CONFIG_PATH": + [ "Additional paths to add to \"PKG_CONFIG_PATH\" when calling pkg-config" + ] + , "base": ["Other targets (using the same rule) to inherit from."] + } + , "imports": + { "base-provides": ["./", "..", "defaults-base-provides"] + , "base-provides-++": ["./", "..", "defaults-base-provides-++"] + , "nub_left": ["", "nub_left"] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["pkg-config", {"type": "FIELD", "name": "pkg-config"}] + , ["provider", "pkg-config"] + , [ "pkg-config" + , { "type": "if" + , "cond": {"type": "var", "name": "pkg-config"} + , "then": {"type": "var", "name": "pkg-config"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["PATH", {"type": "FIELD", "name": "PATH"}] + , ["provider", "PATH"] + , [ "PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + , ["PKG_CONFIG_PATH", {"type": "FIELD", "name": "PKG_CONFIG_PATH"}] + , ["provider", "PKG_CONFIG_PATH"] + , [ "PKG_CONFIG_PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PKG_CONFIG_PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PKG_CONFIG_PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PKG_CONFIG_PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + {"type": "env", "vars": ["pkg-config", "PATH", "PKG_CONFIG_PATH"]} + } + } + } +, "system_library": + { "doc": ["A system library via pkg-config"] + , "string_fields": ["name", "args", "stage"] + , "implicit": + { "defaults": [["./", "..", "defaults"]] + , "shell defaults": [["shell", "defaults"]] + , "add_rpath": ["add_rpath"] + , "pkgconfig defaults": ["defaults"] + } + , "config_vars": ["PKG_CONFIG_ARGS", "ENV"] + , "field_doc": + { "name": ["The pkg-config name of the library."] + , "args": + [ "Additional pkg-config arguments (e.g., \"--define-prefix\" or" + , "\"--static\"), appended to the config variable \"PKG_CONFIG_ARGS\"." + ] + , "stage": ["The stage of the internally created flag files."] + , "defaults": ["The C/C++ toolchain to use"] + , "pkgconfig defaults": ["The pkgconfig configuration to use"] + } + , "config_doc": + { "PKG_CONFIG_ARGS": + [ "Additional pkg-config arguments (e.g., \"--define-prefix\" or" + , "\"--static\")." + ] + , "ENV": + [ "The environment for any action generated. May contain colon-separated" + , "\"PKG_CONFIG_PATH\" for looking up pkg-config files; this variable," + , "as well as \"PATH\", is prefixed by the values provided in" + , "the \"defaults\"." + ] + } + , "imports": {"pkgconfig result": "pkgconfig result"} + , "expression": + { "type": "let*" + , "bindings": + [ [ "name" + , { "type": "assert_non_empty" + , "msg": "system_library requires non-empty name" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , [ "args" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PKG_CONFIG_ARGS", "default": []} + , {"type": "FIELD", "name": "args"} + ] + } + ] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "pkgconfig result"} + } + } +} diff --git a/rules/CC/pkgconfig/TARGETS b/rules/CC/pkgconfig/TARGETS new file mode 100644 index 0000000..705d1d7 --- /dev/null +++ b/rules/CC/pkgconfig/TARGETS @@ -0,0 +1 @@ +{"defaults": {"type": "defaults"}} diff --git a/rules/CC/pkgconfig/add_rpath b/rules/CC/pkgconfig/add_rpath new file mode 100755 index 0000000..d020f2b --- /dev/null +++ b/rules/CC/pkgconfig/add_rpath @@ -0,0 +1,24 @@ +#!/bin/sh +# Copyright 2023 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. + +for x in "$@" +do + echo -n '' "$x" + case $x in + -L*) echo -n '' -Xlinker -rpath -Xlinker "$(expr "$x" : "..\(.*\)")" + ;; + esac +done +echo diff --git a/rules/CC/prebuilt/EXPRESSIONS b/rules/CC/prebuilt/EXPRESSIONS new file mode 100644 index 0000000..b84e494 --- /dev/null +++ b/rules/CC/prebuilt/EXPRESSIONS @@ -0,0 +1,503 @@ +{ "check-file-ending": + { "doc": ["Returns true if all file names end with the given ending."] + , "vars": ["files", "ending", "invert"] + , "vars_doc": + { "files": ["Artifact map that contains the files."] + , "ending": ["The ending to check for (without \".\")."] + , "invert": ["Invert condition to file name not ending with \"ending\"."] + } + , "expression": + { "type": "and" + , "$1": + { "type": "foreach" + , "var": "file" + , "range": {"type": "keys", "$1": {"type": "var", "name": "files"}} + , "body": + { "type": "let*" + , "bindings": + [ [ "is-equal" + , { "type": "==" + , "$1": {"type": "var", "name": "file"} + , "$2": + { "type": "change_ending" + , "$1": {"type": "var", "name": "file"} + , "ending": + { "type": "join" + , "$1": [".", {"type": "var", "name": "ending"}] + } + } + } + ] + ] + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "invert", "default": false} + , "then": + { "type": "if" + , "cond": {"type": "var", "name": "is-equal"} + , "then": false + , "else": true + } + , "else": {"type": "var", "name": "is-equal"} + } + } + } + } + } +, "check-libs-non-static": + { "doc": + [ "Returns true if all libs are non-static libraries or false otherwise." + , "Throws if static and non-static libraries are mixed." + ] + , "vars": ["libs"] + , "vars_doc": {"libs": ["List of artifact maps that contain the libraries."]} + , "imports": {"check-file-ending": "check-file-ending"} + , "expression": + { "type": "let*" + , "bindings": + [ ["files", {"type": "map_union", "$1": {"type": "var", "name": "libs"}}] + , [ "static" + , { "type": "let*" + , "bindings": [["ending", "a"]] + , "body": {"type": "CALL_EXPRESSION", "name": "check-file-ending"} + } + ] + , [ "shared" + , { "type": "let*" + , "bindings": [["ending", "a"], ["invert", true]] + , "body": {"type": "CALL_EXPRESSION", "name": "check-file-ending"} + } + ] + ] + , "body": + { "type": "if" + , "cond": + { "type": "or" + , "$1": + [ {"type": "var", "name": "static"} + , {"type": "var", "name": "shared"} + ] + } + , "then": {"type": "var", "name": "shared"} + , "else": + { "type": "fail" + , "msg": "Prebuilt library types (static/shared) may not be mixed." + } + } + } + } +, "prebuilt result": + { "vars": + [ "ENV" + , "name" + , "version" + , "stage" + , "cflags" + , "ldflags" + , "libs" + , "hdrs" + , "config_reader" + , "pkg-configs" + , "deps-fieldnames" + ] + , "imports": + { "check-libs-non-static": "check-libs-non-static" + , "compile-deps": ["./", "..", "compile-deps"] + , "compile-args-deps": ["./", "..", "compile-args-deps"] + , "link-deps": ["./", "..", "link-deps"] + , "link-args-deps": ["./", "..", "link-args-deps"] + , "run-libs-deps": ["./", "..", "run-libs-deps"] + , "run-libs-args-deps": ["./", "..", "run-libs-args-deps"] + , "cflags-files-deps": ["./", "..", "cflags-files-deps"] + , "ldflags-files-deps": ["./", "..", "ldflags-files-deps"] + , "default-ENV": ["./", "..", "default-ENV"] + , "default-PATH": ["./", "..", "default-PATH"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "shared" + , {"type": "CALL_EXPRESSION", "name": "check-libs-non-static"} + ] + , [ "lib-stage" + , { "type": "if" + , "cond": {"type": "var", "name": "shared"} + , "then": "." + , "else": {"type": "var", "name": "stage"} + } + ] + , [ "staged-libs" + , { "type": "foreach" + , "var": "lib" + , "range": {"type": "var", "name": "libs"} + , "body": + { "type": "to_subdir" + , "subdir": {"type": "var", "name": "lib-stage"} + , "flat": true + , "msg": "prebuilt libraries may not overlap" + , "$1": {"type": "var", "name": "lib"} + } + } + ] + , [ "link-args" + , { "type": "if" + , "cond": {"type": "var", "name": "shared"} + , "then": [] + , "else": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "libs" + , "range": {"type": "var", "name": "staged-libs"} + , "body": {"type": "keys", "$1": {"type": "var", "name": "libs"}} + } + } + } + ] + , [ "run-libs-args" + , { "type": "if" + , "cond": {"type": "var", "name": "shared"} + , "then": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "libs" + , "range": {"type": "var", "name": "staged-libs"} + , "body": {"type": "keys", "$1": {"type": "var", "name": "libs"}} + } + } + } + ] + , [ "libs" + , { "type": "disjoint_map_union" + , "msg": "prebuilt libraries may not overlap" + , "$1": {"type": "var", "name": "staged-libs"} + } + ] + , [ "hdrs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "disjoint_map_union" + , "msg": "prebuilt headers may not overlap" + , "$1": {"type": "var", "name": "hdrs"} + } + } + ] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "cflags"} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + } + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , [ "link-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "link-args"} + , {"type": "CALL_EXPRESSION", "name": "link-args-deps"} + ] + } + } + ] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , { "type": "nub_right" + , "$1": + { "type": "++" + , "$1": + [ {"type": "var", "name": "run-libs-args"} + , {"type": "var", "name": "ldflags"} + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + } + } + ] + , [ "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"}] + } + ] + } + } + } + ] + } + ] + , [ "main-pkg-config" + , { "type": "foldl" + , "range": + { "type": "++" + , "$1": + { "type": "foreach" + , "var": "configs" + , "range": {"type": "var", "name": "pkg-configs", "default": []} + , "body": + {"type": "keys", "$1": {"type": "var", "name": "configs"}} + } + } + , "start": null + , "accum_var": "name" + , "var": "config" + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "name"} + , "then": {"type": "var", "name": "name"} + , "else": {"type": "var", "name": "config"} + } + } + ] + , [ "reader-inputs" + , { "type": "to_subdir" + , "subdir": "lib" + , "$1": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "libs"} + , {"type": "var", "name": "link-deps"} + , {"type": "var", "name": "run-libs"} + , { "type": "to_subdir" + , "subdir": "pkgconfig" + , "flat": true + , "$1": + { "type": "map_union" + , "$1": {"type": "var", "name": "pkg-configs", "default": []} + } + } + ] + } + } + ] + , [ "pc-args" + , { "type": "if" + , "cond": {"type": "var", "name": "shared"} + , "then": [] + , "else": ["--static"] + } + ] + , [ "cflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".cflags"]} + ] + , [ "cflags-file" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "pkg-configs"} + , "then": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "config_reader"} + , {"type": "var", "name": "reader-inputs"} + ] + } + , "cmd": + { "type": "++" + , "$1": + [ [ "./config_reader" + , {"type": "var", "name": "cflags-filename"} + , {"type": "var", "name": "main-pkg-config"} + ] + , {"type": "var", "name": "pc-args"} + ] + } + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "cflags-filename"}] + } + , "else": {"type": "empty_map"} + } + } + ] + , [ "cflags-files" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + , {"type": "var", "name": "cflags-file"} + ] + } + ] + , [ "compile-args" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "compile-args"} + , { "type": "if" + , "cond": {"type": "var", "name": "cflags-file"} + , "then": + [ { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ ["@"] + , { "type": "keys" + , "$1": {"type": "var", "name": "cflags-file"} + } + ] + } + } + ] + } + ] + } + ] + , [ "ldflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".ldflags"]} + ] + , [ "ldflags-file" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "pkg-configs"} + , "then": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "config_reader"} + , {"type": "var", "name": "reader-inputs"} + ] + } + , "cmd": + { "type": "++" + , "$1": + [ [ "./config_reader" + , {"type": "var", "name": "ldflags-filename"} + , {"type": "var", "name": "main-pkg-config"} + ] + , {"type": "var", "name": "pc-args"} + ] + } + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "ldflags-filename"}] + } + , "else": {"type": "empty_map"} + } + } + ] + , [ "ldflags-files" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + , {"type": "var", "name": "ldflags-file"} + ] + } + ] + , [ "run-libs" + , { "type": "map_union" + , "$1": + [ { "type": "if" + , "cond": {"type": "var", "name": "shared"} + , "then": {"type": "var", "name": "libs"} + , "else": {"type": "empty_map"} + } + , {"type": "var", "name": "run-libs"} + ] + } + ] + , [ "run-libs-args" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "run-libs-args"} + , { "type": "if" + , "cond": {"type": "var", "name": "ldflags-file"} + , "then": + [ { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ ["@"] + , { "type": "keys" + , "$1": {"type": "var", "name": "ldflags-file"} + } + ] + } + } + ] + } + ] + } + ] + , [ "package" + , { "type": "let*" + , "bindings": + [ ["name", {"type": "var", "name": "name"}] + , [ "version" + , { "type": "if" + , "cond": {"type": "var", "name": "version"} + , "then": + { "type": "join" + , "separator": "." + , "$1": {"type": "var", "name": "version"} + } + , "else": null + } + ] + ] + , "body": + { "type": "env" + , "vars": ["name", "version", "cflags-files", "ldflags-files"] + } + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "libs"} + , "runfiles": {"type": "var", "name": "hdrs"} + , "provides": + { "type": "map_union" + , "$1": + [ { "type": "env" + , "vars": + [ "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + ] + } + ] + } + } + } + } +} diff --git a/rules/CC/prebuilt/RULES b/rules/CC/prebuilt/RULES new file mode 100644 index 0000000..16f9f26 --- /dev/null +++ b/rules/CC/prebuilt/RULES @@ -0,0 +1,147 @@ +{ "library": + { "doc": ["A prebuilt C++ library"] + , "target_fields": ["lib", "hdrs", "deps", "pkg-config"] + , "string_fields": + ["name", "version", "stage", "defines", "cflags", "ldflags"] + , "implicit": + { "defaults": [["./", "..", "defaults"]] + , "config_reader": [["CC", "prebuilt/read_pkgconfig.py"]] + } + , "config_vars": ["ENV"] + , "field_doc": + { "name": + [ "The name of the library (without leading \"lib\" or trailing file name" + , "extension), also used as name for pkg-config files." + ] + , "version": + [ "The library version, used for pkg-config files. Individual version" + , "components are joined with \".\"." + ] + , "lib": + [ "The actual prebuilt library. If multiple libraries are specified" + , "(e.g., one depends on the other), the order matters. Library types" + , "cannot be mixed. All of them have to be either static or shared." + ] + , "hdrs": ["Any public header files of the library."] + , "deps": ["Any other libraries this library depends upon."] + , "stage": + [ "The logical location of all header and source files, as well as the" + , "resulting library file. Individual directory components are joined" + , "with \"/\"." + ] + , "defines": + [ "List of defines set for this target and its consumers." + , "Each list entry will be prepended by \"-D\"." + ] + , "cflags": + ["List of compile flags set for this target and its consumers."] + , "ldflags": + ["Additional linker flags (typically for linking system libraries)."] + , "pkg-config": + [ "Pkg-config file for optional infer of public cflags and ldflags. If" + , "multiple files are specified (e.g., one depends on the other), the" + , "first one is used as entry. Note that if this field is non-empty the" + , "tool \"pkg-config\" must be available in \"PATH\", which is taken" + , "from [\"CC\", \"defaults\"] or the \"ENV\" variable." + ] + } + , "artifacts_doc": + [ "The actual library (libname.a or libname.so). Only static libraries are" + , "staged in the specified directory." + ] + , "runfiles_doc": ["The public headers staged to the specified directory."] + , "provides_doc": + { "compile-deps": + [ "Map of artifacts specifying any additional files that, besides the" + , "runfiles have to be present in compile actions of targets depending on" + , "this library." + ] + , "link-deps": + [ "Map of artifacts specifying any additional files that, besides the artifacts," + , "have to be present in a link actions of targets depending on this library" + ] + , "run-libs": + [ "Map of artifacts specifying all files, including the artifacts of this" + , "library if shared, that have to be present in link actions of targets" + , "depending on this library." + ] + , "link-args": + [ "List of strings that have to be added to the command line for linking" + , "actions in targets depending on this library." + ] + , "run-libs-args": + [ "List of strings that have to be added to the command line for linking" + , "runtime libraries in targets depending on this library." + ] + , "compile-args": + [ "List of strings that have to be added to the command line for compile" + , "actions in targets depending on this library." + ] + } + , "imports": + { "artifacts": ["./", "../..", "field_artifacts"] + , "artifacts_list": ["./", "../..", "field_artifacts_list"] + , "stage_field": ["", "stage_singleton_field"] + , "prebuilt result": "prebuilt result" + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "name" + , { "type": "assert_non_empty" + , "msg": "name is required for prebuilt library" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["version", {"type": "FIELD", "name": "version"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "cflags" + , { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "cflags"} + , { "type": "foreach" + , "var": "def" + , "range": {"type": "FIELD", "name": "defines"} + , "body": + {"type": "join", "$1": ["-D", {"type": "var", "name": "def"}]} + } + ] + } + ] + , ["ldflags", {"type": "FIELD", "name": "ldflags"}] + , [ "libs" + , { "type": "let*" + , "bindings": [["fieldname", "lib"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + ] + , [ "hdrs" + , { "type": "let*" + , "bindings": [["fieldname", "hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + ] + , [ "config_reader" + , { "type": "let*" + , "bindings": + [["fieldname", "config_reader"], ["location", "config_reader"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "pkg-configs" + , { "type": "let*" + , "bindings": [["fieldname", "pkg-config"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + ] + , ["deps-fieldnames", ["deps"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "prebuilt result"} + } + } +} diff --git a/rules/CC/prebuilt/read_pkgconfig.py b/rules/CC/prebuilt/read_pkgconfig.py new file mode 100755 index 0000000..115c305 --- /dev/null +++ b/rules/CC/prebuilt/read_pkgconfig.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright 2023 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 os +import subprocess +import sys +from pathlib import Path +from typing import Dict, List, Set + + +def run_pkgconfig(args: List[str], env: Dict[str, str]) -> str: + result = subprocess.run(["pkg-config"] + args, env=env, capture_output=True) + if result.returncode != 0: + print(result.stderr.decode("utf-8"), file=sys.stderr) + exit(1) + return result.stdout.decode("utf-8").strip() + + +def read_ldflags(pkg: str, args: List[str], env: Dict[str, str]) -> str: + def libname(filename: str) -> str: + return filename.split(".")[0] + + local_libs = { + libname(f) + for it in os.walk(".") for f in it[2] if f.startswith("lib") + } + + link_flags = run_pkgconfig(args + ["--libs-only-l", pkg], env).split(" ") + + # deduplicate, keep right-most + seen: Set[str] = set() + link_flags = [ + f for f in link_flags[::-1] if f not in seen and not seen.add(f) + ][::-1] + + def is_local(flag: str) -> bool: + if not flag.startswith("-l"): + return False + lib = libname(flag[3:]) if flag.startswith("-l:") else f"lib{flag[2:]}" + return lib in local_libs + + return " ".join([f for f in link_flags if not is_local(f)]) + + +def read_pkgconfig() -> None: + if len(sys.argv) < 3: + print(f"usage: read_pkgconfig OUT_NAME PC_FILE [PC_ARGS...]") + exit(1) + + name = sys.argv[1] + pkg = Path(sys.argv[2]).stem + args = sys.argv[3:] + env = dict(os.environ, PKG_CONFIG_PATH="./lib/pkgconfig") + + if name.endswith(".cflags"): + data = run_pkgconfig(args + ["--cflags-only-other", pkg], env) + else: + data = read_ldflags(pkg, args, env) + + with open(f"{name}", 'w') as f: + f.write(data) + + +if __name__ == "__main__": + read_pkgconfig() diff --git a/rules/CC/proto/EXPRESSIONS b/rules/CC/proto/EXPRESSIONS new file mode 100644 index 0000000..0b44506 --- /dev/null +++ b/rules/CC/proto/EXPRESSIONS @@ -0,0 +1,489 @@ +{ "default-PROTOC": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "PROTOC"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-PROTOCFLAGS": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "PROTOCFLAGS"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-LDFLAGS": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "LDFLAGS"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-GRPC_PLUGIN": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "GRPC_PLUGIN"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-ENV": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "../..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "ENV"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-PATH": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "../..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "PATH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-TOOLCHAIN": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "../..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "proto-defaults"] + , ["provider", "TOOLCHAIN"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-NON_SYSTEM_TOOLS": + { "vars": ["defaults-transition"] + , "expression": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": "proto-defaults"} + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": "NON_SYSTEM_TOOLS" + , "transition": + { "type": "var" + , "name": "defaults-transition" + , "default": {"type": "empty_map"} + } + , "default": {"type": "empty_map"} + } + } + } + } +, "protoc-deps": + { "imports": {"map_provider": ["./", "../..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": [["fieldname", "deps"], ["provider", "protoc-deps"]] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "protoc-compile": + { "vars": + [ "CXX" + , "CXXFLAGS" + , "ADD_CXXFLAGS" + , "AR" + , "ENV" + , "DEBUG" + , "name" + , "stage" + , "service support" + , "public-fieldnames" + , "private-fieldnames" + ] + , "imports": + { "stage": ["", "stage_singleton_field"] + , "result": ["./", "..", "lib result"] + , "runfiles": ["./", "../..", "field_runfiles"] + , "artifacts_list": ["./", "../..", "field_artifacts_list"] + , "protoc-deps": "protoc-deps" + , "default-PROTOC": "default-PROTOC" + , "default-PROTOCFLAGS": "default-PROTOCFLAGS" + , "default-LDFLAGS": "default-LDFLAGS" + , "default-GRPC_PLUGIN": "default-GRPC_PLUGIN" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["pure C", false] + , ["TOOLCHAIN_DIR", "toolchain"] + , ["TOOLCHAIN", {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"}] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , [ "PROTOC" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "PROTOC" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-PROTOC"} + ] + } + } + ] + , [ "GRPC_PLUGIN" + , { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "GRPC_PLUGIN" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-GRPC_PLUGIN"} + ] + } + } + ] + , [ "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" + } + ] + , [ "protoc-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"}] + } + ] + } + } + } + ] + } + ] + , ["protoc-deps", {"type": "CALL_EXPRESSION", "name": "protoc-deps"}] + , [ "proto srcs" + , { "type": "disjoint_map_union" + , "msg": "Sources may not conflict" + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + ] + , [ "all proto srcs" + , { "type": "disjoint_map_union" + , "msg": "Conflict with proto files of dependencies" + , "$1": + [ {"type": "var", "name": "protoc-deps"} + , {"type": "var", "name": "proto srcs"} + ] + } + ] + , [ "staged srcs" + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "proto srcs"} + } + ] + , [ "staged all proto srcs" + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "all proto srcs"} + } + ] + , [ "outs" + , { "type": "++" + , "$1": + { "type": "foreach" + , "var": "f" + , "range": + {"type": "keys", "$1": {"type": "var", "name": "staged srcs"}} + , "body": + { "type": "++" + , "$1": + [ [ { "type": "change_ending" + , "$1": {"type": "var", "name": "f"} + , "ending": ".pb.h" + } + , { "type": "change_ending" + , "$1": {"type": "var", "name": "f"} + , "ending": ".pb.cc" + } + ] + , { "type": "if" + , "cond": {"type": "var", "name": "service support"} + , "then": + [ { "type": "change_ending" + , "$1": {"type": "var", "name": "f"} + , "ending": ".grpc.pb.h" + } + , { "type": "change_ending" + , "$1": {"type": "var", "name": "f"} + , "ending": ".grpc.pb.cc" + } + ] + , "else": [] + } + ] + } + } + } + ] + , [ "cmd" + , { "type": "++" + , "$1": + [ [{"type": "var", "name": "PROTOC"}] + , {"type": "CALL_EXPRESSION", "name": "default-PROTOCFLAGS"} + , ["--proto_path=work", "--cpp_out=work"] + , { "type": "if" + , "cond": {"type": "var", "name": "service support"} + , "then": + [ "--grpc_out=work" + , { "type": "join" + , "$1": + [ "--plugin=protoc-gen-grpc=" + , {"type": "var", "name": "GRPC_PLUGIN"} + ] + } + ] + , "else": [] + } + , {"type": "keys", "$1": {"type": "var", "name": "staged srcs"}} + ] + } + ] + , [ "generated" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "staged all proto srcs"} + , {"type": "var", "name": "TOOLCHAIN"} + ] + } + , "outs": {"type": "var", "name": "outs"} + , "cmd": {"type": "var", "name": "cmd"} + , "env": {"type": "var", "name": "protoc-ENV"} + } + ] + , [ "srcs" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "name" + , "range": + {"type": "keys", "$1": {"type": "var", "name": "proto srcs"}} + , "body": + { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": + { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".pb.cc" + } + , "value": + { "type": "lookup" + , "map": {"type": "var", "name": "generated"} + , "key": + { "type": "join" + , "$1": + [ "work/" + , { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".pb.cc" + } + ] + } + } + } + , { "type": "if" + , "cond": {"type": "var", "name": "service support"} + , "then": + { "type": "singleton_map" + , "key": + { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".grpc.pb.cc" + } + , "value": + { "type": "lookup" + , "map": {"type": "var", "name": "generated"} + , "key": + { "type": "join" + , "$1": + [ "work/" + , { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".grpc.pb.cc" + } + ] + } + } + } + , "else": {"type": "empty_map"} + } + ] + } + } + } + ] + , [ "hdrs" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "name" + , "range": + {"type": "keys", "$1": {"type": "var", "name": "proto srcs"}} + , "body": + { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": + { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".pb.h" + } + , "value": + { "type": "lookup" + , "map": {"type": "var", "name": "generated"} + , "key": + { "type": "join" + , "$1": + [ "work/" + , { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".pb.h" + } + ] + } + } + } + , { "type": "if" + , "cond": {"type": "var", "name": "service support"} + , "then": + { "type": "singleton_map" + , "key": + { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".grpc.pb.h" + } + , "value": + { "type": "lookup" + , "map": {"type": "var", "name": "generated"} + , "key": + { "type": "join" + , "$1": + [ "work/" + , { "type": "change_ending" + , "$1": {"type": "var", "name": "name"} + , "ending": ".grpc.pb.h" + } + ] + } + } + } + , "else": {"type": "empty_map"} + } + ] + } + } + } + ] + , ["private-hdrs", {"type": "empty_map"}] + , [ "extra-provides" + , { "type": "singleton_map" + , "key": "protoc-deps" + , "value": {"type": "var", "name": "all proto srcs"} + } + ] + , ["cflags", []] + , ["private-cflags", []] + , [ "private-ldflags" + , {"type": "CALL_EXPRESSION", "name": "default-LDFLAGS"} + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "result"} + } + } +} diff --git a/rules/CC/proto/RULES b/rules/CC/proto/RULES new file mode 100644 index 0000000..6fb0f40 --- /dev/null +++ b/rules/CC/proto/RULES @@ -0,0 +1,375 @@ +{ "defaults": + { "doc": + [ "A rule to provide protoc/GRPC defaults." + , "Used to implement [\"CC/proto\", \"defaults\"] for CC proto libraries" + , "and [\"CC/proto\", \"service defaults\"] for CC proto service libraries" + , "(GRPC)." + ] + , "target_fields": ["base", "toolchain", "deps"] + , "string_fields": + [ "PROTOC" + , "PROTOCFLAGS" + , "ADD_PROTOCFLAGS" + , "LDFLAGS" + , "ADD_LDFLAGS" + , "GRPC_PLUGIN" + , "PATH" + ] + , "config_vars": ["ARCH", "HOST_ARCH", "DEBUG"] + , "field_doc": + { "base": + [ "Other targets (using the same rule) to inherit values from. If" + , "multiple targets are specified, for values that are overwritten (see" + , "documentation of other fields) the last specified value wins." + ] + , "toolchain": + [ "Optional toolchain directory. A collection of artifacts that provide" + , "the protobuf compiler and the GRPC plugin (if needed). Note that only" + , "artifacts of the specified targets are considered (no runfiles etc.)." + , "Specifying this field extends artifacts from \"base\"." + ] + , "deps": + [ "Optional CC libraries the resulting CC proto libraries implicitly" + , "depend on. Those are typically \"libprotobuf\" for CC proto libraries" + , "and \"libgrpc++\" for CC proto service libraries. Specifying this" + , "field extends dependencies from \"base\"." + ] + , "PROTOC": + [ "The proto compiler. If \"toolchain\" is empty, this field's value is" + , "considered the proto compiler name that is looked up in \"PATH\". If" + , "\"toolchain\" is non-empty, this field's value is assumed to be the" + , "relative path to the proto compiler in \"toolchain\". Specifying this" + , "field overwrites values from \"base\"." + ] + , "GRPC_PLUGIN": + [ "The GRPC plugin for the proto compiler. If \"toolchain\" is empty," + , "this field's value is considered to be the absolute system path to the" + , "plugin. If \"toolchain\" is non-empty, this field's value is assumed" + , "to be the relative path to the plugin in \"toolchain\". Specifying" + , "this field overwrites values from \"base\"." + ] + , "PROTOCFLAGS": + [ "Protobuf compiler flags. Specifying this field overwrites values from" + , "\"base\"." + ] + , "ADD_PROTOCFLAGS": + [ "Additional protobuf compiler flags. Specifying this field extends" + , "values from \"base\"." + ] + , "LDFLAGS": + [ "Linker flags for linking the final CC library. Specifying this field" + , "overwrites values from \"base\"." + ] + , "ADD_LDFLAGS": + [ "Additional linker flags for linking the final CC library. Specifying" + , "this field extends values from \"base\"." + ] + , "PATH": + [ "Path for looking up the proto compiler. Individual paths are joined" + , "with \":\". Specifying this field extends values from \"base\"." + ] + } + , "config_doc": + { "ARCH": + [ "The unqualified architecture. Is taken as a default for \"HOST_ARCH\"" + , "and \"TARGET_ARCH\" if not set." + ] + , "HOST_ARCH": + ["The architecture on which the build actions are carried out."] + , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + } + , "imports": + { "base-provides": ["./", "..", "defaults-base-provides"] + , "base-provides-++": ["./", "..", "defaults-base-provides-++"] + , "base-provides-list": ["./", "..", "defaults-base-provides-list"] + , "artifacts_list": ["", "field_artifacts_list"] + , "nub_left": ["", "nub_left"] + , "compile-deps": ["CC", "compile-deps"] + , "compile-args-deps": ["CC", "compile-args-deps"] + , "link-deps": ["CC", "link-deps"] + , "link-args-deps": ["CC", "link-args-deps"] + , "run-libs-deps": ["CC", "run-libs-deps"] + , "run-libs-args-deps": ["CC", "run-libs-args-deps"] + , "cflags-files-deps": ["CC", "cflags-files-deps"] + , "ldflags-files-deps": ["CC", "ldflags-files-deps"] + , "for host": ["transitions", "for host"] + , "debug-deps": ["CC", "debug-deps"] + } + , "config_transitions": + {"toolchain": [{"type": "CALL_EXPRESSION", "name": "for host"}]} + , "expression": + { "type": "let*" + , "bindings": + [ ["PROTOC", {"type": "FIELD", "name": "PROTOC"}] + , ["PROTOCFLAGS", {"type": "FIELD", "name": "PROTOCFLAGS"}] + , ["LDFLAGS", {"type": "FIELD", "name": "LDFLAGS"}] + , ["GRPC_PLUGIN", {"type": "FIELD", "name": "GRPC_PLUGIN"}] + , ["PATH", {"type": "FIELD", "name": "PATH"}] + , ["provider", "PROTOC"] + , [ "PROTOC" + , { "type": "if" + , "cond": {"type": "var", "name": "PROTOC"} + , "then": {"type": "var", "name": "PROTOC"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "PROTOCFLAGS"] + , [ "PROTOCFLAGS" + , { "type": "if" + , "cond": {"type": "var", "name": "PROTOCFLAGS"} + , "then": {"type": "var", "name": "PROTOCFLAGS"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + , ["provider", "LDFLAGS"] + , [ "LDFLAGS" + , { "type": "if" + , "cond": {"type": "var", "name": "LDFLAGS"} + , "then": {"type": "var", "name": "LDFLAGS"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + , ["provider", "GRPC_PLUGIN"] + , [ "GRPC_PLUGIN" + , { "type": "if" + , "cond": {"type": "var", "name": "GRPC_PLUGIN"} + , "then": {"type": "var", "name": "GRPC_PLUGIN"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "PATH"] + , [ "PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + , ["provider", "ENV"] + , ["default", {"type": "empty_map"}] + , ["ENV", {"type": "CALL_EXPRESSION", "name": "base-provides"}] + , ["provider", "NON_SYSTEM_TOOLS"] + , ["default", {"type": "empty_map"}] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ [{"type": "CALL_EXPRESSION", "name": "base-provides"}] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "PROTOC"} + , "then": + [ { "type": "singleton_map" + , "key": "PROTOC" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "if" + , "cond": {"type": "FIELD", "name": "GRPC_PLUGIN"} + , "then": + [ { "type": "singleton_map" + , "key": "GRPC_PLUGIN" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + ] + } + } + ] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "toolchain artifacts may not overlap" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": + { "type": "let*" + , "bindings": + [ ["fieldname", "toolchain"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "for host"} + ] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + ] + } + } + ] + , [ "PROTOCFLAGS" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PROTOCFLAGS"} + , {"type": "FIELD", "name": "ADD_PROTOCFLAGS"} + ] + } + ] + , [ "LDFLAGS" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "LDFLAGS"} + , {"type": "FIELD", "name": "ADD_LDFLAGS"} + ] + } + ] + , ["deps-fieldnames", ["base", "deps"]] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , ["link-args", {"type": "CALL_EXPRESSION", "name": "link-args-deps"}] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + , [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , ["package", {"type": "env", "vars": ["cflags-files", "ldflags-files"]}] + , [ "debug-srcs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "let*" + , "bindings": [["deps-provider", "debug-srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , "else": {"type": "empty_map"} + } + ] + , [ "debug-hdrs" + , { "type": "if" + , "cond": {"type": "var", "name": "DEBUG"} + , "then": + { "type": "map_union" + , "$1": + [ { "type": "let*" + , "bindings": [["deps-provider", "debug-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "debug-deps"} + } + , {"type": "var", "name": "compile-deps"} + ] + } + , "else": {"type": "empty_map"} + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": + [ "PROTOC" + , "PROTOCFLAGS" + , "LDFLAGS" + , "GRPC_PLUGIN" + , "PATH" + , "ENV" + , "TOOLCHAIN" + , "NON_SYSTEM_TOOLS" + , "compile-deps" + , "compile-args" + , "link-deps" + , "link-args" + , "run-libs" + , "run-libs-args" + , "package" + , "debug-srcs" + , "debug-hdrs" + ] + } + } + } + } +, "library": + { "doc": + [ "A C++ library, generated from proto files." + , "" + , "This rule usually is used to bind anonymous targets generated from" + , "proto libraries." + ] + , "string_fields": ["name", "stage"] + , "target_fields": ["srcs", "deps"] + , "config_vars": ["CXX", "CXXFLAGS", "ADD_CXXFLAGS", "AR", "ENV", "DEBUG"] + , "implicit": + {"defaults": [["./", "..", "defaults"]], "proto-defaults": ["defaults"]} + , "imports": {"protoc-compile": "protoc-compile"} + , "expression": + { "type": "let*" + , "bindings": + [ ["name", {"type": "join", "$1": {"type": "FIELD", "name": "name"}}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , ["public-fieldnames", ["deps", "proto-defaults", "defaults"]] + , ["private-fieldnames", ["deps", "proto-defaults", "defaults"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "protoc-compile"} + } + } +, "service library": + { "doc": + [ "A service C++ library, generated from proto files." + , "" + , "Calls protoc with gRPC plugin to additionally generate gRPC services" + , "from proto libraries." + ] + , "string_fields": ["name", "stage"] + , "target_fields": ["srcs", "deps"] + , "config_vars": ["CXX", "CXXFLAGS", "ADD_CXXFLAGS", "AR", "ENV", "DEBUG"] + , "implicit": + { "defaults": [["./", "..", "defaults"]] + , "proto-defaults": ["service defaults"] + } + , "imports": {"protoc-compile": "protoc-compile"} + , "expression": + { "type": "let*" + , "bindings": + [ ["service support", true] + , ["name", {"type": "join", "$1": {"type": "FIELD", "name": "name"}}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , ["public-fieldnames", ["deps", "proto-defaults", "defaults"]] + , ["private-fieldnames", ["deps", "proto-defaults", "defaults"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "protoc-compile"} + } + } +} diff --git a/rules/CC/proto/TARGETS b/rules/CC/proto/TARGETS new file mode 100644 index 0000000..87bebd0 --- /dev/null +++ b/rules/CC/proto/TARGETS @@ -0,0 +1,16 @@ +{ "defaults": + { "type": ["CC/proto", "defaults"] + , "PROTOC": ["protoc"] + , "PATH": ["/bin", "/usr/bin"] + , "deps": ["libprotobuf"] + } +, "service defaults": + { "type": ["CC/proto", "defaults"] + , "base": ["defaults"] + , "GRPC_PLUGIN": ["/usr/bin/grpc_cpp_plugin"] + , "deps": ["libgrpc++"] + } +, "libprotobuf": + {"type": ["CC/pkgconfig", "system_library"], "name": ["protobuf"]} +, "libgrpc++": {"type": ["CC/pkgconfig", "system_library"], "name": ["grpc++"]} +} diff --git a/rules/CC/test/EXPRESSIONS b/rules/CC/test/EXPRESSIONS new file mode 100644 index 0000000..a10fc2b --- /dev/null +++ b/rules/CC/test/EXPRESSIONS @@ -0,0 +1,327 @@ +{ "run_test": + { "doc": + [ "Build and run a CC test binary using the provided runner." + , "" + , "Note that if variable RUNS_PER_TEST contains a non-false value, a" + , "summarizer must be provided." + ] + , "vars": + [ "ARCH" + , "HOST_ARCH" + , "TARGET_ARCH" + , "ARCH_DISPATCH" + , "TEST_SUMMARY_EXECUTION_PROPERTIES" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ENV" + , "TEST_ENV" + , "TIMEOUT_SCALE" + , "CC_TEST_LAUNCHER" + , "RUNS_PER_TEST" + , "name" + , "pure C" + , "stage" + , "srcs" + , "private-hdrs" + , "private-defines" + , "private-cflags" + , "private-ldflags" + , "defaults-transition" + , "deps-transition" + , "deps-fieldnames" + , "runner" + , "runner-data" + , "test-args" + , "test-data" + , "summarizer" + ] + , "imports": + { "artifacts": ["./", "../..", "field_artifacts"] + , "runfiles": ["./", "../..", "field_runfiles"] + , "compile-deps": ["./", "..", "compile-deps"] + , "compile-args-deps": ["./", "..", "compile-args-deps"] + , "link-deps": ["./", "..", "link-deps"] + , "link-args-deps": ["./", "..", "link-args-deps"] + , "run-libs-deps": ["./", "..", "run-libs-deps"] + , "run-libs-args-deps": ["./", "..", "run-libs-args-deps"] + , "cflags-files-deps": ["./", "..", "cflags-files-deps"] + , "ldflags-files-deps": ["./", "..", "ldflags-files-deps"] + , "binary": ["./", "..", "bin artifact"] + , "host transition": ["transitions", "for host"] + , "target properties": ["transitions", "target properties"] + , "stage": ["./", "../..", "stage_singleton_field"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "cflags-files" + , {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + ] + , ["compile-deps", {"type": "CALL_EXPRESSION", "name": "compile-deps"}] + , [ "compile-args" + , { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "def" + , "range": + {"type": "var", "name": "private-defines", "default": []} + , "body": + {"type": "join", "$1": ["-D", {"type": "var", "name": "def"}]} + } + , {"type": "var", "name": "private-cflags", "default": []} + , {"type": "CALL_EXPRESSION", "name": "compile-args-deps"} + ] + } + ] + , [ "ldflags-files" + , {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + ] + , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] + , [ "link-args" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "link-args-deps"} + , {"type": "var", "name": "private-ldflags", "default": []} + ] + } + ] + , ["run-libs", {"type": "CALL_EXPRESSION", "name": "run-libs-deps"}] + , [ "run-libs-args" + , {"type": "CALL_EXPRESSION", "name": "run-libs-args-deps"} + ] + , ["binary", {"type": "CALL_EXPRESSION", "name": "binary"}] + , [ "staged test binary" + , { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "range": {"type": "var", "name": "binary"} + , "var_val": "binary" + , "body": + { "type": "singleton_map" + , "key": "test" + , "value": {"type": "var", "name": "binary"} + } + } + } + ] + , [ "test-args" + , { "type": "singleton_map" + , "key": "test-args.json" + , "value": + { "type": "BLOB" + , "data": + { "type": "json_encode" + , "$1": {"type": "var", "name": "test-args", "default": []} + } + } + } + ] + , [ "test-launcher" + , { "type": "singleton_map" + , "key": "test-launcher.json" + , "value": + { "type": "BLOB" + , "data": + { "type": "json_encode" + , "$1": + {"type": "var", "name": "CC_TEST_LAUNCHER", "default": []} + } + } + } + ] + , [ "test-name" + , { "type": "join" + , "separator": "/" + , "$1": + [{"type": "var", "name": "stage"}, {"type": "var", "name": "name"}] + } + ] + , [ "test input" + , { "type": "map_union" + , "$1": + [ { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "test-data"} + } + , {"type": "var", "name": "runner"} + , { "type": "var" + , "name": "runner-data" + , "default": {"type": "empty_map"} + } + , {"type": "var", "name": "test-args"} + , {"type": "var", "name": "test-launcher"} + , {"type": "var", "name": "staged test binary"} + , {"type": "var", "name": "run-libs"} + ] + } + ] + , [ "target properties" + , {"type": "CALL_EXPRESSION", "name": "target properties"} + ] + ] + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "RUNS_PER_TEST"} + , "else": + { "type": "let*" + , "bindings": + [ [ "test-results" + , { "type": "ACTION" + , "outs": + ["result", "stdout", "stderr", "time-start", "time-stop"] + , "inputs": {"type": "var", "name": "test input"} + , "cmd": ["./runner"] + , "env": + { "type": "var" + , "name": "TEST_ENV" + , "default": {"type": "empty_map"} + } + , "may_fail": ["test"] + , "fail_message": + { "type": "join" + , "$1": + ["CC test ", {"type": "var", "name": "test-name"}, " failed"] + } + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 1.0} + , "execution properties": + {"type": "var", "name": "target properties"} + } + ] + , [ "runfiles" + , { "type": "singleton_map" + , "key": {"type": "var", "name": "name"} + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "test-results"}} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "test-results"} + , "runfiles": {"type": "var", "name": "runfiles"} + } + } + , "then": + { "type": "let*" + , "bindings": + [ [ "attempts" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "ATTEMPT" + , "range": + { "type": "range" + , "$1": {"type": "var", "name": "RUNS_PER_TEST"} + } + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "ATTEMPT"} + , "value": + { "type": "TREE" + , "$1": + { "type": "ACTION" + , "outs": + [ "result" + , "stdout" + , "stderr" + , "time-start" + , "time-stop" + ] + , "inputs": + { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": "ATTEMPT" + , "value": + { "type": "BLOB" + , "data": {"type": "var", "name": "ATTEMPT"} + } + } + , {"type": "var", "name": "test input"} + ] + } + , "cmd": ["./runner"] + , "env": + { "type": "var" + , "name": "TEST_ENV" + , "default": {"type": "empty_map"} + } + , "may_fail": ["test"] + , "no_cache": ["test"] + , "fail_message": + { "type": "join" + , "$1": + [ "CC test " + , {"type": "var", "name": "test-name"} + , " failed (Run" + , {"type": "var", "name": "ATTEMPT"} + , ")" + ] + } + , "timeout scaling": + { "type": "var" + , "name": "TIMEOUT_SCALE" + , "default": 1.0 + } + , "execution properties": + {"type": "var", "name": "target properties"} + } + } + } + } + } + ] + , [ "summary" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "attempts"} + , {"type": "var", "name": "summarizer"} + ] + } + , "outs": + ["stdout", "stderr", "result", "time-start", "time-stop"] + , "cmd": ["./summarizer"] + , "execution properties": + { "type": "var" + , "name": "TEST_SUMMARY_EXECUTION_PROPERTIES" + , "default": {"type": "empty_map"} + } + } + ] + , [ "artifacts" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "summary"} + , { "type": "singleton_map" + , "key": "work" + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "attempts"}} + } + ] + } + ] + , [ "runfiles" + , { "type": "singleton_map" + , "key": {"type": "var", "name": "name"} + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "artifacts"}} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "artifacts"} + , "runfiles": {"type": "var", "name": "runfiles"} + } + } + } + } + } +} diff --git a/rules/CC/test/RULES b/rules/CC/test/RULES new file mode 100644 index 0000000..1dac31b --- /dev/null +++ b/rules/CC/test/RULES @@ -0,0 +1,255 @@ +{ "test": + { "doc": ["A test written in C++"] + , "tainted": ["test"] + , "target_fields": ["srcs", "private-hdrs", "private-deps", "data"] + , "string_fields": + [ "name" + , "args" + , "stage" + , "pure C" + , "private-defines" + , "private-cflags" + , "private-ldflags" + ] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "TARGET_ARCH" + , "CC" + , "CXX" + , "CFLAGS" + , "CXXFLAGS" + , "LDFLAGS" + , "ADD_CFLAGS" + , "ADD_CXXFLAGS" + , "ADD_LDFLAGS" + , "ENV" + , "BUILD_POSITION_INDEPENDENT" + , "TEST_ENV" + , "TIMEOUT_SCALE" + , "CC_TEST_LAUNCHER" + , "RUNS_PER_TEST" + , "ARCH_DISPATCH" + , "TEST_SUMMARY_EXECUTION_PROPERTIES" + ] + , "implicit": + { "defaults": [["./", "..", "defaults"]] + , "runner": ["runner"] + , "summarizer": [["./", "../../shell/test", "summarizer"]] + } + , "field_doc": + { "name": + [ "The name of the test" + , "" + , "Used to name the test binary as well as for staging the test result" + ] + , "args": ["Command line arguments for the test binary"] + , "srcs": + [ "The sources of the test binary" + , "" + , "The resulting test binary is run in an environment where it can assume" + , "that the environment variable TEST_TMPDIR points to a" + , "directory that may be used exclusively by this test." + , "For convenience, the environment variable TMPDIR is also set to TEST_TMPDIR." + , "" + , "This running of the test is carried out by the implicit dependency" + , "on the target \"runner\". By setting this target in the target layer" + , "of this rules repository (instead of letting it default to the" + , "respective file), the C/C++ test environment can be modified globally." + ] + , "private-hdrs": + [ "Any additional header files that need to be present when compiling" + , "the test binary." + ] + , "private-defines": + [ "List of defines set for source files local to this target." + , "Each list entry will be prepended by \"-D\"." + ] + , "private-cflags": + ["List of compile flags set for source files local to this target."] + , "private-ldflags": + [ "Additional linker flags for linking external libraries (not built" + , "by this tool, typically system libraries)." + ] + , "stage": + [ "The logical location of all header and source files." + , "Individual directory components are joined with \"/\"." + ] + , "data": ["Any files the test binary needs access to when running"] + , "defaults": ["The C/C++ toolchain to use"] + , "runner": + [ "The test runner which starts the actual test binary after providing" + , "the respective environment. The runner also takes care of capturing" + , "stdout/stderr and timing information." + ] + , "summarizer": + [ "Tool to aggregate the results of individual test runs (for flakyness" + , "detection) to an overall test result." + ] + } + , "config_doc": + { "CC": ["The name of the C compiler to be used."] + , "CXX": ["The name of the C++ compiler to be used."] + , "CFLAGS": + [ "The flags for CC 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" + ] + , "LDFLAGS": + [ "The linker flags do 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" + ] + , "ADD_LDFLAGS": + [ "The linker flags to add to the default ones" + , "taken from the [\"CC\", \"defaults\"] target" + ] + , "ENV": ["The environment for any action generated."] + , "BUILD_POSITION_INDEPENDENT": ["Build with -fPIC."] + , "TEST_ENV": ["The environment for executing the test runner."] + , "TIMEOUT_SCALE": + ["Factor on how to scale the timeout for this test. Defaults to 1.0."] + , "CC_TEST_LAUNCHER": + [ "List of strings representing the launcher that is prepend to the" + , "command line for running the test binary." + ] + , "RUNS_PER_TEST": + [ "The number of times the test should be run in order to detect flakyness." + , "If set, no test action will be taken from cache." + , "" + , "Test runs are summarized by the [\"shell/test\", \"summarizer\"] that" + , "is also used by shell tests." + ] + , "TARGET_ARCH": + [ "The architecture to build the test for." + , "" + , "Will only be honored, if that architecture is available in the" + , "ARCH_DISPATCH map. Otherwise, the test will be built for and run" + , "on the host architecture." + ] + , "ARCH_DISPATCH": + [ "Map of architectures to execution properties that ensure execution" + , "on that architecture. Only the actual test binary will be run with" + , "the specified execution properties (i.e., on the target architecture);" + , "all building will be done on the host architecture." + ] + , "TEST_SUMMARY_EXECUTION_PROPERTIES": + [ "Additional remote-execution properties for the test-summarizing action" + , "in case RUNS_PER_TEST is set; defaults to the empty map." + ] + } + , "artifacts_doc": + [ "result: the result of this test (\"PASS\" or \"FAIL\"); useful for" + , " generating test reports." + , "stdout/stderr: Any output the invocation of the test binary produced on" + , " the respective file descriptor" + , "time-start/time-stop: The time (decimally coded) in seconds since the" + , " epoch when the test invocation started and ended." + ] + , "runfiles_doc": + [ "A tree consisting of the artifacts staged at the name of the test." + , "As the built-in \"install\" rule only takes the runfiles of its" + , "\"private-deps\" argument, this gives an easy way of defining test" + , "suites." + ] + , "imports": + { "artifacts": ["./", "../..", "field_artifacts"] + , "runfiles": ["./", "../..", "field_runfiles"] + , "host transition": ["transitions", "maybe for host"] + , "stage": ["./", "../..", "stage_singleton_field"] + , "run_test": "run_test" + } + , "config_transitions": + { "defaults": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + , "private-deps": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + , "data": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + , "runner": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "name" + , { "type": "assert_non_empty" + , "msg": "A non-empty name has to be provided for binaries" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["pure C", {"type": "FIELD", "name": "pure C"}] + , [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "srcs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , [ "private-hdrs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "private-hdrs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + } + ] + , ["host-trans", {"type": "CALL_EXPRESSION", "name": "host transition"}] + , ["defaults-transition", {"type": "var", "name": "host-trans"}] + , ["deps-transition", {"type": "var", "name": "host-trans"}] + , ["deps-fieldnames", ["private-deps", "defaults"]] + , [ "runner" + , { "type": "let*" + , "bindings": + [ ["fieldname", "runner"] + , ["location", "runner"] + , ["transition", {"type": "var", "name": "host-trans"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , ["test-args", {"type": "FIELD", "name": "args", "default": []}] + , [ "test-data" + , { "type": "let*" + , "bindings": + [ ["fieldname", "data"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": + { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "runfiles"} + , {"type": "CALL_EXPRESSION", "name": "artifacts"} + ] + } + } + ] + , [ "summarizer" + , { "type": "let*" + , "bindings": + [["fieldname", "summarizer"], ["location", "summarizer"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "run_test"} + } + } +} diff --git a/rules/CC/test/TARGETS b/rules/CC/test/TARGETS new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/rules/CC/test/TARGETS @@ -0,0 +1 @@ +{} diff --git a/rules/CC/test/runner b/rules/CC/test/runner new file mode 100755 index 0000000..45a1bee --- /dev/null +++ b/rules/CC/test/runner @@ -0,0 +1,69 @@ +#!/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 os +import subprocess +import time + +time_start: float = time.time() +time_stop: float = 0 +result: str = "UNKNOWN" +stderr: str = "" +stdout: str = "" + + +def dump_results() -> None: + with open("result", "w") as f: + f.write("%s\n" % (result, )) + with open("time-start", "w") as f: + f.write("%d\n" % (time_start, )) + with open("time-stop", "w") as f: + f.write("%d\n" % (time_stop, )) + with open("stdout", "w") as f: + f.write("%s\n" % (stdout, )) + with open("stderr", "w") as f: + f.write("%s\n" % (stderr, )) + + +dump_results() + +TEMP_DIR = os.path.realpath("scratch") +os.makedirs(TEMP_DIR, exist_ok=True) + +WORK_DIR = os.path.realpath("work") +os.makedirs(WORK_DIR, exist_ok=True) + +ENV = dict(os.environ, TEST_TMPDIR=TEMP_DIR, TMPDIR=TEMP_DIR) + +with open('test-launcher.json') as f: + test_launcher = json.load(f) + +with open('test-args.json') as f: + test_args = json.load(f) + +ret = subprocess.run(test_launcher + ["../test"] + test_args, + cwd=WORK_DIR, + env=ENV, + capture_output=True) + +time_stop = time.time() +result = "PASS" if ret.returncode == 0 else "FAIL" +stdout = ret.stdout.decode("utf-8") +stderr = ret.stderr.decode("utf-8") + +dump_results() + +if result != "PASS": exit(1) diff --git a/rules/EXPRESSIONS b/rules/EXPRESSIONS new file mode 100644 index 0000000..52a381f --- /dev/null +++ b/rules/EXPRESSIONS @@ -0,0 +1,243 @@ +{ "field_artifacts_list": + { "doc": ["Query list of artifacts from target_field's targets"] + , "vars": ["fieldname", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + } + , "expression": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "x"} + , "transition": + {"type": "var", "name": "transition", "default": {"type": "empty_map"}} + } + } + } +, "field_artifacts": + { "doc": ["Query and merge artifacts from target_field's targets"] + , "vars": ["fieldname", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + } + , "imports": {"artifacts_list": "field_artifacts_list"} + , "expression": + { "type": "disjoint_map_union" + , "msg": + ["artifacts", {"type": "var", "name": "fieldname"}, "must not overlap"] + , "$1": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } +, "field_runfiles_list": + { "doc": ["Query list of runfiles from target_field's targets"] + , "vars": ["fieldname", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + } + , "expression": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "DEP_RUNFILES" + , "dep": {"type": "var", "name": "x"} + , "transition": + {"type": "var", "name": "transition", "default": {"type": "empty_map"}} + } + } + } +, "field_runfiles": + { "doc": ["Query and merge runfiles from target_field's targets"] + , "vars": ["fieldname", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + } + , "imports": {"runfiles_list": "field_runfiles_list"} + , "expression": + { "type": "disjoint_map_union" + , "msg": + ["runfiles", {"type": "var", "name": "fieldname"}, "must not overlap"] + , "$1": {"type": "CALL_EXPRESSION", "name": "runfiles_list"} + } + } +, "field_provider_list": + { "doc": ["Query list of providers from targets' provides map"] + , "vars": ["fieldname", "provider", "transition", "default"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "provider": ["The name of the map provider in the provides map."] + , "transition": ["The optional configuration transition for the targets."] + , "default": ["The default if the provider was not found (default: [])."] + } + , "expression": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": {"type": "var", "name": "provider"} + , "transition": + {"type": "var", "name": "transition", "default": {"type": "empty_map"}} + , "default": {"type": "var", "name": "default", "default": []} + } + } + } +, "field_map_provider": + { "doc": ["Query and merge map-providers from targets' provides map"] + , "vars": ["fieldname", "provider", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "provider": ["The name of the map provider in the provides map."] + , "transition": ["The optional configuration transition for the targets."] + } + , "imports": {"provider_list": "field_provider_list"} + , "expression": + { "type": "disjoint_map_union" + , "msg": + ["Overlapping entries in provider", {"type": "var", "name": "provider"}] + , "$1": + { "type": "let*" + , "bindings": [["default", {"type": "empty_map"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "provider_list"} + } + } + } +, "field_list_provider": + { "doc": ["Query and merge list-providers from targets' provides map"] + , "vars": ["fieldname", "provider", "transition"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "provider": ["The name of the list provider in the provides map."] + , "transition": ["The optional configuration transition for the targets."] + } + , "imports": {"provider_list": "field_provider_list"} + , "expression": + {"type": "++", "$1": {"type": "CALL_EXPRESSION", "name": "provider_list"}} + } +, "action_env": + { "vars": ["ENV"] + , "expression": + { "type": "map_union" + , "$1": + [ {"type": "singleton_map", "key": "PATH", "value": "/bin:/usr/bin"} + , {"type": "var", "name": "ENV", "default": {"type": "empty_map"}} + ] + } + } +, "stage_singleton_field": + { "vars": ["fieldname", "transition", "location"] + , "expression": + { "type": "assert_non_empty" + , "msg": + ["No artifact specified in field", {"type": "var", "name": "fieldname"}] + , "$1": + { "type": "disjoint_map_union" + , "msg": + [ "Expecting (essentially) a single artifact in field" + , {"type": "var", "name": "fieldname"} + ] + , "$1": + { "type": "foreach" + , "var": "src" + , "range": + {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "disjoint_map_union" + , "$1": + { "type": "foreach" + , "var": "artifact" + , "range": + { "type": "values" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "src"} + , "transition": + { "type": "var" + , "name": "transition" + , "default": {"type": "empty_map"} + } + } + } + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "location"} + , "value": {"type": "var", "name": "artifact"} + } + } + } + } + } + } + } +, "stage_artifact_to_singleton_field": + { "vars": ["artifact", "fieldname", "transition"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "location" + , { "type": "++" + , "$1": + { "type": "foreach" + , "var": "src" + , "range": + {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "keys" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "src"} + , "transition": + { "type": "var" + , "name": "transition" + , "default": {"type": "empty_map"} + } + } + } + } + } + ] + , [ "staged_artifact" + , { "type": "foreach_map" + , "range": {"type": "var", "name": "artifact"} + , "var_val": "val" + , "body": + { "type": "foreach" + , "range": {"type": "var", "name": "location"} + , "var": "pos" + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "pos"} + , "value": {"type": "var", "name": "val"} + } + } + } + ] + ] + , "body": + { "type": "disjoint_map_union" + , "$1": {"type": "++", "$1": {"type": "var", "name": "staged_artifact"}} + } + } + } +, "nub_left": + { "doc": ["Removes all but the leftmost duplicate from the list."] + , "vars": ["list"] + , "vars_doc": {"list": ["The list to remove duplicates from."]} + , "expression": + { "type": "let*" + , "bindings": + [ ["list", {"type": "reverse", "$1": {"type": "var", "name": "list"}}] + , ["list", {"type": "nub_right", "$1": {"type": "var", "name": "list"}}] + , ["list", {"type": "reverse", "$1": {"type": "var", "name": "list"}}] + ] + , "body": {"type": "var", "name": "list"} + } + } +} diff --git a/rules/data/EXPRESSIONS b/rules/data/EXPRESSIONS new file mode 100644 index 0000000..929eaf8 --- /dev/null +++ b/rules/data/EXPRESSIONS @@ -0,0 +1,113 @@ +{ "field_artifacts_without": + { "doc": + [ "Query and merge artifacts from target_field's targets," + , "leaving out the specified logical paths." + ] + , "vars": ["fieldname", "transition", "exclude"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + , "exclude": ["The logical paths to exclude"] + } + , "expression": + { "type": "disjoint_map_union" + , "msg": + [ "artifacts" + , {"type": "var", "name": "fieldname"} + , "must not overlap after dropping paths" + , {"type": "var", "name": "exclude"} + ] + , "$1": + { "type": "foreach" + , "var": "x" + , "range": + {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "range": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "x"} + , "transition": + { "type": "var" + , "name": "transition" + , "default": {"type": "empty_map"} + } + } + , "body": + { "type": "if" + , "cond": + { "type": "lookup" + , "key": {"type": "var", "name": "_"} + , "map": {"type": "var", "name": "exclude"} + } + , "then": {"type": "empty_map"} + , "else": + { "type": "singleton_map" + , "key": {"type": "var", "name": "_"} + , "value": {"type": "var", "name": "$_"} + } + } + } + } + } + } + } +, "field_runfiles_without": + { "doc": + [ "Query and merge runfiles from target_field's targets," + , "leaving out the specified logical paths." + ] + , "vars": ["fieldname", "transition", "exclude"] + , "vars_doc": + { "fieldname": ["The name of the target_field to query."] + , "transition": ["The optional configuration transition for the targets."] + , "exclude": ["The logical paths to exclude"] + } + , "expression": + { "type": "disjoint_map_union" + , "msg": + [ "artifacts" + , {"type": "var", "name": "fieldname"} + , "must not overlap after dropping paths" + , {"type": "var", "name": "exclude"} + ] + , "$1": + { "type": "foreach" + , "var": "x" + , "range": + {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "range": + { "type": "DEP_RUNFILES" + , "dep": {"type": "var", "name": "x"} + , "transition": + { "type": "var" + , "name": "transition" + , "default": {"type": "empty_map"} + } + } + , "body": + { "type": "if" + , "cond": + { "type": "lookup" + , "key": {"type": "var", "name": "_"} + , "map": {"type": "var", "name": "exclude"} + } + , "then": {"type": "empty_map"} + , "else": + { "type": "singleton_map" + , "key": {"type": "var", "name": "_"} + , "value": {"type": "var", "name": "$_"} + } + } + } + } + } + } + } +} diff --git a/rules/data/RULES b/rules/data/RULES new file mode 100644 index 0000000..ab5c92e --- /dev/null +++ b/rules/data/RULES @@ -0,0 +1,138 @@ +{ "staged": + { "doc": ["Stage data to a logical subdirectory."] + , "target_fields": ["srcs", "deps"] + , "string_fields": ["stage", "drop"] + , "field_doc": + { "srcs": ["The files to be staged"] + , "stage": + [ "The logical directory to stage the files to." + , "Individual directory components are joined with \"/\"." + ] + , "deps": + [ "Targets of with their runfiles should be added as well." + , "Their staging is not changed." + ] + , "drop": + [ "List of paths to drop from (each of) the \"srcs\" targets" + , "before joining and staging. In this way, GLOB constructs can" + , "be used is \"srcs\"." + ] + } + , "artifacts_doc": + [ "The runfiles and artifacts of the \"srcs\" targets, leaving out" + , "the ones with logical path in \"drop\", staged to the directory" + , "specified in \"stage\" together the runfiles of the targets" + , "specied in the field \"deps\" (in their original location)." + ] + , "runfiles_doc": ["Same as artifacts"] + , "imports": + { "runfiles": ["./", "..", "field_runfiles"] + , "artifacts": ["./", "..", "field_artifacts"] + , "runfiles w/o": "field_runfiles_without" + , "artifacts w/o": "field_artifacts_without" + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "exclude" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "range": {"type": "FIELD", "name": "drop"} + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "_"} + , "value": true + } + } + } + ] + , [ "srcs" + , { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": + { "type": "map_union" + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "exclude"} + , "then": + [ {"type": "CALL_EXPRESSION", "name": "runfiles w/o"} + , {"type": "CALL_EXPRESSION", "name": "artifacts w/o"} + ] + , "else": + [ {"type": "CALL_EXPRESSION", "name": "runfiles"} + , {"type": "CALL_EXPRESSION", "name": "artifacts"} + ] + } + } + } + ] + , [ "staged" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": {"type": "var", "name": "srcs"} + } + ] + , [ "dep stage" + , { "type": "let*" + , "bindings": [["fieldname", "deps"]] + , "body": {"type": "CALL_EXPRESSION", "name": "runfiles"} + } + ] + , [ "total" + , { "type": "disjoint_map_union" + , "msg": "Conflict between staged data and dependencies" + , "$1": + [ {"type": "var", "name": "dep stage"} + , {"type": "var", "name": "staged"} + ] + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "total"} + , "runfiles": {"type": "var", "name": "total"} + } + } + } +, "overlay": + { "doc": + ["Overlay the artifacts of \"deps\" targets in a latest-wins fashion."] + , "target_fields": ["deps"] + , "field_doc": {"deps": ["The targets of which to overlay the artifacts"]} + , "artifacts_doc": + [ "Artifacts of the targets specified in \"deps\". For conflicting" + , "logical paths, the artifact is taken from the latest target (in" + , "the \"deps\" field) that defines that logical path" + ] + , "runfiles_doc": ["Same as artifacts"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "all" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "dep" + , "range": {"type": "FIELD", "name": "deps"} + , "body": + {"type": "DEP_ARTIFACTS", "dep": {"type": "var", "name": "dep"}} + } + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "all"} + , "runfiles": {"type": "var", "name": "all"} + } + } + } +} diff --git a/rules/patch/EXPRESSIONS b/rules/patch/EXPRESSIONS new file mode 100644 index 0000000..7f8ce19 --- /dev/null +++ b/rules/patch/EXPRESSIONS @@ -0,0 +1,77 @@ +{ "default-PATCH": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "patch-defaults"] + , ["provider", "PATCH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-ENV": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "patch-defaults"] + , ["provider", "ENV"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-PATH": + { "vars": ["defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "patch-defaults"] + , ["provider", "PATH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "default-TOOLCHAIN": + { "vars": ["defaults-transition"] + , "imports": {"map_provider": ["./", "..", "field_map_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "patch-defaults"] + , ["provider", "TOOLCHAIN"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , ["default", {"type": "empty_map"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } +, "default-NON_SYSTEM_TOOLS": + { "vars": ["defaults-transition"] + , "expression": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": "patch-defaults"} + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": "NON_SYSTEM_TOOLS" + , "transition": + { "type": "var" + , "name": "defaults-transition" + , "default": {"type": "empty_map"} + } + , "default": {"type": "empty_map"} + } + } + } + } +} diff --git a/rules/patch/RULES b/rules/patch/RULES new file mode 100644 index 0000000..c55de58 --- /dev/null +++ b/rules/patch/RULES @@ -0,0 +1,355 @@ +{ "defaults": + { "doc": + [ "A rule to provide defaults." + , "All targets take their defaults for PATCH from the target" + , "[\"patch\", \"defaults\"]. This is probably the only sensible" + , "use of this rule. As targets form a different root, the defaults" + , "can be provided without changing this directory." + ] + , "target_fields": ["base", "toolchain"] + , "string_fields": ["PATCH", "PATH", "SYSTEM_TOOLS"] + , "field_doc": + { "base": ["Other targets (using the same rule) to inherit values from."] + , "toolchain": + [ "Optional toolchain directory. A collection of artifacts that provide" + , "the tool PATCH. Note that only artifacts of" + , "the specified targets are considered (no runfiles etc.). Specifying" + , "this field extends artifacts from \"base\"." + ] + , "PATCH": ["The patch binary to use"] + , "SYSTEM_TOOLS": + [ "List of tools (\"PATCH\") that should be taken from" + , "the system instead of from \"toolchain\" (if specified)." + ] + , "PATH": + [ "Path for looking up the compilers. Individual paths are joined" + , "with \":\". Specifying this field extends values from \"base\"." + ] + } + , "config_vars": ["ARCH", "HOST_ARCH"] + , "imports": + { "base-provides": ["CC", "defaults-base-provides"] + , "base-provides-++": ["CC", "defaults-base-provides-++"] + , "base-provides-list": ["CC", "defaults-base-provides-list"] + , "artifacts_list": ["", "field_artifacts_list"] + , "nub_left": ["", "nub_left"] + , "for host": ["transitions", "for host"] + } + , "config_transitions": + {"toolchain": [{"type": "CALL_EXPRESSION", "name": "for host"}]} + , "expression": + { "type": "let*" + , "bindings": + [ ["PATCH", {"type": "FIELD", "name": "PATCH"}] + , ["PATH", {"type": "FIELD", "name": "PATH"}] + , ["provider", "PATCH"] + , [ "PATCH" + , { "type": "if" + , "cond": {"type": "var", "name": "PATCH"} + , "then": {"type": "var", "name": "PATCH"} + , "else": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , ["provider", "PATH"] + , [ "PATH" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "PATH"} + , {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + ] + } + ] + , [ "PATH" + , { "type": "let*" + , "bindings": [["list", {"type": "var", "name": "PATH"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "nub_left"} + } + ] + , ["provider", "ENV"] + , ["default", {"type": "empty_map"}] + , ["ENV", {"type": "CALL_EXPRESSION", "name": "base-provides"}] + , ["provider", "NON_SYSTEM_TOOLS"] + , ["default", {"type": "empty_map"}] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ [{"type": "CALL_EXPRESSION", "name": "base-provides"}] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "PATCH"} + , "then": + [ { "type": "singleton_map" + , "key": "PATCH" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "SYSTEM_TOOLS"} + , "var": "tool" + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "tool"} + , "value": false + } + } + ] + } + } + ] + , ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "toolchain artifacts may not overlap" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + , { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": + { "type": "let*" + , "bindings": + [ ["fieldname", "toolchain"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "for host"} + ] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + ] + } + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": ["PATCH", "PATH", "ENV", "TOOLCHAIN", "NON_SYSTEM_TOOLS"] + } + } + } + } +, "file": + { "doc": ["Replace a file, logically in place, by a patched version"] + , "target_fields": ["src", "patch"] + , "config_vars": ["PATCH", "ENV"] + , "implicit": + {"patch-defaults": ["defaults"], "defaults": [["shell", "defaults"]]} + , "field_doc": + { "src": + [ "The single source file to patch, typically an explicit file reference." + ] + , "patch": ["The patch to apply."] + , "patch-defaults": ["The patch binary (and toolchain) to use"] + , "defaults": ["The shell toolchain to use"] + } + , "artifacts_doc": + ["The patched file, staged to the position the of the original file"] + , "runfiles_doc": ["Same as artifacts"] + , "imports": + { "stage_field": ["./", "..", "stage_singleton_field"] + , "stage_artifact": ["./", "..", "stage_artifact_to_singleton_field"] + , "default-PATCH": "default-PATCH" + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-ENV": "default-ENV" + , "default-PATH": "default-PATH" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + , "sh-TOOLCHAIN": ["CC", "default-TOOLCHAIN"] + , "sh-PATH": ["CC", "default-PATH"] + , "sh": ["shell", "sh"] + , "list_provider": ["./", "..", "field_list_provider"] + } + , "expression": + { "type": "let*" + , "bindings": + [ ["TOOLCHAIN_DIR", "toolchain"] + , [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "Staging conflict between patch and sh toolchain" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"} + , {"type": "CALL_EXPRESSION", "name": "sh-TOOLCHAIN"} + ] + } + ] + , [ "TOOLCHAIN" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": {"type": "var", "name": "TOOLCHAIN"} + } + ] + , [ "bin dirs" + , { "type": "let*" + , "bindings": [["fieldname", "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"} + ] + , [ "PATCH" + , { "type": "var" + , "name": "PATCH" + , "default": + { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": + { "type": "lookup" + , "key": "PATCH" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + ["./", {"type": "var", "name": "TOOLCHAIN_DIR"}, "/"] + } + , {"type": "CALL_EXPRESSION", "name": "default-PATCH"} + ] + } + } + } + ] + , [ "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": "CALL_EXPRESSION", "name": "sh-PATH"} + , {"type": "var", "name": "bin dirs"} + , { "type": "if" + , "cond": {"type": "var", "name": "ENV_PATH"} + , "then": [{"type": "var", "name": "ENV_PATH"}] + } + ] + } + } + } + ] + } + ] + , ["sh", {"type": "CALL_EXPRESSION", "name": "sh"}] + , [ "orig" + , { "type": "let*" + , "bindings": [["fieldname", "src"], ["location", "orig"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "patch" + , { "type": "let*" + , "bindings": [["fieldname", "patch"], ["location", "patch"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "script" + , { "type": "singleton_map" + , "key": "run_patch.sh" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + [ "set -e" + , "cp orig patched" + , "chmod +w patched" + , { "type": "join" + , "$1": + [ { "type": "join_cmd" + , "$1": + [ {"type": "var", "name": "PATCH", "default": "patch"} + , "patched" + , "patch" + ] + } + , " >log || (cat log && exit 1)" + ] + } + ] + } + } + } + ] + , [ "inputs" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "orig"} + , {"type": "var", "name": "patch"} + , {"type": "var", "name": "TOOLCHAIN"} + , {"type": "var", "name": "script"} + ] + } + ] + , [ "patched" + , { "type": "ACTION" + , "inputs": {"type": "var", "name": "inputs"} + , "outs": ["patched"] + , "cmd": [{"type": "var", "name": "sh"}, "./run_patch.sh"] + , "env": {"type": "var", "name": "ENV"} + } + ] + , [ "result" + , { "type": "let*" + , "bindings": + [ ["artifact", {"type": "var", "name": "patched"}] + , ["fieldname", "src"] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_artifact"} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "result"} + , "runfiles": {"type": "var", "name": "result"} + } + } + } +} diff --git a/rules/patch/TARGETS b/rules/patch/TARGETS new file mode 100644 index 0000000..9a0ad77 --- /dev/null +++ b/rules/patch/TARGETS @@ -0,0 +1,6 @@ +{ "defaults": + { "type": ["patch", "defaults"] + , "PATCH": ["patch"] + , "PATH": ["/bin", "/usr/bin"] + } +} diff --git a/rules/proto/RULES b/rules/proto/RULES new file mode 100644 index 0000000..a9152dd --- /dev/null +++ b/rules/proto/RULES @@ -0,0 +1,99 @@ +{ "library": + { "doc": + [ "A proto library as abstract data structure." + , "" + , "Such a library does not produce any artifacts itself, but it can be" + , "used as a dependency for various language-specific rules." + ] + , "target_fields": ["srcs", "deps"] + , "string_fields": ["stage", "name", "service"] + , "field_doc": + { "srcs": ["The proto files for this library"] + , "deps": ["Any other proto library this library depends on"] + , "stage": + [ "The directory to stage the source files to." + , "Directory components are joined by \"/\"." + ] + , "name": ["The name of the (abstract) library."] + , "service": + [ "If non empty, generate a service library (with access to \"rpc\"" + , "definitions) instead of a regular one." + ] + } + , "artifacts_doc": ["None"] + , "runfiles_doc": ["None"] + , "provides_doc": + { "proto": + [ "A list containing a single target-graph node with the definition of" + , "this proto library. The node types generated are \"library\" and" + , "\"service library\"." + ] + } + , "imports": + { "artifacts_list": ["./", "..", "field_artifacts_list"] + , "list_provider": ["./", "..", "field_list_provider"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "FIELD", "name": "stage"} + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "Have to provide a name, unique in the stage" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , [ "srcs" + , [ { "type": "VALUE_NODE" + , "$1": + { "type": "RESULT" + , "artifacts": + { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "disjoint_map_union" + , "msg": "Sources have to be conflict free" + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "srcs"]] + , "body": + {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + } + } + } + } + ] + ] + , [ "deps" + , { "type": "let*" + , "bindings": [["fieldname", "deps"], ["provider", "proto"]] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + ] + , ["name", [{"type": "var", "name": "name"}]] + , ["stage", [{"type": "var", "name": "stage"}]] + , [ "proto" + , [ { "type": "ABSTRACT_NODE" + , "node_type": + { "type": "if" + , "cond": {"type": "FIELD", "name": "service"} + , "then": "service library" + , "else": "library" + } + , "target_fields": {"type": "env", "vars": ["srcs", "deps"]} + , "string_fields": {"type": "env", "vars": ["name", "stage"]} + } + ] + ] + ] + , "body": + {"type": "RESULT", "provides": {"type": "env", "vars": ["proto"]}} + } + } +} diff --git a/rules/shell/EXPRESSIONS b/rules/shell/EXPRESSIONS new file mode 100644 index 0000000..34a5c92 --- /dev/null +++ b/rules/shell/EXPRESSIONS @@ -0,0 +1,171 @@ +{ "default-sh": + { "vars": ["defaults-transition", "fieldname"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ [ "fieldname" + , {"type": "var", "name": "fieldname", "default": "defaults"} + ] + , ["provider", "sh"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + , [ "provided sh" + , { "type": "join" + , "$1": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + ] + , [ "sh" + , { "type": "if" + , "cond": {"type": "var", "name": "provided sh"} + , "then": {"type": "var", "name": "provided sh"} + , "else": "sh" + } + ] + ] + , "body": {"type": "var", "name": "sh"} + } + } +, "NON_SYSTEM": + { "vars": ["defaults-transition", "fieldname"] + , "expression": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": + { "type": "FIELD" + , "name": {"type": "var", "name": "fieldname", "default": "defaults"} + } + , "body": + { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "x"} + , "provider": "NON_SYSTEM_TOOLS" + , "transition": + { "type": "var" + , "name": "defaults-transition" + , "default": {"type": "empty_map"} + } + , "default": {"type": "empty_map"} + } + } + } + } +, "sh": + { "vars": ["defaults-transition", "TOOLCHAIN_DIR", "fieldname"] + , "imports": {"default-sh": "default-sh", "NON_SYSTEM": "NON_SYSTEM"} + , "expression": + { "type": "let*" + , "bindings": + [ ["sh", {"type": "CALL_EXPRESSION", "name": "default-sh"}] + , ["NON_SYSTEM", {"type": "CALL_EXPRESSION", "name": "NON_SYSTEM"}] + , [ "sh" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "sh" + , "map": {"type": "var", "name": "NON_SYSTEM"} + } + , "then": + { "type": "join" + , "separator": "/" + , "$1": + [ "." + , { "type": "var" + , "name": "TOOLCHAIN_DIR" + , "default": "toolchain" + } + , {"type": "var", "name": "sh"} + ] + } + , "else": {"type": "var", "name": "sh"} + } + ] + ] + , "body": {"type": "var", "name": "sh"} + } + } +, "PATH": + { "vars": ["fieldname", "defaults-transition"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ [ "fieldname" + , {"type": "var", "name": "fieldname", "default": "defaults"} + ] + , ["provider", "PATH"] + , ["transition", {"type": "var", "name": "defaults-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } +, "prolog": + { "vars": ["fieldname", "TOOLCHAIN_DIR"] + , "imports": {"list_provider": ["./", "..", "field_list_provider"]} + , "expression": + { "type": "let*" + , "bindings": + [ ["provider", "bin dirs"] + , ["bin dirs", {"type": "CALL_EXPRESSION", "name": "list_provider"}] + , [ "relative paths" + , { "type": "foreach" + , "range": {"type": "var", "name": "bin dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ "." + , { "type": "var" + , "name": "TOOLCHAIN_DIR" + , "default": "toolchain" + } + , {"type": "var", "name": "_"} + ] + } + } + ] + , [ "pwd paths" + , { "type": "foreach" + , "range": {"type": "var", "name": "bin dirs"} + , "body": + { "type": "join" + , "separator": "/" + , "$1": + [ "$(pwd)" + , { "type": "var" + , "name": "TOOLCHAIN_DIR" + , "default": "toolchain" + } + , {"type": "var", "name": "_"} + ] + } + } + ] + ] + , "body": + [ "__PATH=$PATH" + , { "type": "join" + , "$1": + [ "export PATH=" + , { "type": "join" + , "separator": ":" + , "$1": {"type": "var", "name": "relative paths"} + } + , "${PATH:+:}${PATH}" + ] + } + , { "type": "join" + , "$1": + [ "export PATH=" + , { "type": "join" + , "separator": ":" + , "$1": {"type": "var", "name": "pwd paths"} + } + , "${__PATH:+:}${__PATH}" + ] + } + , "unset __PATH" + ] + } + } +} diff --git a/rules/shell/RULES b/rules/shell/RULES new file mode 100644 index 0000000..41530a2 --- /dev/null +++ b/rules/shell/RULES @@ -0,0 +1,349 @@ +{ "defaults": + { "doc": + [ "A rule to provide defaults for the usage of the shell" + , "" + , "All targets using invocations of the shell use the target" + , "[\"shel\", \"defaults\"] to determine which shell to use and how to" + , "invoke it. The definition of this default target is probably the only" + , "meaningful use of this rule." + ] + , "target_fields": ["base", "toolchain"] + , "string_fields": ["sh", "PATH", "bin dirs"] + , "field_doc": + { "base": ["Other targets (using the same rule) to inherit values from."] + , "toolchain": + [ "Optional toolchain directory. A collection of artifacts that" + , "form the toolchain, in particular the shell itself, where not taken" + , "from the ambient host environment." + , "Values provided from base are extended." + , "This field is built for the host." + ] + , "sh": + [ "The name of the sh binary; if the the field \"toolchain\" is" + , "not empty, the value is interpreted as relative to the toolchain" + , "directory." + ] + , "PATH": + [ "Paths for looking up system tools." + , "Specifying this field extends values from \"base\"." + ] + , "bin dirs": + [ "Directories of the toolchain that contain additional binaries." + , "Shell-specific rules will add those into PATH." + ] + } + , "config_vars": ["ARCH", "HOST_ARCH", "TARGET_ARCH"] + , "imports": + { "for host": ["transitions", "for host"] + , "artifacts_list": ["", "field_artifacts_list"] + , "base-provides-list": ["CC", "defaults-base-provides-list"] + , "base-provides-++": ["CC", "defaults-base-provides-++"] + , "base-provides": ["CC", "defaults-base-provides"] + } + , "config_transitions": + {"toolchain": [{"type": "CALL_EXPRESSION", "name": "for host"}]} + , "expression": + { "type": "let*" + , "bindings": + [ [ "TOOLCHAIN" + , { "type": "disjoint_map_union" + , "msg": "toolchain artifacts must not overlap" + , "$1": + { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": + [ ["provider", "TOOLCHAIN"] + , ["default", {"type": "empty_map"}] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "base-provides-list"} + } + , { "type": "let*" + , "bindings": + [ ["fieldname", "toolchain"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "for host"} + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + ] + } + } + ] + , [ "sh" + , { "type": "if" + , "cond": {"type": "FIELD", "name": "sh"} + , "then": {"type": "FIELD", "name": "sh"} + , "else": + { "type": "let*" + , "bindings": [["provider", "sh"]] + , "body": {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + } + ] + , [ "NON_SYSTEM_TOOLS" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ [ { "type": "let*" + , "bindings": + [ ["provider", "NON_SYSTEM_TOOLS"] + , ["default", {"type": "empty_map"}] + ] + , "body": + {"type": "CALL_EXPRESSION", "name": "base-provides"} + } + ] + , { "type": "if" + , "cond": {"type": "FIELD", "name": "sh"} + , "then": + [ { "type": "singleton_map" + , "key": "sh" + , "value": + { "type": "if" + , "cond": {"type": "FIELD", "name": "toolchain"} + , "then": true + , "else": false + } + } + ] + } + ] + } + } + ] + , [ "PATH" + , { "type": "reverse" + , "$1": + { "type": "nub_right" + , "$1": + { "type": "reverse" + , "$1": + { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "PATH"} + , { "type": "let*" + , "bindings": [["provider", "PATH"]] + , "body": + {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + } + } + } + } + ] + , [ "bin dirs" + , { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "bin dirs"} + , { "type": "let*" + , "bindings": [["provider", "bin dirs"]] + , "body": {"type": "CALL_EXPRESSION", "name": "base-provides-++"} + } + ] + } + ] + ] + , "body": + { "type": "RESULT" + , "provides": + { "type": "env" + , "vars": ["TOOLCHAIN", "sh", "NON_SYSTEM_TOOLS", "PATH", "bin dirs"] + } + } + } + } +, "cmds": + { "doc": + [ "Execute comands using the shell" + , "" + , "This rule behaves similar to the built-in \"generic\" rule, however" + , "with the difference that the shell toolchain is honored." + ] + , "target_fields": ["deps"] + , "string_fields": ["cmds", "outs", "out_dirs"] + , "implicit": {"defaults": ["defaults"]} + , "field_doc": + { "deps": + [ "Any inputs to the argument." + , "Both, artifacts and rufiles of the dependecies are staged into" + , "the (effective) working directory of the action. Conflicts are" + , "resolved by giving artifacts priority to runfiles, and within" + , "each of those priority to ones brought by the latest dependency." + ] + , "cmds": + [ "The command to be executed." + , "Individual entries are joined by newline characters; the whole" + , "script is then prefixed by commands necessary to set up the" + , "work environment using the shell tool chain." + ] + , "defaults": ["The shell toolchain to use."] + , "outs": ["The expected file outputs"] + , "out_dirs": ["The expected output directories"] + } + , "imports": + { "artifacts_list": ["", "field_artifacts_list"] + , "runfiles_list": ["", "field_runfiles_list"] + , "map_provider": ["", "field_map_provider"] + , "prolog": "prolog" + , "sh": "sh" + , "PATH": "PATH" + } + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "deps"] + , [ "deps" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "runfiles_list"} + , {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + ] + } + } + ] + , ["fieldname", "defaults"] + , ["TOOLCHAIN_DIR", "toolchain"] + , [ "toolchain" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "TOOLCHAIN_DIR"} + , "$1": + { "type": "let*" + , "bindings": + [["provider", "TOOLCHAIN"], ["default", {"type": "empty_map"}]] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } + ] + , ["WRKDIR", "work"] + , [ "cmds" + , { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "prolog"} + , [ { "type": "join_cmd" + , "$1": ["cd", {"type": "var", "name": "WRKDIR"}] + } + ] + , {"type": "FIELD", "name": "cmds"} + ] + } + ] + , ["sh", {"type": "CALL_EXPRESSION", "name": "sh"}] + , [ "cmdfile" + , { "type": "singleton_map" + , "key": "cmd" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": {"type": "var", "name": "cmds"} + } + } + } + ] + , ["PATH", {"type": "CALL_EXPRESSION", "name": "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"} + } + ] + , [ "outs in WRKDIR" + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "outs"} + , "body": + { "type": "join" + , "$1": + [ {"type": "var", "name": "WRKDIR"} + , "/" + , {"type": "var", "name": "_"} + ] + } + } + ] + , [ "out_dirs in WRKDIR" + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "out_dirs"} + , "body": + { "type": "join" + , "$1": + [ {"type": "var", "name": "WRKDIR"} + , "/" + , {"type": "var", "name": "_"} + ] + } + } + ] + , [ "artifacts" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "toolchain"} + , {"type": "var", "name": "cmdfile"} + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "WRKDIR"} + , "$1": {"type": "var", "name": "deps"} + } + ] + } + , "cmd": [{"type": "var", "name": "sh"}, "cmd"] + , "outs": {"type": "var", "name": "outs in WRKDIR"} + , "out_dirs": {"type": "var", "name": "out_dirs in WRKDIR"} + , "env": {"type": "var", "name": "env"} + } + ] + , [ "staged artifacts" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "range": + { "type": "++" + , "$1": + [ {"type": "FIELD", "name": "outs"} + , {"type": "FIELD", "name": "out_dirs"} + ] + } + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "_"} + , "value": + { "type": "lookup" + , "map": {"type": "var", "name": "artifacts"} + , "key": + { "type": "join" + , "$1": + [ {"type": "var", "name": "WRKDIR"} + , "/" + , {"type": "var", "name": "_"} + ] + } + } + } + } + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "staged artifacts"} + } + } + } +} diff --git a/rules/shell/TARGETS b/rules/shell/TARGETS new file mode 100644 index 0000000..705d1d7 --- /dev/null +++ b/rules/shell/TARGETS @@ -0,0 +1 @@ +{"defaults": {"type": "defaults"}} diff --git a/rules/shell/test/EXPRESSIONS b/rules/shell/test/EXPRESSIONS new file mode 100644 index 0000000..f0966f7 --- /dev/null +++ b/rules/shell/test/EXPRESSIONS @@ -0,0 +1,364 @@ +{ "test-action": + { "vars": + [ "TEST_ENV" + , "TIMEOUT_SCALE" + , "ATTEMPT" + , "name" + , "test.sh" + , "keep" + , "runner" + , "deps-fieldname" + , "deps-transition" + , "target properties" + ] + , "imports": + { "artifacts_list": ["./", "../..", "field_artifacts_list"] + , "runfiles_list": ["./", "../..", "field_runfiles_list"] + , "map_provider": ["./", "../..", "field_map_provider"] + , "default-TOOLCHAIN": ["./", "../../CC", "default-TOOLCHAIN"] + , "default-NON_SYSTEM_TOOLS": + ["./", "../../CC", "default-NON_SYSTEM_TOOLS"] + , "default-PATH": ["./", "../../CC", "default-PATH"] + , "default-sh": ["./", "..", "default-sh"] + , "sh prolog": ["shell", "prolog"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "runner" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "runner" + , "range": {"type": "var", "name": "runner"} + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "runner" + , "range": + { "type": "values" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "runner"} + } + } + , "body": {"type": "env", "vars": ["runner"]} + } + } + } + } + ] + , ["toolchain dirname", "toolchain"] + , [ "toolchain" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "toolchain dirname"} + , "$1": {"type": "CALL_EXPRESSION", "name": "default-TOOLCHAIN"} + } + ] + , ["sh", {"type": "CALL_EXPRESSION", "name": "default-sh"}] + , [ "NON_SYSTEM_TOOLS" + , {"type": "CALL_EXPRESSION", "name": "default-NON_SYSTEM_TOOLS"} + ] + , [ "sh from outside" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "sh" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + { "type": "join" + , "$1": ["./toolchain/", {"type": "var", "name": "sh"}] + } + , "else": {"type": "var", "name": "sh"} + } + ] + , [ "sh from workdir" + , { "type": "if" + , "cond": + { "type": "lookup" + , "key": "sh" + , "map": {"type": "var", "name": "NON_SYSTEM_TOOLS"} + } + , "then": + { "type": "join" + , "$1": ["../toolchain/", {"type": "var", "name": "sh"}] + } + , "else": {"type": "var", "name": "sh"} + } + ] + , [ "with-env" + , { "type": "singleton_map" + , "key": "with-env" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + { "type": "++" + , "$1": + [ { "type": "let*" + , "bindings": [["fieldname", "defaults"]] + , "body": {"type": "CALL_EXPRESSION", "name": "sh prolog"} + } + , [ "" + , { "type": "join_cmd" + , "$1": + { "type": "++" + , "$1": [["./runner"], {"type": "var", "name": "keep"}] + } + } + , "" + ] + ] + } + } + } + } + ] + , [ "invocation cmd" + , [{"type": "var", "name": "sh from workdir"}, "../test.sh"] + ] + , [ "invocation" + , { "type": "singleton_map" + , "key": "invocation" + , "value": + { "type": "BLOB" + , "data": + { "type": "join_cmd" + , "$1": {"type": "var", "name": "invocation cmd"} + } + } + } + ] + , [ "test_env" + , {"type": "var", "name": "TEST_ENV", "default": {"type": "empty_map"}} + ] + , [ "test_env PATH" + , { "type": "lookup" + , "key": "PATH" + , "map": {"type": "var", "name": "test_env"} + } + ] + , [ "PATH" + , { "type": "join" + , "separator": ":" + , "$1": + { "type": "++" + , "$1": + [ { "type": "if" + , "cond": {"type": "var", "name": "test_env PATH"} + , "then": [{"type": "var", "name": "test_env PATH"}] + } + , {"type": "CALL_EXPRESSION", "name": "default-PATH"} + ] + } + } + ] + , [ "test_env" + , { "type": "if" + , "cond": {"type": "var", "name": "PATH"} + , "then": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "test_env"} + , { "type": "singleton_map" + , "key": "PATH" + , "value": {"type": "var", "name": "PATH"} + } + ] + } + , "else": {"type": "var", "name": "test_env"} + } + ] + , [ "deps" + , { "type": "TREE" + , "$1": + { "type": "disjoint_map_union" + , "msg": + [ "Field" + , {"type": "var", "name": "deps-fieldname"} + , "has to stage in a conflict free way" + ] + , "$1": + { "type": "++" + , "$1": + { "type": "let*" + , "bindings": + [ ["fieldname", {"type": "var", "name": "deps-fieldname"}] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": + [ {"type": "CALL_EXPRESSION", "name": "runfiles_list"} + , {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + ] + } + } + } + } + ] + , [ "run-libs" + , { "type": "TREE" + , "$1": + { "type": "let*" + , "bindings": + [ ["fieldname", {"type": "var", "name": "deps-fieldname"}] + , ["provider", "run-libs"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "map_provider"} + } + } + ] + , [ "attempt marker" + , { "type": "if" + , "cond": + { "type": "==" + , "$1": {"type": "var", "name": "ATTEMPT"} + , "$2": null + } + , "then": {"type": "empty_map"} + , "else": + { "type": "singleton_map" + , "key": "ATTEMPT" + , "value": + {"type": "BLOB", "data": {"type": "var", "name": "ATTEMPT"}} + } + } + ] + , [ "outs" + , { "type": "++" + , "$1": + [ ["result", "stdout", "stderr", "time-start", "time-stop"] + , { "type": "foreach" + , "var": "filename" + , "range": {"type": "var", "name": "keep"} + , "body": + { "type": "join" + , "$1": ["work/", {"type": "var", "name": "filename"}] + } + } + ] + } + ] + , [ "inputs" + , { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": "work" + , "value": {"type": "var", "name": "deps"} + } + , { "type": "singleton_map" + , "key": "libs" + , "value": {"type": "var", "name": "run-libs"} + } + , {"type": "var", "name": "toolchain"} + , {"type": "var", "name": "with-env"} + , {"type": "var", "name": "runner"} + , {"type": "var", "name": "invocation"} + , {"type": "var", "name": "test.sh"} + , {"type": "var", "name": "attempt marker"} + ] + } + ] + , ["cmd", [{"type": "var", "name": "sh from outside"}, "with-env"]] + , [ "test_env" + , { "type": "map_union" + , "$1": + [ { "type": "if" + , "cond": + { "type": "==" + , "$1": {"type": "var", "name": "ATTEMPT"} + , "$2": null + } + , "then": {"type": "empty_map"} + , "else": + { "type": "singelton_map" + , "key": "TEST_RUN_NUMBER" + , "value": {"type": "var", "name": "ATTEMPT"} + } + } + , {"type": "var", "name": "test_env"} + ] + } + ] + ] + , "body": + { "type": "if" + , "cond": + {"type": "==", "$1": {"type": "var", "name": "ATTEMPT"}, "$2": null} + , "then": + { "type": "ACTION" + , "outs": {"type": "var", "name": "outs"} + , "inputs": {"type": "var", "name": "inputs"} + , "cmd": {"type": "var", "name": "cmd"} + , "env": {"type": "var", "name": "test_env"} + , "may_fail": ["test"] + , "fail_message": + { "type": "join" + , "$1": ["shell test ", {"type": "var", "name": "name"}, " failed"] + } + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 1.0} + , "execution properties": {"type": "var", "name": "target properties"} + } + , "else": + { "type": "ACTION" + , "outs": {"type": "var", "name": "outs"} + , "inputs": {"type": "var", "name": "inputs"} + , "cmd": {"type": "var", "name": "cmd"} + , "env": {"type": "var", "name": "test_env"} + , "may_fail": ["test"] + , "no_cache": ["test"] + , "fail_message": + { "type": "join" + , "$1": + [ "shell test " + , {"type": "var", "name": "name"} + , " failed (Run " + , {"type": "var", "name": "ATTEMPT"} + , ")" + ] + } + , "timeout scaling": + {"type": "var", "name": "TIMEOUT_SCALE", "default": 1.0} + , "execution properties": {"type": "var", "name": "target properties"} + } + } + } + } +, "test-result": + { "vars": + [ "TEST_ENV" + , "TIMEOUT_SCALE" + , "name" + , "test.sh" + , "keep" + , "runner" + , "deps-fieldname" + , "deps-transition" + , "target properties" + ] + , "imports": {"action": "test-action"} + , "expression": + { "type": "let*" + , "bindings": + [ ["test-results", {"type": "CALL_EXPRESSION", "name": "action"}] + , [ "runfiles" + , { "type": "singleton_map" + , "key": {"type": "var", "name": "name"} + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "test-results"}} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "test-results"} + , "runfiles": {"type": "var", "name": "runfiles"} + } + } + } +} diff --git a/rules/shell/test/RULES b/rules/shell/test/RULES new file mode 100644 index 0000000..4b72d10 --- /dev/null +++ b/rules/shell/test/RULES @@ -0,0 +1,260 @@ +{ "script": + { "doc": ["Shell test, given by a test script"] + , "target_fields": ["deps", "test"] + , "string_fields": ["keep", "name"] + , "config_vars": + [ "ARCH" + , "HOST_ARCH" + , "RUNS_PER_TEST" + , "TEST_ENV" + , "TIMEOUT_SCALE" + , "TARGET_ARCH" + , "ARCH_DISPATCH" + , "TEST_SUMMARY_EXECUTION_PROPERTIES" + ] + , "field_doc": + { "test": + [ "The shell script for the test, launched with sh." + , "" + , "An empty directory is created to store any temporary files needed" + , "by the test, and it is made available in the environment variable" + , "TEST_TMPDIR. The test should not assume write permissions" + , "outside the working directory and the TEST_TMPDIR." + , "For convenience, the environment variable TMPDIR is also set to TEST_TMPDIR." + , "" + , "If the configuration variable RUNS_PER_TEST is set, the environment" + , "variable TEST_RUN_NUMBER will also be set to the number of the attempt," + , "counting from 0." + , "" + , "This running of the test is carried out by the implicit dependency" + , "on the target \"runner\". By setting this target in the target layer" + , "of this rues repository (instead of letting it default to the" + , "respective file), the shell test environment can be modified globally." + ] + , "name": + [ "A name for the test, used in reporting, as well as for staging" + , "the test result tree in the runfiles" + ] + , "keep": + [ "List of names (relative to the test working directory) of files that" + , "the test might generate that should be kept as part of the output." + , "This might be useful for further analysis of the test" + ] + , "deps": + [ "Any targets that should be staged (with artifacts and runfiles) into" + , "the tests working directory" + ] + , "runner": + [ "The test runner which starts the actual test script after providing" + , "the respective environment. The runner also takes care of capturing" + , "stdout/stderr, timing information, and ensure the presence of the" + , "files to keep even if the script failed to produce them." + ] + , "summarizer": + [ "Tool to aggregate the results of individual test runs (for flakyness" + , "detection) to an overall test result." + ] + , "defaults": ["The shell toolcahin to use."] + } + , "config_doc": + { "RUNS_PER_TEST": + [ "The number of times the test should be run in order to detect flakyness." + , "If set, no test action will be taken from cache." + , "" + , "The individual test runs will be summarized by the implict dependency" + , "on the target \"summarizer\". By setting this target in the target" + , "in the target layer of this rues repository (instead of letting it" + , "default to the respective file) the layout of the summary can be" + , "changed globally." + ] + , "TEST_ENV": ["Additional environment for executing the test runner."] + , "TIMEOUT_SCALE": + ["Factor on how to scale the timeout for this test. Defaults to 1.0."] + , "TARGET_ARCH": + [ "The architecture to build the test for." + , "" + , "Will only be honored, if that architecture is available in the" + , "ARCH_DISPATCH map. Otherwise, the test will be built for and run" + , "on the host architecture." + ] + , "ARCH_DISPATCH": + [ "Map of architectures to execution properties that ensure execution" + , "on that architecture. Only the actual test binary will be run with" + , "the specified execution properties (i.e., on the target architecture);" + , "all building will be done on the host architecture." + ] + , "TEST_SUMMARY_EXECUTION_PROPERTIES": + [ "Additional remote-execution properties for the test-summarizing action" + , "in case RUNS_PER_TEST is set; defaults to the empty map." + ] + } + , "tainted": ["test"] + , "artifacts_doc": + [ "result: the result of this test (\"PASS\" or \"FAIL\"); useful for" + , " generating test reports." + , "stdout/stderr: Any output the invocation of the test binary produced on" + , " the respective file descriptor" + , "work: In this directory, all the files specified to \"keep\" are staged" + , "time-start/time-stop: The time (decimally coded) in seconds since the" + , " epoch when the test invocation started and ended." + ] + , "runfiles_doc": + [ "A tree consisting of the artifacts staged at the name of the test." + , "As the built-in \"install\" rule only takes the runfiles of its \"deps\"" + , "argument, this gives an easy way of defining test suites." + ] + , "implicit": + { "runner": ["runner"] + , "summarizer": ["summarizer"] + , "defaults": [["./", "..", "defaults"]] + } + , "imports": + { "test-result": "test-result" + , "action": "test-action" + , "stage": ["./", "../..", "stage_singleton_field"] + , "host transition": ["transitions", "maybe for host"] + , "target properties": ["transitions", "target properties"] + } + , "config_transitions": + { "deps": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + , "test": [{"type": "CALL_EXPRESSION", "name": "host transition"}] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "test.sh" + , { "type": "context" + , "msg": "Expecting 'test' to specify precisely one file containing a shell script" + , "$1": + { "type": "let*" + , "bindings": + [ ["fieldname", "test"] + , ["location", "test.sh"] + , [ "transition" + , {"type": "CALL_EXPRESSION", "name": "host transition"} + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "Have to provide a non-empty name for the test (e.g., for result staging)" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + , ["keep", {"type": "FIELD", "name": "keep"}] + , ["runner", {"type": "FIELD", "name": "runner"}] + , ["deps-fieldname", "deps"] + , [ "deps-transition" + , {"type": "CALL_EXPRESSION", "name": "host transition"} + ] + , [ "target properties" + , {"type": "CALL_EXPRESSION", "name": "target properties"} + ] + ] + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "RUNS_PER_TEST"} + , "else": {"type": "CALL_EXPRESSION", "name": "test-result"} + , "then": + { "type": "let*" + , "bindings": + [ [ "attempts" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "ATTEMPT" + , "range": + { "type": "range" + , "$1": {"type": "var", "name": "RUNS_PER_TEST"} + } + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "ATTEMPT"} + , "value": + { "type": "TREE" + , "$1": {"type": "CALL_EXPRESSION", "name": "action"} + } + } + } + } + ] + , [ "summarizer" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "FIELD", "name": "summarizer"} + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": + { "type": "values" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "x"} + } + } + , "body": + { "type": "singleton_map" + , "key": "summarizer" + , "value": {"type": "var", "name": "x"} + } + } + } + } + } + ] + , [ "summary" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "attempts"} + , {"type": "var", "name": "summarizer"} + ] + } + , "outs": + ["stdout", "stderr", "result", "time-start", "time-stop"] + , "cmd": ["./summarizer"] + , "execution properties": + { "type": "var" + , "name": "TEST_SUMMARY_EXECUTION_PROPERTIES" + , "default": {"type": "empty_map"} + } + } + ] + , [ "artifacts" + , { "type": "map_union" + , "$1": + [ {"type": "var", "name": "summary"} + , { "type": "singleton_map" + , "key": "work" + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "attempts"}} + } + ] + } + ] + , [ "runfiles" + , { "type": "singleton_map" + , "key": {"type": "var", "name": "name"} + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "artifacts"}} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "artifacts"} + , "runfiles": {"type": "var", "name": "runfiles"} + } + } + } + } + } +} diff --git a/rules/shell/test/TARGETS b/rules/shell/test/TARGETS new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/rules/shell/test/TARGETS @@ -0,0 +1 @@ +{} diff --git a/rules/shell/test/runner b/rules/shell/test/runner new file mode 100755 index 0000000..2f97005 --- /dev/null +++ b/rules/shell/test/runner @@ -0,0 +1,59 @@ +#!/bin/sh +# 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. + + +# ensure all required outputs are present +touch stdout +touch stderr +RESULT=UNKNOWN +echo "${RESULT}" > result +echo UNKNOWN > time-start +echo UNKNOWN > time-stop + +mkdir scratch +export TEST_TMPDIR=$(realpath scratch) +export TMPDIR="${TEST_TMPDIR}" +export LD_LIBRARY_PATH=$(realpath ./libs):$LD_LIBRARY_PATH + +# Change to the working directory; note: while unlikely, the test +# might not have test data, so we have to ensure the presence of +# the work directory. +mkdir -p work +cd work + +date +%s > ../time-start +# TODO: +# - proper wrapping with timeout +if . ../invocation > ../stdout 2> ../stderr +then + RESULT=PASS +else + RESULT=FAIL +fi +date +%s > ../time-stop + +# Ensure all the promissed output files in the work directory +# are present, even if the test failed to create them. +for f in "$@" +do + touch "./${f}" +done + +echo "${RESULT}" > ../result + +if [ "${RESULT}" '!=' PASS ] +then + exit 1; +fi diff --git a/rules/shell/test/summarizer b/rules/shell/test/summarizer new file mode 100755 index 0000000..72cd1b9 --- /dev/null +++ b/rules/shell/test/summarizer @@ -0,0 +1,73 @@ +#!/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 os +import time + +from typing import Any, Dict, List + +g_RESULTS: Dict[str, List[Any]] = {} +g_COUNT: float = 0 + +time_start: float = time.time() +time_stop: float = 0 + +for attempt in os.listdir("."): + if os.path.isdir(attempt): + g_COUNT += 1 + with open(os.path.join(attempt, "result")) as f: + result = f.read().strip() + g_RESULTS[result] = g_RESULTS.get(result, []) + [int(attempt)] + try: + with open(os.path.join(attempt, "time-start")) as f: + time_start = min(time_start, float(f.read().strip())) + except: + pass + try: + with open(os.path.join(attempt, "time-stop")) as f: + time_stop = max(time_start, float(f.read().strip())) + except: + pass + +result: str = "UNKNOWN" +if set(g_RESULTS.keys()) <= set(["PASS", "FAIL"]): + if not g_RESULTS.get("FAIL"): + result = "PASS" + elif not g_RESULTS.get("PASS"): + result = "FAIL" + else: + result = "FLAKY" +with open("result", "w") as f: + f.write("%s\n" % (result, )) + +with open("time-start", "w") as f: + f.write("%d\n" % (time_start, )) +with open("time-stop", "w") as f: + f.write("%d\n" % (time_stop, )) + +with open("stdout", "w") as f: + f.write("Summary: %s\n\n" % (result, )) + f.write("PASS: %s\n" % (sorted(g_RESULTS.get("PASS", [])), )) + failures =sorted(g_RESULTS.get("FAIL", [])) + f.write("FAIL: %s\n" % (failures, )) + g_RESULTS.pop("PASS", None) + g_RESULTS.pop("FAIL", None) + if g_RESULTS: + f.write("\nother results: %r\n" % (g_RESULTS, )) + if result == "FLAKY": + f.write("\nFailure rate %5.2f%%\n" % (100.0 * len(failures) / g_COUNT)) + +with open("stderr", "w") as f: + pass diff --git a/rules/transitions/EXPRESSIONS b/rules/transitions/EXPRESSIONS new file mode 100644 index 0000000..fef8542 --- /dev/null +++ b/rules/transitions/EXPRESSIONS @@ -0,0 +1,82 @@ +{ "for host": + { "vars": ["ARCH", "HOST_ARCH", "TARGET_ARCH"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "BUILD_ARCH" + , { "type": "var" + , "name": "TARGET_ARCH" + , "default": {"type": "var", "name": "ARCH"} + } + ] + , [ "TARGET_ARCH" + , { "type": "var" + , "name": "HOST_ARCH" + , "default": {"type": "var", "name": "ARCH"} + } + ] + ] + , "body": {"type": "env", "vars": ["BUILD_ARCH", "TARGET_ARCH"]} + } + } +, "with fPIC": + { "doc": + [ "Transition that enables BUILD_POSITION_INDEPENDENT if config_field" + , "\"shared\" is not empty." + ] + , "expression": + { "type": "if" + , "cond": {"type": "FIELD", "name": "shared"} + , "then": + { "type": "singleton_map" + , "key": "BUILD_POSITION_INDEPENDENT" + , "value": true + } + , "else": {"type": "empty_map"} + } + } +, "target properties": + { "vars": ["ARCH", "TARGET_ARCH", "ARCH_DISPATCH"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "TARGET_ARCH" + , { "type": "var" + , "name": "TARGET_ARCH" + , "default": {"type": "var", "name": "ARCH"} + } + ] + ] + , "body": + { "type": "if" + , "cond": + { "type": "==" + , "$1": {"type": "var", "name": "TARGET_ARCH"} + , "$2": null + } + , "then": {"type": "empty_map"} + , "else": + { "type": "lookup" + , "map": + { "type": "var" + , "name": "ARCH_DISPATCH" + , "default": {"type": "empty_map"} + } + , "key": {"type": "var", "name": "TARGET_ARCH"} + , "default": {"type": "empty_map"} + } + } + } + } +, "maybe for host": + { "vars": ["ARCH", "HOST_ARCH", "TARGET_ARCH", "ARCH_DISPATCH"] + , "imports": + {"target properties": "target properties", "for host": "for host"} + , "expression": + { "type": "if" + , "cond": {"type": "CALL_EXPRESSION", "name": "target properties"} + , "then": {"type": "empty_map"} + , "else": {"type": "CALL_EXPRESSION", "name": "for host"} + } + } +} |