From 8ce1c4589e553f7f79893c712b8f4847a098ce75 Mon Sep 17 00:00:00 2001 From: Klaus Aehlig Date: Mon, 12 Aug 2024 10:36:49 +0200 Subject: Make CC binary and library support providing information for linting If the configuration variable "LINT" is set, also provide information on compile actions and header files (with preprocessing as described command, in particular also providing the correct flags) in correct dependency context. In this way, lint rules can request the needed information for performing their checks. --- CC/EXPRESSIONS | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- CC/RULES | 12 +++ 2 files changed, 248 insertions(+), 1 deletion(-) diff --git a/CC/EXPRESSIONS b/CC/EXPRESSIONS index 39f8743..ebe4017 100644 --- a/CC/EXPRESSIONS +++ b/CC/EXPRESSIONS @@ -805,6 +805,214 @@ } } } +, "lint information": + { "vars": + [ "srcs" + , "hdrs" + , "private-hdrs" + , "compile-deps" + , "cflags-files" + , "lint-deps fieldnames" + , "deps-transition" + , "compile-args" + ] + , "imports": + { "objects": "objects" + , "list_provider": ["./", "..", "field_list_provider"] + , "default-TOOLCHAIN": "default-TOOLCHAIN" + , "default-NON_SYSTEM_TOOLS": "default-NON_SYSTEM_TOOLS" + , "compiler": "compiler" + , "flags": "flags" + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "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"} + ] + } + ] + , [ "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"} + ] + } + } + ] + } + ] + , [ "hdr lint" + , { "type": "foreach" + , "range": + { "type": "++" + , "$1": + [ {"type": "keys", "$1": {"type": "var", "name": "private-hdrs"}} + , {"type": "keys", "$1": {"type": "var", "name": "hdrs"}} + ] + } + , "body": + { "type": "VALUE_NODE" + , "$1": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "all hdrs"} + , "provides": + { "type": "let*" + , "bindings": + [ [ "src" + , { "type": "join" + , "$1": ["work/", {"type": "var", "name": "_"}] + } + ] + , [ "cmd" + , { "type": "++" + , "$1": + [ [{"type": "var", "name": "COMPILER"}] + , {"type": "var", "name": "COMPILE_FLAGS"} + , [ "-I" + , "work" + , "-isystem" + , "include" + , "-E" + , {"type": "var", "name": "src"} + ] + ] + } + ] + ] + , "body": {"type": "env", "vars": ["cmd", "src"]} + } + } + } + } + ] + , [ "src lint" + , { "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"}] + } + ] + , [ "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"}] + ] + } + ] + ] + , "body": + { "type": "VALUE_NODE" + , "$1": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "inputs"} + , "provides": + { "type": "let*" + , "bindings": + [["src", {"type": "var", "name": "work src_name"}]] + , "body": {"type": "env", "vars": ["cmd", "src"]} + } + } + } + } + } + ] + , [ "dep lint nodes" + , { "type": "++" + , "$1": + { "type": "foreach" + , "var": "fieldname" + , "range": {"type": "var", "name": "lint-deps fieldnames"} + , "body": + { "type": "let*" + , "bindings": + [ ["provider", "lint"] + , ["transition", {"type": "var", "name": "deps-transition"}] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "list_provider"} + } + } + } + ] + , [ "lint nodes" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "hdr lint"} + , {"type": "var", "name": "src lint"} + , {"type": "var", "name": "dep lint nodes"} + ] + } + ] + , [ "lint nodes" + , {"type": "nub_right", "$1": {"type": "var", "name": "lint nodes"}} + ] + ] + , "body": {"type": "var", "name": "lint nodes"} + } + } , "compiler-cc": { "vars": ["CC", "TOOLCHAIN_DIR", "NON_SYSTEM_TOOLS", "defaults-transition"] , "imports": {"default-CC": "default-CC"} @@ -1141,6 +1349,7 @@ , "AR" , "ENV" , "DEBUG" + , "LINT" , "name" , "pure C" , "srcs" @@ -1164,6 +1373,7 @@ , "ldflags-files-deps": "ldflags-files-deps" , "lib artifact": "lib artifact" , "debug-deps": "debug-deps" + , "lint": "lint information" } , "expression": { "type": "let*" @@ -1187,6 +1397,13 @@ ] , ["link-deps", {"type": "CALL_EXPRESSION", "name": "link-deps"}] , ["lib", {"type": "CALL_EXPRESSION", "name": "lib artifact"}] + , ["lint-deps fieldnames", ["deps", "private-deps"]] + , [ "lint" + , { "type": "if" + , "cond": {"type": "var", "name": "LINT"} + , "then": {"type": "CALL_EXPRESSION", "name": "lint"} + } + ] , [ "link-args" , { "type": "nub_right" , "$1": @@ -1276,6 +1493,7 @@ , "package" , "debug-srcs" , "debug-hdrs" + , "lint" ] } , { "type": "var" @@ -1516,6 +1734,7 @@ , "ADD_CXXFLAGS" , "ENV" , "DEBUG" + , "LINT" , "name" , "pure C" , "srcs" @@ -1534,6 +1753,7 @@ , "ldflags-files-deps": "ldflags-files-deps" , "binary": "bin artifact" , "debug-deps": "debug-deps" + , "lint": "lint information" } , "expression": { "type": "let*" @@ -1600,12 +1820,27 @@ , "else": {"type": "empty_map"} } ] + , [ "lint" + , { "type": "if" + , "cond": {"type": "var", "name": "LINT"} + , "then": + { "type": "let*" + , "bindings": + [ ["hdrs", {"type": "empty_map"}] + , ["lint-deps fieldnames", ["private-deps"]] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "lint"} + } + } + ] ] , "body": { "type": "RESULT" , "artifacts": {"type": "CALL_EXPRESSION", "name": "binary"} , "provides": - {"type": "env", "vars": ["package", "debug-srcs", "debug-hdrs"]} + { "type": "env" + , "vars": ["package", "debug-srcs", "debug-hdrs", "lint"] + } } } } diff --git a/CC/RULES b/CC/RULES index 93407ac..85c7456 100644 --- a/CC/RULES +++ b/CC/RULES @@ -407,6 +407,7 @@ , "AR" , "ENV" , "DEBUG" + , "LINT" ] , "implicit": {"defaults": ["defaults"]} , "field_doc": @@ -501,6 +502,11 @@ ] , "ENV": ["The environment for any action generated."] , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + , "LINT": + [ "Also provide nodes describing compile actions and header files;" + , "those can be used by lint rules (doing also the config transition)" + , "for additional checks." + ] } , "artifacts_doc": ["The actual library (libname.a) staged in the specified directory"] @@ -637,6 +643,7 @@ , "ADD_CXXFLAGS" , "ENV" , "DEBUG" + , "LINT" ] , "implicit": {"defaults": ["defaults"]} , "field_doc": @@ -695,6 +702,11 @@ ] , "ENV": ["The environment for any action generated."] , "DEBUG": ["Compute the debug-stage, needed for local debugging."] + , "LINT": + [ "Also provide nodes describing compile actions and header files;" + , "those can be used by lint rules (doing also the config transition)" + , "for additional checks." + ] } , "artifacts_doc": ["The final binary, staged to the given directory"] , "runfiles_doc": ["None"] -- cgit v1.2.3 From 2ab70dbcfa7f7f5a352c4ff15404227b47242c66 Mon Sep 17 00:00:00 2001 From: Klaus Aehlig Date: Mon, 12 Aug 2024 14:34:00 +0200 Subject: new rule ["lint", "targets"] --- lint/RULES | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lint/TARGETS | 1 + lint/call_lint | 41 ++++++++++++ lint/call_summary | 35 ++++++++++ 4 files changed, 264 insertions(+) create mode 100644 lint/RULES create mode 100644 lint/TARGETS create mode 100755 lint/call_lint create mode 100755 lint/call_summary diff --git a/lint/RULES b/lint/RULES new file mode 100644 index 0000000..d7b2703 --- /dev/null +++ b/lint/RULES @@ -0,0 +1,187 @@ +{ "targets": + { "doc": + [ "Run a given linter on the lint information provided by the given targets." + ] + , "target_fields": ["linter", "config", "summarizer", "targets"] + , "tainted": ["lint"] + , "field_doc": + { "linter": + [ "Single artifact running the lint checks." + , "" + , "This artifact with" + , "- argv[1] the file to lint, and" + , "- argv[2:] the original command line." + , "This invocation happens in an environment with" + , "- CONFIG pointing to the directory with all the artifacts given" + , " by the field \"config\"." + , "- OUT pointing to a directory to which files with the lint result" + , " can be written." + , "The linter is supposed to indicate by the exit code whether the" + , "indicated file complies with the given linting policy, with 0 meaning" + , "compliant." + , "Stdout and stderr, as well as the directory ${OUT} can be used to" + , "provide additional information." + ] + , "config": ["Any configuration or other files needed by the linter."] + , "summarizer": + [ "Single artifact generating a summary of the individual lint results." + , "It will be called in a directory where all subdirectories with names" + , "consisting entirely of digits are the results of the individual lint" + , "actions. Those are given as" + , " - a file result with content PASS if and only if the lint action" + , " exited 0," + , " - files stdout and stderr with stdout and stderr of the lint" + , " action, and" + , " - a directory out with the additional information provided by the" + , " lint action." + , "The summarizer is required to indicate the overall result by the exit" + , "code, produce a human-readable summary on stdout, and optionally" + , "additional information in the directory ${OUT}." + ] + , "call_lint": ["Launcher for the linter"] + , "call_summary": ["Launcher for the summarizer"] + } + , "implicit": {"call_lint": ["call_lint"], "call_summary": ["call_summary"]} + , "config_transitions": + {"targets": [{"type": "singleton_map", "key": "LINT", "value": true}]} + , "anonymous": + {"lint": {"target": "targets", "provider": "lint", "rule_map": {}}} + , "imports": + { "stage": ["", "stage_singleton_field"] + , "artifacts": ["", "field_artifacts"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "linter" + , { "type": "let*" + , "bindings": [["fieldname", "linter"], ["location", "linter"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , [ "runner" + , { "type": "let*" + , "bindings": [["fieldname", "call_lint"], ["location", "runner"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , [ "config" + , { "type": "let*" + , "bindings": [["fieldname", "config"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts"} + } + ] + , [ "lint results" + , { "type": "foreach" + , "range": {"type": "FIELD", "name": "lint"} + , "body": + { "type": "let*" + , "bindings": + [ [ "src" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "_"} + , "provider": "src" + } + ] + , [ "cmd" + , { "type": "DEP_PROVIDES" + , "dep": {"type": "var", "name": "_"} + , "provider": "cmd" + } + ] + , [ "src input" + , { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "_"} + } + ] + ] + , "body": + { "type": "TREE" + , "$1": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "runner"} + , {"type": "var", "name": "linter"} + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "src input"} + } + , { "type": "to_subdir" + , "subdir": "config" + , "$1": {"type": "var", "name": "config"} + } + ] + } + , "cmd": + { "type": "++" + , "$1": + [ ["./runner", {"type": "var", "name": "src"}] + , {"type": "var", "name": "cmd"} + ] + } + , "outs": ["stdout", "stderr", "result"] + , "out_dirs": ["out"] + , "may_fail": ["lint"] + , "fail_message": + { "type": "join" + , "$1": ["lint failed for ", {"type": "var", "name": "src"}] + } + } + } + } + } + ] + , [ "summary input" + , {"type": "enumerate", "$1": {"type": "var", "name": "lint results"}} + ] + , [ "summarizer" + , { "type": "let*" + , "bindings": + [["fieldname", "summarizer"], ["location", "summarizer"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , [ "runner" + , { "type": "let*" + , "bindings": [["fieldname", "call_summary"], ["location", "runner"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + ] + , [ "summary" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "runner"} + , {"type": "var", "name": "summarizer"} + , { "type": "to_subdir" + , "subdir": "work" + , "$1": {"type": "var", "name": "summary input"} + } + ] + } + , "cmd": ["./runner"] + , "outs": ["report", "result"] + , "out_dirs": ["out"] + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "summary"} + , { "type": "singleton_map" + , "key": "work" + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "summary input"}} + } + ] + } + } + } + } +} diff --git a/lint/TARGETS b/lint/TARGETS new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/lint/TARGETS @@ -0,0 +1 @@ +{} diff --git a/lint/call_lint b/lint/call_lint new file mode 100755 index 0000000..ab9c2b8 --- /dev/null +++ b/lint/call_lint @@ -0,0 +1,41 @@ +#!/bin/sh +# Copyright 2024 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 + +export OUT="$(pwd)/out" +mkdir -p config +export CONFIG="$(pwd)/config" + +cd work + +if ../linter "$@" > ../stdout 2> ../stderr +then + RESULT=PASS +else + RESULT=FAIL +fi + +echo "${RESULT}" > ../result + +if [ "${RESULT}" '!=' PASS ] +then + exit 1; +fi diff --git a/lint/call_summary b/lint/call_summary new file mode 100755 index 0000000..d4aa8cb --- /dev/null +++ b/lint/call_summary @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright 2024 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 report +RESULT=UNKNOWN +echo "${RESULT}" > result + +export OUT="$(pwd)/out" + +cd work + +if ../summarizer > ../report +then + RESULT=PASS +else + RESULT=FAIL +fi + +echo "${RESULT}" > ../result + +exit 0 -- cgit v1.2.3