From 3048fdf7a151b43cfbc90c3a6503b16c416071a0 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 9 Oct 2021 22:46:47 +0200 Subject: [PATCH] Add presubmit. --- Makefile | 38 ++++++ build-aux/verify-coding-style.sh | 111 ++++++++++++++++++ build-aux/verify-headers-in-configuration.sh | 115 +++++++++++++++++++ build-aux/verify-headers.sh | 43 +++++++ build-aux/verify-manual.sh | 11 ++ share/man/man7/development.7 | 16 +++ 6 files changed, 334 insertions(+) create mode 100755 build-aux/verify-coding-style.sh create mode 100755 build-aux/verify-headers-in-configuration.sh create mode 100755 build-aux/verify-headers.sh create mode 100755 build-aux/verify-manual.sh diff --git a/Makefile b/Makefile index 50677a4b..c6520223 100644 --- a/Makefile +++ b/Makefile @@ -522,6 +522,44 @@ release: release-arch release-shared sed -E 's,^([^ ]* )\./,\1,' | \ LC_ALL=C sort -k 2 > sha256sum +# Presubmit checks + +presubmit: + $(MAKE) verify-coding-style + $(MAKE) verify-manual + $(MAKE) verify-build-tools +# TODO: The gcc port doesn't ship with cross-compilers out of the box. +ifeq ($(BUILD_IS_SORTIX),1) + $(MAKE) verify-build +else + $(MAKE) verify-build HOST=i686-sortix + $(MAKE) verify-build HOST=x86_64-sortix +endif + $(MAKE) verify-headers + @echo ok + +verify-coding-style: + build-aux/verify-coding-style.sh + +verify-manual: + build-aux/verify-manual.sh + +verify-build-tools: + $(MAKE) clean-build-tools + $(MAKE) OPTLEVEL='-O2 -g -Werror -Werror=strict-prototypes' build-tools + +verify-build: + $(MAKE) mostlyclean + $(MAKE) OPTLEVEL='-O2 -g -Werror -Werror=strict-prototypes' PACKAGES='' + +verify-headers: +# TODO: The gcc port doesn't ship with cross-compilers out of the box. +ifeq ($(BUILD_IS_SORTIX),1) + build-aux/verify-headers.sh $(HOST) # Inherit jobserver: $(MAKE) +else + build-aux/verify-headers.sh # Inherit jobserver: $(MAKE) +endif + # Virtualization .PHONY: run-virtualbox run-virtualbox: sortix.iso diff --git a/build-aux/verify-coding-style.sh b/build-aux/verify-coding-style.sh new file mode 100755 index 00000000..fd4dd488 --- /dev/null +++ b/build-aux/verify-coding-style.sh @@ -0,0 +1,111 @@ +#!/bin/sh +# Verifies the coding style conventions are adhered to. + +RESULT=true + +complain() { + echo "$1 $2" +} + +check_trailing_whitespace() { + grep -q -E '( | )+$' -- "$1" +} + +check_tabs_following_spaces() { + grep -q -E '^( | )* + ' -- "$1" +} + +check_trailing_blank_lines() { + [ "$(cat -- "$1" | wc -l)" != "0" ] && + [ -z "$(tail -1 -- "$1")" ] +} + +grep_copyright_header_full() { + grep -m 1 -A 100 -E '^/\*+$' | + grep -m 1 -B 100 -E '^\*+/$' +} + +grep_copyright_header_contents() { + grep -v -E '^/\*+$' | + grep -v -E '^\*+/$' +} + +has_leading_tabs() { + grep -q -E '^ +' +} + +has_bsd_tag() { + grep -q -E '/\*[[:space:]]*\$.*\$[[:space:]]*\*/' +} + +verify_source() { + FILE="$1" + if ! cat -- "$FILE" | has_bsd_tag && + ! grep -q -- "Permission to use, copy, modify, and distribute this software for any" "$FILE" && + ! grep -q -- "$FILE" "$FILE"; then + complain "$PWD/$FILE" "doesn't contain its own file path" + RESULT=false + fi + if ! grep -q -i -E 'copyright|public domain' -- "$FILE"; then + complain "$PWD/$FILE" "doesn't have a copyright statement" + RESULT=false + fi + if grep -q COPYRIGHT -- "$FILE" || + grep -q -E '^/\*{78}$' -- "$FILE" || + grep -q -E '^\*{78}/$' -- "$FILE"; then + complain "$PWD/$FILE" "has an obsolete copyright statement" + RESULT=false + fi + if grep -q -E '^/\*{80}$' -- "$FILE" || + grep -q -E '^/\*{80}$' -- "$FILE"; then + complain "$PWD/$FILE" "has a spurious copyright statement" + RESULT=false + fi + if cat -- "$FILE" | + grep_copyright_header_full | + grep_copyright_header_contents | + has_leading_tabs; then + complain "$PWD/$FILE" "has tabs in its copyright statement" + RESULT=false + fi + if check_trailing_whitespace "$FILE"; then + complain "$PWD/$FILE" "has trailing whitespace" + RESULT=false + fi + if check_tabs_following_spaces "$FILE"; then + complain "$PWD/$FILE" "has tabs following spaces" + RESULT=false + fi + if check_trailing_blank_lines "$FILE"; then + complain "$PWD/$FILE" "has trailing blank lines" + RESULT=false + fi + if echo "$FILE" | grep -Eq 'include' && + grep -E '^#(define|ifndef)' -- "$FILE" | head -2 | grep -q ' '; then + complain "$PWD/$FILE" "has tabs in include guards" + RESULT=false + fi + # TODO: Wrong include guards. + # TODO: Include guards being set to 1. + $RESULT +} + +# TODO: Some of these patterns should also apply to build-aux, and maybe also +# partially to libm. Makefile and kblayout should also not have whitespace +# problems. +for MODULE in $(git ls-files | grep / | sed 's,/.*,,' | sort -u | grep -Ev '^(build-aux|doc|etc|libm|share)$'); do + cd "$MODULE" + for FILE in $(git ls-files | grep -Ev '^include/' | grep -Ev '((^|/)(Makefile|\.gitignore|tixbuildinfo)|\.([0-9]|kblayout|f16|rgb))$'); do + verify_source "$FILE" + done + if [ -e "$MODULE/include" ]; then + cd include + for FILE in $(cd $MODULE/include && git ls-files); do + verify_source "$FILE" + done + cd .. + fi + cd .. +done + +$RESULT diff --git a/build-aux/verify-headers-in-configuration.sh b/build-aux/verify-headers-in-configuration.sh new file mode 100755 index 00000000..c9b255fe --- /dev/null +++ b/build-aux/verify-headers-in-configuration.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# Verifies whether the system headers compiles with the mix of architecture, +# language standard version, and feature macros. +set -e +target="$1" +case $target in +i686-sortix) libm_machine=libm/arch/i387 ;; +x86_64-sortix) libm_machine=libm/arch/x86_64 ;; +esac +std="$2" +feature="$3" +(printf '.PHONY: all\n' + printf 'all:\n' + for header in \ + $(find libc/include -type f | sort) \ + $(find libm/include -type f | sort) \ + $(find kernel/include -type f | grep -Ev '^kernel/include/sortix/kernel/'| sort); do + case $std in + *-ansi*pedantic* | \ + *89*pedantic* | \ + *90*pedantic*) + case $header in + libc/include/assert.h | \ + libc/include/ctype.h | \ + libc/include/errno.h | \ + libc/include/limits.h | \ + libc/include/locale.h | \ + libc/include/setjmp.h | \ + libc/include/signal.h | \ + libc/include/stdarg.h | \ + libc/include/stddef.h | \ + libc/include/stdlib.h | \ + libc/include/string.h | \ + libm/include/float.h | \ + libm/include/math.h) ;; + *) continue ;; + esac ;; + # TODO: Unsupported because fpos_t and time_t must be long long. + # These headers could use typedef __extension__ long long foo; + #libc/include/stdio.h | \ + #libc/include/time.h | \ + *99*pedantic*) + case $header in + libc/include/assert.h | \ + libc/include/ctype.h | \ + libc/include/errno.h | \ + libc/include/inttypes.h | \ + libc/include/iso646.h | \ + libc/include/limits.h | \ + libc/include/locale.h | \ + libc/include/setjmp.h | \ + libc/include/signal.h | \ + libc/include/stdarg.h | \ + libc/include/stdbool.h | \ + libc/include/stddef.h | \ + libc/include/stdint.h | \ + libc/include/stdio.h | \ + libc/include/stdlib.h | \ + libc/include/string.h | \ + libc/include/time.h | \ + libc/include/wchar.h | \ + libc/include/wctype.h | \ + libm/include/complex.h | \ + libm/include/float.h | \ + libm/include/fenv.h | \ + libm/include/math.h | \ + libm/include/tgmath.h) ;; + *) continue ;; + esac ;; + *11*pedantic*) + case $header in + libc/include/assert.h | \ + libc/include/ctype.h | \ + libc/include/errno.h | \ + libc/include/inttypes.h | \ + libc/include/iso646.h | \ + libc/include/limits.h | \ + libc/include/locale.h | \ + libc/include/setjmp.h | \ + libc/include/signal.h | \ + libc/include/stdalign.h | \ + libc/include/stdarg.h | \ + libc/include/stdatomic.h | \ + libc/include/stdbool.h | \ + libc/include/stddef.h | \ + libc/include/stdint.h | \ + libc/include/stdio.h | \ + libc/include/stdlib.h | \ + libc/include/stdnoreturn.h | \ + libc/include/string.h | \ + libc/include/threads.h | \ + libc/include/time.h | \ + libc/include/uchar.h | \ + libc/include/wchar.h | \ + libc/include/wctype.h | \ + libm/include/complex.h | \ + libm/include/float.h | \ + libm/include/fenv.h | \ + libm/include/math.h | \ + libm/include/tgmath.h) ;; + *) continue ;; + esac ;; + esac + printf 'all: %s\n' "$header" + printf '.PHONY: %s\n' "$header" + printf '%s:\n' "$header" + case $std in + *++*) + printf '\t@%s\n' "$target-g++ $std $feature -c $header -o /dev/null -O3 -Wall -Wextra -Wsystem-headers -Werror -I libc/include -I libm/include -I $libm_machine -I kernel/include" + ;; + *) + printf '\t@%s\n' "$target-gcc $std $feature -c $header -o /dev/null -O3 -Wall -Wextra -Wsystem-headers -Werror -I libc/include -I libm/include -I $libm_machine -I kernel/include" + ;; + esac + done) | make -f - --no-print-directory diff --git a/build-aux/verify-headers.sh b/build-aux/verify-headers.sh new file mode 100755 index 00000000..f2bd74a9 --- /dev/null +++ b/build-aux/verify-headers.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Verifies whether the system headers compiles on supported mixes of +# architectures, language standard versions, and feature macros. +set -e +if [ "$#" = 0 ]; then + set i686-sortix x86_64-sortix +fi +for target; do + for feature in "" "-D_POSIX_C_SOURCE=200809L" "-D_XOPEN_SOURCE=700" "-D_SORTIX_SOURCE"; do + for std in \ + "-ansi -pedantic-errors" \ + "-std=c89 -pedantic-errors" \ + "-std=c90 -pedantic-errors" \ + "-std=c99 -pedantic-errors" \ + "-std=c11 -pedantic-errors" \ + "-std=c89" \ + "-std=gnu89" \ + "-std=c90" \ + "-std=gnu90" \ + "-std=c99" \ + "-std=gnu99" \ + "-std=c11" \ + "-std=gnu11" \ + "-std=c++98" \ + "-std=gnu++98" \ + "-std=c++11" \ + "-std=gnu++11" \ + "-std=c++14" \ + "-std=gnu++14" \ + ; do + case "$std $feature" in + *pedantic*-D_POSIX_SOURCE* | \ + *pedantic*-D_POSIX_C_SOURCE* | \ + *pedantic*-D_XOPEN_SOURCE* | \ + *pedantic*-D_SORTIX_SOURCE*) + continue ;; + esac + echo "$(dirname -- "$0")/verify-headers-in-configuration.sh" "$target" "\"$std\"" "\"$feature\"" + "$(dirname -- "$0")/verify-headers-in-configuration.sh" "$target" "$std" "$feature" + done + done + # TODO: Also verify kernel c++ headers. +done diff --git a/build-aux/verify-manual.sh b/build-aux/verify-manual.sh new file mode 100755 index 00000000..4ab56f59 --- /dev/null +++ b/build-aux/verify-manual.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Checks if mandoc -Tlint warns about any manual pages. +RESULT=true +for MANUAL in $(git ls-files | grep -E '\.[0-9]$' | grep -Ev '^libm/man/'); do + # TODO: mandoc on Sortix can't parse .Dd dates at the moment. + #if ! mandoc -Tlint $MANUAL; then + if mandoc -Tlint $MANUAL 2>&1 | grep -Ev "WARNING: cannot parse date"; then + RESULT=false + fi +done +$RESULT diff --git a/share/man/man7/development.7 b/share/man/man7/development.7 index 35d176dd..9c977e39 100644 --- a/share/man/man7/development.7 +++ b/share/man/man7/development.7 @@ -106,6 +106,17 @@ directory after making .It Sy mostlyclean Clean everything except binary packages. .Sy ( clean-builds , clean-core , clean-ports , clean-release , clean-sysroot ) +.It Sy presubmit +Verify the coding style is followed +.Sy ( verify-coding-style ) , +the manual pages does not have lints +.Sy ( verify-manual ) , +the build tools compile +.Sy ( verify-build-tools ) , +that everything compiles without warnings on all architectures +.Sy ( verify-build ) , +and the system headers works in all supported configurations +.Sy ( verify-headers ) . .It Sy release Make .Sy iso @@ -321,6 +332,11 @@ A good approach is to set up your own local development branch and work there: git commit -m 'Add hello(1).' .Ed .Pp +The +.Sy presubmit +makefile target can be used to verify your work needs some of the development +conventions. +.Pp You can then easily prepare your a set of patches for upstream submission: .Bd -literal git format-patch master..local