sonar

Scan files at memory bandwidth speed.
Log | Files | Refs

commit 620f76b84c78cee762f8f3d100051ecf62398cc6
parent 0e96291b65c4c9de2ef9a858cf45d5fe85349977
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Wed, 23 Sep 2026 14:59:00 -0300

sonar: replace makefile with justfile

The recipes are the same: ASan debug build, optimised release, per-package
tests, check, clean, plus the standard install. What goes is make's
timestamp-based skipping of an up-to-date binary; an Odin build of this size
is quick enough that a rebuild on every call costs less than the second
build system it took to avoid it.

Diffstat:
DMakefile | 54------------------------------------------------------
Ajustfile | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 54 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,54 +0,0 @@ -# sonar build -# -# make debug build with AddressSanitizer -> build/debug/sonar.exe -# make release optimised build -> build/release/sonar.exe -# make test run the package tests under ASan -> build/test/ -# make check type-check both modes without producing a binary -# make clean remove build/ -# -# Debug and test builds carry -sanitize:address. The debug allocator poisons its -# guard bytes and freed blocks, so instrumented reads past the end or after free trap -# at the faulting instruction. Pass SAN= to build without it (e.g. make debug SAN=). -# -# GNU Make runs recipes through sh even on Windows (scoop's make finds sh.exe), so -# the recipes use POSIX commands. Odin does not create output directories, hence the -# order-only directory prerequisites. - -ODIN ?= odin -BUILD := build -FLAGS := -vet -strict-style -SAN ?= -sanitize:address -EXE := $(if $(filter Windows_NT,$(OS)),.exe,) - -SRC := $(wildcard *.odin) $(wildcard ntfs/*.odin) $(wildcard debug/*.odin) $(wildcard flow/*.odin) $(wildcard scan/*.odin) $(wildcard walk/*.odin) - -.PHONY: all debug release test check clean - -all: debug - -debug: $(BUILD)/debug/sonar$(EXE) - -release: $(BUILD)/release/sonar$(EXE) - -$(BUILD)/debug/sonar$(EXE): $(SRC) | $(BUILD)/debug - $(ODIN) build . -debug $(SAN) $(FLAGS) -out:$@ - -$(BUILD)/release/sonar$(EXE): $(SRC) | $(BUILD)/release - $(ODIN) build . -o:speed $(FLAGS) -out:$@ - -test: | $(BUILD)/test - $(ODIN) test ntfs -debug $(SAN) $(FLAGS) -out:$(BUILD)/test/ntfs$(EXE) - $(ODIN) test flow -debug $(SAN) $(FLAGS) -out:$(BUILD)/test/flow$(EXE) - $(ODIN) test scan -debug $(SAN) $(FLAGS) -out:$(BUILD)/test/scan$(EXE) - $(ODIN) test walk -debug $(SAN) $(FLAGS) -out:$(BUILD)/test/walk$(EXE) - $(ODIN) test . -debug $(SAN) $(FLAGS) -out:$(BUILD)/test/main$(EXE) - -check: - $(ODIN) check . $(FLAGS) - $(ODIN) check . -debug $(FLAGS) - -$(BUILD)/debug $(BUILD)/release $(BUILD)/test: - mkdir -p $@ - -clean: - rm -rf $(BUILD) diff --git a/justfile b/justfile @@ -0,0 +1,72 @@ +# Standard recipes: build (debug), release, clean, test, install. +# +# just build debug build with AddressSanitizer -> build/debug/sonar +# just release optimised build -> build/release/sonar +# just test run the package tests under ASan -> build/test/ +# just check type-check both modes without producing a binary +# just clean remove build/ +# +# Debug and test builds carry -sanitize:address. The debug allocator poisons its +# guard bytes and freed blocks, so instrumented reads past the end or after free +# trap at the faulting instruction. Pass SAN= to build without it: +# `SAN= just build`. Odin does not create output directories, hence the mkdir. + +odin := env("ODIN", "odin") +flags := "-vet -strict-style" +san := env("SAN", "-sanitize:address") +exe := if os() == "windows" { ".exe" } else { "" } +bin := "sonar" + +# `just` alone lists the recipes. +default: + @just --list --unsorted + +# Debug build with AddressSanitizer -> build/debug/sonar +build: + mkdir -p build/debug + {{odin}} build . -debug {{san}} {{flags}} -out:build/debug/{{bin}}{{exe}} + +# Optimised build -> build/release/sonar +release: + mkdir -p build/release + {{odin}} build . -o:speed {{flags}} -out:build/release/{{bin}}{{exe}} + +# Run every package's tests under ASan -> build/test/ +test: + mkdir -p build/test + {{odin}} test ntfs -debug {{san}} {{flags}} -out:build/test/ntfs{{exe}} + {{odin}} test flow -debug {{san}} {{flags}} -out:build/test/flow{{exe}} + {{odin}} test scan -debug {{san}} {{flags}} -out:build/test/scan{{exe}} + {{odin}} test walk -debug {{san}} {{flags}} -out:build/test/walk{{exe}} + {{odin}} test . -debug {{san}} {{flags}} -out:build/test/main{{exe}} + +# Type-check both modes without producing a binary. +check: + {{odin}} check . {{flags}} + {{odin}} check . -debug {{flags}} + +# Remove build/. +clean: + rm -rf build + +# Copy the release binary to a directory on PATH. An installed copy is replaced in +# place; otherwise ~/.local/bin, ~/bin, GOBIN, GOPATH/bin, /usr/local/bin, else the +# first writable PATH entry. +install: release + #!/usr/bin/env bash + set -euo pipefail + dest="" + if existing=$(command -v {{bin}} 2>/dev/null) && [[ -w ${existing%/*} ]]; then + dest=${existing%/*} + fi + gopath=$(go env GOPATH 2>/dev/null || true); gobin=$(go env GOBIN 2>/dev/null || true) + for d in "$HOME/.local/bin" "$HOME/bin" "$gobin" "${gopath:+$gopath/bin}" /usr/local/bin; do + [[ -z $dest && -n $d && -d $d && -w $d && ":$PATH:" == *":$d:"* ]] && dest=$d + done + if [[ -z $dest ]]; then + IFS=: read -ra dirs <<<"$PATH" + for d in "${dirs[@]}"; do [[ -d $d && -w $d ]] && { dest=$d; break; }; done + fi + [[ -n $dest ]] || { echo "install: no writable directory on PATH" >&2; exit 1; } + install -m 755 build/release/{{bin}}{{exe}} "$dest/{{bin}}" + echo "installed $dest/{{bin}}"