Diff options
Diffstat (limited to '')
| -rwxr-xr-x | tools/build-development.sh | 36 | |
| -rwxr-xr-x | tools/build-release.sh | 33 | |
| -rwxr-xr-x | tools/serve.py | 15 |
3 files changed, 51 insertions, 33 deletions
diff --git a/tools/build-development.sh b/tools/build-development.sh index 79b9259..00ff569 100755 --- a/tools/build-development.sh +++ b/tools/build-development.sh @@ -1,13 +1,10 @@ #!/bin/sh -# Build cgit for development and debugging. It compiles without optimisation -# and with full debug information, holds the sources to git's DEVELOPER -# warnings, and links in AddressSanitizer and UndefinedBehaviorSanitizer, so a -# memory error or undefined behaviour stops the program where it happens. With -# clang it also leaves a compilation database in build/compile_commands.json, -# where a language server looks for one, and with ctags a tags file in -# build/tags. The sanitizers make cgit slow, so the result is for testing and -# debugging rather than serving. +# Build cgit for development and debugging. The sanitizers the compiler offers +# stop the program at a memory error or undefined behaviour, which makes it +# slow, so the result is for testing rather than serving. With clang it also +# leaves a compilation database in build/ for a language server, and with +# ctags a tags file there. # # Any arguments go on to make, the way Lua flags do where pkg-config cannot # find Lua: @@ -18,14 +15,33 @@ set -eu -# Every make target below is written relative to the repository root. cd "$(dirname "$0")/.." # The build starts from clean so the bundled git objects pick up the same # flags, and cleanall rather than clean because only cleanall descends into # vendor/git. make cleanall -make "$@" CFLAGS="-O0 -g3" DEVELOPER=1 SANITIZE=address,undefined \ + +# Named once, so the probe and the build use the same compiler. CC goes on +# make's command line because git's Makefile sets it, which would override +# the one from the environment. +CC=${CC:-cc} + +# OpenBSD's compiler has no AddressSanitizer, so the build falls back to the +# undefined behaviour checks alone, and to no sanitizer where neither links. +probe=$(mktemp "${TMPDIR:-/tmp}/cgit-probe.XXXXXX") +trap 'rm -f "$probe" "$probe.c"' EXIT +printf 'int main(void){return 0;}\n' >"$probe.c" +sanitize="" +for checks in address,undefined undefined +do + if $CC -fsanitize="$checks" -o "$probe" "$probe.c" >/dev/null 2>&1 + then + sanitize="SANITIZE=$checks" + break + fi +done +make "$@" CC="$CC" CFLAGS="-O0 -g3" DEVELOPER=1 $sanitize \ GENERATE_COMPILATION_DATABASE=yes # clang writes one entry per object under vendor/git/compile_commands, each diff --git a/tools/build-release.sh b/tools/build-release.sh index ade979c..b5e6faa 100755 --- a/tools/build-release.sh +++ b/tools/build-release.sh @@ -1,8 +1,9 @@ #!/bin/sh -# Build cgit for a release with Linux hardening flags, which are ELF and GCC or -# Clang specific. The flags add a stack protector, fortified libc calls, a -# position independent executable, and full RELRO. By default Lua is pinned off +# Build cgit for a release with hardening flags: a stack protector, fortified +# libc calls, a position independent executable, and full RELRO. Each flag a +# toolchain may lack is probed first and left out where it is missing, so the +# script builds on Linux, the BSDs and macOS alike. By default Lua is pinned off # so the binary needs no Lua at runtime, and running it as # ./tools/build-release.sh lua links in the backend behind the "lua:" filter # prefix instead, which needs a Lua dev package installed. @@ -27,7 +28,6 @@ lua) ;; esac -# Every make target below is written relative to the repository root. cd "$(dirname "$0")/.." CC=${CC:-cc} @@ -71,17 +71,24 @@ then CFLAGS="$CFLAGS -ffile-prefix-map=$PWD=." fi -LDFLAGS="-pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack" +# The linker flags are probed the same way, since Apple's linker has no -z +# options and makes a position independent executable unasked. +LDFLAGS="" +if supports "-fPIE -pie" +then + LDFLAGS="-pie" +fi +for flag in -Wl,-z,relro,-z,now -Wl,-z,noexecstack +do + if supports "$flag" + then + LDFLAGS="$LDFLAGS $flag" + fi +done # These reach only the cgit objects, so git's own sources are not held to them. # -Wformat-security is an error because a non-literal format with no arguments -# is never intentional. -Wformat-nonliteral would catch the module-link shape, -# a non-literal that does take arguments, but it also fires on va_list -# forwarding and on local format constants, so it is left to manual runs when -# touching anything that formats. -# -# make cgit CGIT_EXTRA_CFLAGS=-Wformat-nonliteral -# +# is never intentional. CGIT_EXTRA_CFLAGS="-Wformat -Wformat-security -Werror=format-security" # The build starts from clean so the bundled git objects pick up the same @@ -90,5 +97,5 @@ CGIT_EXTRA_CFLAGS="-Wformat -Wformat-security -Werror=format-security" # which would override the one from the environment the flags were probed # with. make cleanall -exec make "$@" CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \ +make "$@" CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \ CGIT_EXTRA_CFLAGS="$CGIT_EXTRA_CFLAGS" diff --git a/tools/serve.py b/tools/serve.py index 8924e53..492345e 100755 --- a/tools/serve.py +++ b/tools/serve.py @@ -65,12 +65,9 @@ def split_cgi_output(output: bytes) -> CgiResponse: The header block ends at the first blank line. cgit ends its lines with a bare LF while a filter writing its own headers may use CRLF, so whichever - terminator appears earliest is the real one. Looking for CRLF everywhere - before falling back to LF would instead find the first CRLF in the body, - and a commit message with DOS line endings has one, which swallowed the - whole document head into the headers. Splitting on the separator rather - than on a non-empty body keeps a legitimately empty body, such as the one - a redirect leaves behind, from being read as headers. + terminator appears earliest is the real one, and a later blank line of the + other kind, such as one in a commit message with DOS line endings, belongs + to the body. The body may also be empty, as a redirect leaves it. """ ends = [(at, len(sep)) for sep in (b"\r\n\r\n", b"\n\n") if (at := output.find(sep)) >= 0] if ends: @@ -233,8 +230,6 @@ class CgitHandler(BaseHTTPRequestHandler): _ = self.wfile.write(response.body) def log_message(self, format: str, *args: object) -> None: - # The signature matches BaseHTTPRequestHandler, so the parameter here - # shadows the builtin of the same name. _ = sys.stderr.write(f" {format % args}\n") @@ -262,14 +257,14 @@ class Options(argparse.Namespace): data: str = str(REPO_ROOT / "assets") -def parse_args(argv: list[str] | None = None) -> Options: +def parse_args() -> Options: parser = argparse.ArgumentParser(description="Preview cgit locally.") _ = parser.add_argument("--config", default=Options.config, help="path to cgitrc (default: ./cgitrc)") _ = parser.add_argument("--port", type=int, default=Options.port) _ = parser.add_argument("--host", default=Options.host) _ = parser.add_argument("--cgit", default=Options.cgit, help="path to the cgit binary") _ = parser.add_argument("--data", default=Options.data, help="directory holding cgit.css, cgit.js, images") - return parser.parse_args(argv, namespace=Options()) + return parser.parse_args(namespace=Options()) def main() -> None: |
