From 785a3f2d777627f39bed44f4ae7a0180d5184109 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 19 Oct 2023 16:37:47 -0400 Subject: tests: Refactor implementation into separate files --- tests/util.sh | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 tests/util.sh (limited to 'tests/util.sh') diff --git a/tests/util.sh b/tests/util.sh new file mode 100644 index 0000000..5131522 --- /dev/null +++ b/tests/util.sh @@ -0,0 +1,189 @@ +#!/hint/bash + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +## Utility functions + +# Portable realpath(1) +_realpath() ( + cd "$(dirname -- "$1")" + echo "$PWD/$(basename -- "$1")" +) + +# Globals +TESTS=$(_realpath "$TESTS") +if [ "${BUILDDIR-}" ]; then + BIN=$(_realpath "$BUILDDIR/bin") +else + BIN=$(_realpath "$TESTS/../bin") +fi +MKSOCK="$BIN/tests/mksock" +XTOUCH="$BIN/tests/xtouch" +UNAME=$(uname) + +# Standardize the environment +stdenv() { + export LC_ALL=C + export TZ=UTC0 + + local SAN_OPTIONS="halt_on_error=1:log_to_syslog=0" + export ASAN_OPTIONS="$SAN_OPTIONS" + export LSAN_OPTIONS="$SAN_OPTIONS" + export MSAN_OPTIONS="$SAN_OPTIONS" + export TSAN_OPTIONS="$SAN_OPTIONS" + export UBSAN_OPTIONS="$SAN_OPTIONS" + + export LS_COLORS="" + unset BFS_COLORS + + if [ "$UNAME" = Darwin ]; then + # ASan on macOS likes to report + # + # malloc: nano zone abandoned due to inability to preallocate reserved vm space. + # + # to syslog, which as a side effect opens a socket which might take the + # place of one of the standard streams if the process is launched with + # it closed. This environment variable avoids the message. + export MallocNanoZone=0 + fi + + # Close non-standard inherited fds + if [ -d /proc/self/fd ]; then + local fds=/proc/self/fd + else + local fds=/dev/fd + fi + + for fd in "$fds"/*; do + if [ ! -e "$fd" ]; then + continue + fi + + local fd="${fd##*/}" + if ((fd > 2)); then + eval "exec ${fd}<&-" + fi + done + + # Close stdin so bfs doesn't think we're interactive + # dup() the standard fds for logging even when redirected + exec &1 4>&2 +} + +# Drop root priviliges or bail +drop_root() { + if command -v capsh &>/dev/null; then + if capsh --has-p=cap_dac_override &>/dev/null || capsh --has-p=cap_dac_read_search &>/dev/null; then + if [ -n "${BFS_TRIED_DROP:-}" ]; then + color >&2 <&2 <&2 < 0)); then + printf ' %q' "$@" + fi +} + +# Run a command when this (sub)shell exits +defer() { + # Refresh trap state before trap -p + # See https://unix.stackexchange.com/a/556888/56202 + trap -- KILL + + # Check if the EXIT trap is already set + if ! trap -p EXIT | grep -q pop_defers; then + DEFER_CMDS=() + DEFER_LINES=() + DEFER_FILES=() + trap pop_defers EXIT + fi + + DEFER_CMDS+=("$(quote "$@")") + + local line file + read -r line file < <(caller) + DEFER_LINES+=("$line") + DEFER_FILES+=("$file") +} + +# Pop a single command from the defer stack and run it +pop_defer() { + local cmd="${DEFER_CMDS[-1]}" + local file="${DEFER_FILES[-1]}" + local line="${DEFER_LINES[-1]}" + unset "DEFER_CMDS[-1]" + unset "DEFER_FILES[-1]" + unset "DEFER_LINES[-1]" + + local ret=0 + eval "$cmd" || ret=$? + + if ((ret != 0)); then + debug "$file" $line "${RED}error $ret${RST}" "defer $cmd" >&4 + fi + + return $ret +} + +# Run all deferred commands +pop_defers() { + local ret=0 + + while ((${#DEFER_CMDS[@]} > 0)); do + pop_defer || ret=$? + done + + return $ret +} -- cgit v1.2.3 From 13053c43ee8f5a2a5f7a66258d047e1b68203da3 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 19 Oct 2023 17:05:36 -0400 Subject: tests: Don't unset array[-1] This was only added in Bash 4.3 which is too new for macOS. --- tests/util.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'tests/util.sh') diff --git a/tests/util.sh b/tests/util.sh index 5131522..efc24b0 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -160,12 +160,13 @@ defer() { # Pop a single command from the defer stack and run it pop_defer() { - local cmd="${DEFER_CMDS[-1]}" - local file="${DEFER_FILES[-1]}" - local line="${DEFER_LINES[-1]}" - unset "DEFER_CMDS[-1]" - unset "DEFER_FILES[-1]" - unset "DEFER_LINES[-1]" + local i=$((${#DEFER_CMDS[@]} - 1)) + local cmd="${DEFER_CMDS[$i]}" + local file="${DEFER_FILES[$i]}" + local line="${DEFER_LINES[$i]}" + unset "DEFER_CMDS[$i]" + unset "DEFER_FILES[$i]" + unset "DEFER_LINES[$i]" local ret=0 eval "$cmd" || ret=$? -- cgit v1.2.3 From 60366e4583a1d148dd5f8171c9148ebb98890478 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 20 Oct 2023 15:52:45 -0400 Subject: tests/color: Remove some useless cats --- tests/color.sh | 12 +++------- tests/getopts.sh | 10 ++++---- tests/run.sh | 73 +++++++++++++++++++++++++++++--------------------------- tests/util.sh | 8 +++---- 4 files changed, 50 insertions(+), 53 deletions(-) (limited to 'tests/util.sh') diff --git a/tests/color.sh b/tests/color.sh index 0d6ef68..805d2b8 100644 --- a/tests/color.sh +++ b/tests/color.sh @@ -24,20 +24,14 @@ color_fd() { color_fd 1 && COLOR_STDOUT=1 || COLOR_STDOUT=0 color_fd 2 && COLOR_STDERR=1 || COLOR_STDERR=0 -# Save these in case the tests unset PATH -CAT=$(command -v cat) +# Save this in case the tests unset PATH SED=$(command -v sed) # Filter out escape sequences if necessary color() { if color_fd 1; then - "$CAT" + "$@" else - "$SED" $'s/\e\\[[^m]*m//g' + "$@" | "$SED" $'s/\e\\[[^m]*m//g' fi } - -# printf with auto-detected color support -cprintf() { - printf "$@" | color -} diff --git a/tests/getopts.sh b/tests/getopts.sh index 6616a4a..7d3ef4b 100644 --- a/tests/getopts.sh +++ b/tests/getopts.sh @@ -8,7 +8,7 @@ # Print usage information usage() { local pad=$(printf "%*s" ${#0} "") - color <&2 + color printf "${RED}error:${RST} Unrecognized option '%s'.\n\n" "$arg" >&2 usage >&2 exit 1 ;; @@ -149,9 +149,9 @@ parse_args() { done if ((${#TEST_CASES[@]} == 0)); then - cprintf "${RED}error:${RST} No tests matched" >&2 - cprintf " ${BLD}%s${RST}" "${PATTERNS[@]}" >&2 - cprintf ".\n\n" >&2 + color printf "${RED}error:${RST} No tests matched" >&2 + color printf " ${BLD}%s${RST}" "${PATTERNS[@]}" >&2 + color printf ".\n\n" >&2 usage >&2 exit 1 fi diff --git a/tests/run.sh b/tests/run.sh index 70c9cc2..5fcccad 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -93,7 +93,7 @@ run_tests() { else ((++failed)) ((VERBOSE_ERRORS)) || cat "$TMP/$TEST.err" >&2 - cprintf "${BOL}${RED}%s failed!${RST}\n" "$TEST" + color printf "${BOL}${RED}%s failed!${RST}\n" "$TEST" ((STOP)) && break fi done @@ -101,13 +101,13 @@ run_tests() { printf "${BOL}" if ((passed > 0)); then - cprintf "${GRN}tests passed: %d${RST}\n" "$passed" + color printf "${GRN}tests passed: %d${RST}\n" "$passed" fi if ((skipped > 0)); then - cprintf "${CYN}tests skipped: %s${RST}\n" "$skipped" + color printf "${CYN}tests skipped: %s${RST}\n" "$skipped" fi if ((failed > 0)); then - cprintf "${RED}tests failed: %s${RST}\n" "$failed" + color printf "${RED}tests failed: %s${RST}\n" "$failed" exit 1 fi } @@ -126,7 +126,7 @@ skip() { debug "$file" $line "${CYN}$TEST skipped!${RST}" "$(awk "NR == $line" "$file")" >&3 } elif ((VERBOSE_TESTS)); then - cprintf "${BOL}${CYN}%s skipped!${RST}\n" "$TEST" + color printf "${BOL}${CYN}%s skipped!${RST}\n" "$TEST" fi exit $EX_SKIP @@ -175,39 +175,42 @@ set_acl() { } # Print a bfs invocation for --verbose=commands -bfs_verbose() ( - if ((!VERBOSE_COMMANDS)); then - return +bfs_verbose() { + if ((VERBOSE_COMMANDS)); then + ( + # Close some fds to make room for the pipe, + # even with extremely low ulimit -n + exec >&- 4>&- + exec >&3 3>&- + color bfs_verbose_impl "$@" + ) fi +} - # Free up an fd for the pipe - exec 4>&- - - { - printf "${GRN}%q${RST} " "${BFS[@]}" - - local expr_started= - for arg; do - if [[ $arg == -[A-Z]* ]]; then - printf "${CYN}%q${RST} " "$arg" - elif [[ $arg == [\(!] || $arg == -[ao] || $arg == -and || $arg == -or || $arg == -not ]]; then - expr_started=yes - printf "${RED}%q${RST} " "$arg" - elif [[ $expr_started && $arg == [\),] ]]; then - printf "${RED}%q${RST} " "$arg" - elif [[ $arg == -?* ]]; then - expr_started=yes - printf "${BLU}%q${RST} " "$arg" - elif [ "$expr_started" ]; then - printf "${BLD}%q${RST} " "$arg" - else - printf "${MAG}%q${RST} " "$arg" - fi - done +bfs_verbose_impl() { + printf "${GRN}%q${RST} " "${BFS[@]}" + + local expr_started= + for arg; do + if [[ $arg == -[A-Z]* ]]; then + printf "${CYN}%q${RST} " "$arg" + elif [[ $arg == [\(!] || $arg == -[ao] || $arg == -and || $arg == -or || $arg == -not ]]; then + expr_started=yes + printf "${RED}%q${RST} " "$arg" + elif [[ $expr_started && $arg == [\),] ]]; then + printf "${RED}%q${RST} " "$arg" + elif [[ $arg == -?* ]]; then + expr_started=yes + printf "${BLU}%q${RST} " "$arg" + elif [ "$expr_started" ]; then + printf "${BLD}%q${RST} " "$arg" + else + printf "${MAG}%q${RST} " "$arg" + fi + done - printf '\n' - } | color >&3 -) + printf '\n' +} # Run the bfs we're testing invoke_bfs() { diff --git a/tests/util.sh b/tests/util.sh index efc24b0..31a7b6c 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -76,14 +76,14 @@ drop_root() { if command -v capsh &>/dev/null; then if capsh --has-p=cap_dac_override &>/dev/null || capsh --has-p=cap_dac_read_search &>/dev/null; then if [ -n "${BFS_TRIED_DROP:-}" ]; then - color >&2 <&2 <&2 <&2 <&2 <&2 < Date: Mon, 23 Oct 2023 11:42:33 -0400 Subject: tests: Fix Bash 3 compatibility --- tests/bfs/execdir_plus_nonexistent.sh | 6 ++--- tests/common/execdir_nonexistent.sh | 6 ++--- tests/posix/L_loops.sh | 4 ++-- tests/posix/exec_nonexistent.sh | 7 ++---- tests/posix/exec_plus_nonexistent.sh | 6 ++--- tests/run.sh | 44 +++++++++++++++++++++++++---------- tests/util.sh | 11 ++++----- 7 files changed, 47 insertions(+), 37 deletions(-) (limited to 'tests/util.sh') diff --git a/tests/bfs/execdir_plus_nonexistent.sh b/tests/bfs/execdir_plus_nonexistent.sh index e3b4d2d..ed7ed56 100644 --- a/tests/bfs/execdir_plus_nonexistent.sh +++ b/tests/bfs/execdir_plus_nonexistent.sh @@ -1,4 +1,2 @@ -! stderr=$(invoke_bfs basic -execdir "$TESTS/nonexistent" {} + 2>&1 >/dev/null) -[ -n "$stderr" ] - -! bfs_diff basic -execdir "$TESTS/nonexistent" {} + -print +bfs_diff basic -execdir "$TESTS/nonexistent" {} + -print 2>"$TEST/err" && fail +test -s "$TEST/err" diff --git a/tests/common/execdir_nonexistent.sh b/tests/common/execdir_nonexistent.sh index 4bb4fdb..0ec013c 100644 --- a/tests/common/execdir_nonexistent.sh +++ b/tests/common/execdir_nonexistent.sh @@ -1,4 +1,2 @@ -! stderr=$(invoke_bfs basic -execdir "$TESTS/nonexistent" {} \; 2>&1 >/dev/null) -[ -n "$stderr" ] - -! bfs_diff basic -print -execdir "$TESTS/nonexistent" {} \; -print +bfs_diff basic -print -execdir "$TESTS/nonexistent" {} \; -print 2>"$TEST/err" && fail +test -s "$TEST/err" diff --git a/tests/posix/L_loops.sh b/tests/posix/L_loops.sh index 1314401..01b7efc 100644 --- a/tests/posix/L_loops.sh +++ b/tests/posix/L_loops.sh @@ -1,4 +1,4 @@ # POSIX says it's okay to either stop or keep going on seeing a filesystem # loop, as long as a diagnostic is printed -! errors=$(invoke_bfs -L loops 2>&1 >/dev/null) -[ -n "$errors" ] +invoke_bfs -L loops >/dev/null 2>"$OUT" && fail +test -s "$OUT" diff --git a/tests/posix/exec_nonexistent.sh b/tests/posix/exec_nonexistent.sh index 901be86..a9ff052 100644 --- a/tests/posix/exec_nonexistent.sh +++ b/tests/posix/exec_nonexistent.sh @@ -1,7 +1,4 @@ # Failure to execute the command should lead to an error message and # non-zero exit status. See https://unix.stackexchange.com/q/704522/56202 - -! stderr=$(invoke_bfs basic -exec "$TESTS/nonexistent" {} \; 2>&1 >/dev/null) -[ -n "$stderr" ] - -! bfs_diff basic -print -exec "$TESTS/nonexistent" {} \; -print +bfs_diff basic -print -exec "$TESTS/nonexistent" {} \; -print 2>"$TEST/err" && fail +test -s "$TEST/err" diff --git a/tests/posix/exec_plus_nonexistent.sh b/tests/posix/exec_plus_nonexistent.sh index 6bddc67..24582a3 100644 --- a/tests/posix/exec_plus_nonexistent.sh +++ b/tests/posix/exec_plus_nonexistent.sh @@ -1,4 +1,2 @@ -! stderr=$(invoke_bfs basic -exec "$TESTS/nonexistent" {} + 2>&1 >/dev/null) -[ -n "$stderr" ] - -! bfs_diff basic -exec "$TESTS/nonexistent" {} + -print +bfs_diff basic -exec "$TESTS/nonexistent" {} + -print 2>"$TEST/err" && fail +test -s "$TEST/err" diff --git a/tests/run.sh b/tests/run.sh index b46fde6..d581476 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -47,7 +47,7 @@ bg_test() { if ((VERBOSE_ERRORS)); then run_test "$1" else - run_test "$1" 2>"$TMP/TEST.err" + run_test "$1" 2>"$TMP/$TEST.err" fi ret=$? @@ -59,9 +59,21 @@ bg_test() { return $ret } -# Reap a background job -reap() { - wait -n +# Wait for any background job to complete +if ((BASH_VERSINFO[0] > 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3))); then + wait_any() { + wait -n + } +else + wait_any() { + read -ra jobs < <(jobs -p) + wait ${jobs[0]} + } +fi + +# Wait for a background test to finish +wait_test() { + wait_any ret=$? ((BG--)) @@ -118,7 +130,7 @@ run_tests() { OUT="$TMP/$TEST.out" if ((BG >= JOBS)); then - reap + wait_test fi ((++BG)) @@ -126,7 +138,7 @@ run_tests() { done while ((BG > 0)); do - reap + wait_test done printf "${BOL}" @@ -145,6 +157,14 @@ run_tests() { ## Utilities for the tests themselves +# Default return value for failed tests +EX_FAIL=1 + +# Fail the current test +fail() { + exit $EX_FAIL +} + # Return value when a test is skipped EX_SKIP=77 @@ -166,9 +186,9 @@ skip() { # Run a command and check its exit status check_exit() { local expected="$1" - local actual="0" + local actual=0 shift - "$@" || actual="$?" + "$@" || actual=$? ((actual == expected)) } @@ -253,9 +273,9 @@ invoke_bfs() { # Allow bfs to fail, but not crash if ((ret > 125)); then - exit "$ret" + exit $ret else - return "$ret" + return $ret fi } @@ -275,9 +295,9 @@ bfs_pty() { "$UNBUFFER" bash -c 'stty cols 80 rows 24 && "$@"' bash "${BFS[@]}" "$@" || ret=$? if ((ret > 125)); then - exit "$ret" + exit $ret else - return "$ret" + return $ret fi } diff --git a/tests/util.sh b/tests/util.sh index 31a7b6c..bfa5d16 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -120,7 +120,7 @@ callers() { # Print a message including path, line number, and command debug() { - local file="${1/#*\/tests\//tests\/}" + local file="${1/#*\/tests\//tests/}" set -- "$file" "${@:2}" color printf "${BLD}%s:%d:${RST} %s\n %s\n" "$@" } @@ -136,14 +136,13 @@ quote() { fi } +DEFER_LEVEL=-1 + # Run a command when this (sub)shell exits defer() { - # Refresh trap state before trap -p - # See https://unix.stackexchange.com/a/556888/56202 - trap -- KILL - # Check if the EXIT trap is already set - if ! trap -p EXIT | grep -q pop_defers; then + if ((DEFER_LEVEL != BASH_SUBSHELL)); then + DEFER_LEVEL=$BASH_SUBSHELL DEFER_CMDS=() DEFER_LINES=() DEFER_FILES=() -- cgit v1.2.3 From 3114d6c94332cf4b7f2c0c87a425e513c006dd14 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 23 Nov 2023 13:55:10 -0500 Subject: tests: Set abort_on_error for the sanitizers --- tests/util.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/util.sh') diff --git a/tests/util.sh b/tests/util.sh index bfa5d16..5bd3328 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -27,7 +27,7 @@ stdenv() { export LC_ALL=C export TZ=UTC0 - local SAN_OPTIONS="halt_on_error=1:log_to_syslog=0" + local SAN_OPTIONS="abort_on_error=1:halt_on_error=1:log_to_syslog=0" export ASAN_OPTIONS="$SAN_OPTIONS" export LSAN_OPTIONS="$SAN_OPTIONS" export MSAN_OPTIONS="$SAN_OPTIONS" -- cgit v1.2.3 From f8b22f20147d872aef9fa1037139c39e4dd0e687 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 1 Feb 2024 16:03:05 -0500 Subject: tests: Use variable redirections to dup std{out,err} Previously, we hardcoded file descriptors 3 and 4 for duplicating stdandard output/error respectively. In preparation for keeping inherited FDs open, switch to using bash's variable redirection feature to dynamically assign FDs. This feature is only available from bash 4.1 onwards, so this marks the end of our support for bash 3. macOS users will need to install a modern bash version to run our tests. --- .github/workflows/ci.yml | 4 +++- tests/run.sh | 26 +++++++------------------- tests/util.sh | 17 ++++++++--------- 3 files changed, 18 insertions(+), 29 deletions(-) (limited to 'tests/util.sh') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72037e3..ff0ff6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,9 @@ jobs: - name: Install dependencies run: | - brew install expect + brew install \ + bash \ + expect - name: Run tests run: | diff --git a/tests/run.sh b/tests/run.sh index 4a159f9..85d961f 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -28,7 +28,7 @@ debug_err() { callers | while read -r line func file; do if [ "$func" = source ]; then local cmd="$(awk "NR == $line" "$file" 2>/dev/null)" || : - debug "$file" $line "${RED}error $ret${RST}" "$cmd" >&4 + debug "$file" $line "${RED}error $ret${RST}" "$cmd" >&$DUPERR break fi done @@ -73,21 +73,9 @@ bg_test() { return $ret } -# Wait for any background job to complete -if ((BASH_VERSINFO[0] > 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3))); then - wait_any() { - wait -n - } -else - wait_any() { - read -ra jobs < <(jobs -p) - wait ${jobs[0]} - } -fi - # Wait for a background test to finish wait_test() { - wait_any + wait -n ret=$? ((BG--)) @@ -197,7 +185,7 @@ skip() { caller | { read -r line file printf "${BOL}" - debug "$file" $line "" "$(awk "NR == $line" "$file")" >&3 + debug "$file" $line "" "$(awk "NR == $line" "$file")" >&$DUPOUT } fi @@ -252,8 +240,8 @@ bfs_verbose() { ( # Close some fds to make room for the pipe, # even with extremely low ulimit -n - exec >&- 4>&- - exec >&3 3>&- + exec >&- {DUPERR}>&- + exec >&$DUPOUT {DUPOUT}>&- color bfs_verbose_impl "$@" ) fi @@ -306,7 +294,7 @@ invoke_bfs() { local ret=0 # Close the logging fds - "${BFS[@]}" "$@" 3>&- 4>&- || ret=$? + "${BFS[@]}" "$@" {DUPOUT}>&- {DUPERR}>&- || ret=$? # Allow bfs to fail, but not crash if ((ret > 125)); then @@ -391,7 +379,7 @@ diff_output() { if ((UPDATE)); then cp "$OUT" "$GOLD" else - $DIFF -u "$GOLD" "$OUT" >&4 + $DIFF -u "$GOLD" "$OUT" >&$DUPERR fi } diff --git a/tests/util.sh b/tests/util.sh index 5bd3328..686cc77 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -68,7 +68,7 @@ stdenv() { # Close stdin so bfs doesn't think we're interactive # dup() the standard fds for logging even when redirected - exec &1 4>&2 + exec &1 {DUPERR}>&2 } # Drop root priviliges or bail @@ -159,19 +159,18 @@ defer() { # Pop a single command from the defer stack and run it pop_defer() { - local i=$((${#DEFER_CMDS[@]} - 1)) - local cmd="${DEFER_CMDS[$i]}" - local file="${DEFER_FILES[$i]}" - local line="${DEFER_LINES[$i]}" - unset "DEFER_CMDS[$i]" - unset "DEFER_FILES[$i]" - unset "DEFER_LINES[$i]" + local cmd="${DEFER_CMDS[-1]}" + local file="${DEFER_FILES[-1]}" + local line="${DEFER_LINES[-1]}" + unset "DEFER_CMDS[-1]" + unset "DEFER_FILES[-1]" + unset "DEFER_LINES[-1]" local ret=0 eval "$cmd" || ret=$? if ((ret != 0)); then - debug "$file" $line "${RED}error $ret${RST}" "defer $cmd" >&4 + debug "$file" $line "${RED}error $ret${RST}" "defer $cmd" >&$DUPERR fi return $ret -- cgit v1.2.3 From c4334184502c25a41b5cab060681229b2b570c0a Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 1 Feb 2024 16:14:19 -0500 Subject: tests: Don't clobber inherited FDs Rather than attempting to close any unexpected FDs, just count them and adjust our ulimit -n calls to account for them. --- .github/workflows/ci.yml | 1 + tests/bfs/deep_strict.sh | 2 +- tests/common/execdir_ulimit.sh | 2 +- tests/gnu/execdir_ulimit.out | 32 ++++++++++++++++---------------- tests/gnu/execdir_ulimit.sh | 2 +- tests/gnu/printf_u_g_ulimit.sh | 2 +- tests/posix/deep.sh | 2 +- tests/posix/exec_ulimit.out | 32 ++++++++++++++++---------------- tests/posix/exec_ulimit.sh | 2 +- tests/posix/nogroup_ulimit.sh | 2 +- tests/posix/nouser_ulimit.sh | 2 +- tests/util.sh | 17 +++++------------ 12 files changed, 46 insertions(+), 52 deletions(-) (limited to 'tests/util.sh') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff0ff6f..8e96526 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,6 +86,7 @@ jobs: tcl-wrapper pw useradd -n action -m -G wheel -s /usr/local/bin/bash echo "%wheel ALL=(ALL) NOPASSWD: ALL" >>/usr/local/etc/sudoers + mount -t fdescfs none /dev/fd run: | chown -R action:action . diff --git a/tests/bfs/deep_strict.sh b/tests/bfs/deep_strict.sh index 50c8f05..22453c0 100644 --- a/tests/bfs/deep_strict.sh +++ b/tests/bfs/deep_strict.sh @@ -1,3 +1,3 @@ # Not even enough fds to keep the root open -ulimit -n 7 +ulimit -n $((NOPENFD + 4)) bfs_diff deep -type f -exec bash -c 'echo "${1:0:6}/.../${1##*/} (${#1})"' bash {} \; diff --git a/tests/common/execdir_ulimit.sh b/tests/common/execdir_ulimit.sh index 90c93c1..122c282 100644 --- a/tests/common/execdir_ulimit.sh +++ b/tests/common/execdir_ulimit.sh @@ -2,5 +2,5 @@ cd "$TEST" mkdir -p a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z mkdir -p a/b/c/d/e/f/g/h/i/j/k/l/m/0/1/2/3/4/5/6/7/8/9/A/B/C -ulimit -n 13 +ulimit -n $((NOPENFD + 10)) bfs_diff . -execdir echo {} \; diff --git a/tests/gnu/execdir_ulimit.out b/tests/gnu/execdir_ulimit.out index 7931f9a..6749f7d 100644 --- a/tests/gnu/execdir_ulimit.out +++ b/tests/gnu/execdir_ulimit.out @@ -1,16 +1,16 @@ -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 ./0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE diff --git a/tests/gnu/execdir_ulimit.sh b/tests/gnu/execdir_ulimit.sh index 3245dad..e14e716 100644 --- a/tests/gnu/execdir_ulimit.sh +++ b/tests/gnu/execdir_ulimit.sh @@ -1,2 +1,2 @@ -ulimit -Sn 16 +ulimit -Sn 64 bfs_diff deep -type f -execdir bash -c 'printf "%d %s\n" $(ulimit -Sn) "$1"' bash {} \; diff --git a/tests/gnu/printf_u_g_ulimit.sh b/tests/gnu/printf_u_g_ulimit.sh index 390ad48..c621b9b 100644 --- a/tests/gnu/printf_u_g_ulimit.sh +++ b/tests/gnu/printf_u_g_ulimit.sh @@ -1,2 +1,2 @@ -ulimit -n 16 +ulimit -n $((NOPENFD + 13)) [ "$(invoke_bfs deep -printf '%u %g\n' | uniq)" = "$(id -un) $(id -gn)" ] diff --git a/tests/posix/deep.sh b/tests/posix/deep.sh index 431705e..36a88c0 100644 --- a/tests/posix/deep.sh +++ b/tests/posix/deep.sh @@ -1,2 +1,2 @@ -ulimit -n 16 +ulimit -n $((NOPENFD + 13)) bfs_diff deep -type f -exec bash -c 'echo "${1:0:6}/.../${1##*/} (${#1})"' bash {} \; diff --git a/tests/posix/exec_ulimit.out b/tests/posix/exec_ulimit.out index 587ece2..144169e 100644 --- a/tests/posix/exec_ulimit.out +++ b/tests/posix/exec_ulimit.out @@ -1,16 +1,16 @@ -16 deep/0/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/1/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/2/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/3/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/4/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/5/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/6/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/7/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/8/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/9/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/A/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/B/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/C/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/D/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/E/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE -16 deep/F/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/0/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/1/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/2/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/3/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/4/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/5/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/6/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/7/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/8/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/9/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/A/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/B/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/C/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/D/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/E/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +64 deep/F/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE diff --git a/tests/posix/exec_ulimit.sh b/tests/posix/exec_ulimit.sh index 8ac8ff1..655fbec 100644 --- a/tests/posix/exec_ulimit.sh +++ b/tests/posix/exec_ulimit.sh @@ -1,2 +1,2 @@ -ulimit -Sn 16 +ulimit -Sn 64 bfs_diff deep -type f -exec bash -c 'printf "%d %s\n" $(ulimit -Sn) "${1:0:6}/.../${1##*/}"' bash {} \; diff --git a/tests/posix/nogroup_ulimit.sh b/tests/posix/nogroup_ulimit.sh index 5b4c440..a39dd1f 100644 --- a/tests/posix/nogroup_ulimit.sh +++ b/tests/posix/nogroup_ulimit.sh @@ -1,2 +1,2 @@ -ulimit -n 16 +ulimit -n $((NOPENFD + 13)) bfs_diff deep -type f -nogroup diff --git a/tests/posix/nouser_ulimit.sh b/tests/posix/nouser_ulimit.sh index e1400f0..a94b8c5 100644 --- a/tests/posix/nouser_ulimit.sh +++ b/tests/posix/nouser_ulimit.sh @@ -1,2 +1,2 @@ -ulimit -n 16 +ulimit -n $((NOPENFD + 13)) bfs_diff deep -type f -nouser diff --git a/tests/util.sh b/tests/util.sh index 686cc77..ec24958 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -48,23 +48,16 @@ stdenv() { export MallocNanoZone=0 fi - # Close non-standard inherited fds + # Count the inherited FDs if [ -d /proc/self/fd ]; then local fds=/proc/self/fd else local fds=/dev/fd fi - - for fd in "$fds"/*; do - if [ ! -e "$fd" ]; then - continue - fi - - local fd="${fd##*/}" - if ((fd > 2)); then - eval "exec ${fd}<&-" - fi - done + # We use ls $fds on purpose, rather than e.g. ($fds/*), to avoid counting + # internal bash fds that are not exposed to spawned processes + NOPENFD=$(ls -1q "$fds/" 2>/dev/null | wc -l) + NOPENFD=$((NOPENFD > 3 ? NOPENFD - 1 : 3)) # Close stdin so bfs doesn't think we're interactive # dup() the standard fds for logging even when redirected -- cgit v1.2.3 From 4d0d84f935159c395ccf3b95d5727a3553003b68 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 1 Feb 2024 12:11:41 -0500 Subject: tests: Implement jobserver inheritance --- .github/workflows/ci.yml | 12 ++--- GNUmakefile | 7 +-- tests/getopts.sh | 22 ++++++--- tests/run.sh | 119 +++++++++++++++++++++++++++++++++++++---------- tests/tests.mk | 7 +++ tests/util.sh | 12 +++-- 6 files changed, 132 insertions(+), 47 deletions(-) create mode 100644 tests/tests.mk (limited to 'tests/util.sh') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e96526..5ca0a75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: - name: Run tests run: | jobs=$(sysctl -n hw.ncpu) - make -j$jobs distcheck JOBS=-j$jobs + make -j$jobs distcheck freebsd: name: FreeBSD @@ -90,7 +90,7 @@ jobs: run: | chown -R action:action . - sudo -u action gmake -j$(nproc) distcheck JOBS=-j$(nproc) + sudo -u action gmake -j$(nproc) distcheck openbsd: name: OpenBSD @@ -120,7 +120,7 @@ jobs: run: | chown -R action:action . jobs=$(sysctl -n hw.ncpu) - doas -u action gmake -j$jobs check JOBS=-j$jobs TEST_FLAGS="--sudo=doas --verbose=skipped" + doas -u action gmake -j$jobs check TEST_FLAGS="--sudo=doas --verbose=skipped" netbsd: name: NetBSD @@ -153,7 +153,7 @@ jobs: PATH="/sbin:/usr/sbin:$PATH" chown -R action:action . jobs=$(sysctl -n hw.ncpu) - sudo -u action gmake -j$jobs check CC=clang LDFLAGS="-rpath /usr/pkg/lib" JOBS=-j$jobs TEST_FLAGS="--sudo --verbose=skipped" + sudo -u action gmake -j$jobs check CC=clang LDFLAGS="-rpath /usr/pkg/lib" TEST_FLAGS="--sudo --verbose=skipped" dragonflybsd: name: DragonFly BSD @@ -184,7 +184,7 @@ jobs: run: | chown -R action:action . jobs=$(sysctl -n hw.ncpu) - sudo -u action gmake -j$jobs check JOBS=-j$jobs TEST_FLAGS="--sudo --verbose=skipped" + sudo -u action gmake -j$jobs check TEST_FLAGS="--sudo --verbose=skipped" omnios: name: OmniOS @@ -216,4 +216,4 @@ jobs: PATH="/usr/xpg4/bin:$PATH" chown -R action:staff . jobs=$(getconf NPROCESSORS_ONLN) - sudo -u action gmake -j$jobs check LDFLAGS="-Wl,-rpath,/opt/ooce/lib/amd64" JOBS=-j$jobs TEST_FLAGS="--sudo --verbose=skipped" + sudo -u action gmake -j$jobs check LDFLAGS="-Wl,-rpath,/opt/ooce/lib/amd64" TEST_FLAGS="--sudo --verbose=skipped" diff --git a/GNUmakefile b/GNUmakefile index 34c7f37..e01e93a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -304,13 +304,8 @@ check: $(CHECKS) check-units: $(BIN)/tests/units $< -JOBS := $(filter -j%,$(MAKEFLAGS)) -ifndef JOBS - JOBS := -j1 -endif - $(STRATEGY_CHECKS): check-%: $(BIN)/bfs $(TEST_UTILS) - ./tests/tests.sh $(JOBS) --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS) + +./tests/tests.sh --make="$(MAKE)" --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS) # Custom test flags for distcheck DISTCHECK_FLAGS := -s TEST_FLAGS="--sudo --verbose=skipped" diff --git a/tests/getopts.sh b/tests/getopts.sh index ac75140..5214e9f 100644 --- a/tests/getopts.sh +++ b/tests/getopts.sh @@ -10,6 +10,7 @@ if command -v nproc &>/dev/null; then else JOBS=1 fi +MAKE= PATTERNS=() SUDO=() STOP=0 @@ -24,15 +25,19 @@ VERBOSE_TESTS=0 usage() { local pad=$(printf "%*s" ${#0} "") color cat </dev/null)" || : - debug "$file" $line "${RED}error $ret${RST}" "$cmd" >&$DUPERR + debug "$file" $line "${RED}error $ret${RST}" >&$DUPERR break fi done } -# Run a single test -run_test() ( +# Source a test +source_test() ( set -eE trap debug_err ERR + + if ((${#MAKE[@]})); then + # Close the jobserver pipes + exec {READY_PIPE}<&- {DONE_PIPE}>&- + fi + cd "$TMP" source "$@" ) -# Run a test in the background -bg_test() { +# Run a test +run_test() { if ((VERBOSE_ERRORS)); then - run_test "$1" + source_test "$1" else - run_test "$1" 2>"$TMP/$TEST.err" + source_test "$1" 2>"$TMP/$TEST.err" fi ret=$? + if ((${#MAKE[@]})); then + # Write one byte to the done pipe + printf . >&$DONE_PIPE + fi + case $ret in 0) if ((VERBOSE_TESTS)); then @@ -73,28 +83,87 @@ bg_test() { return $ret } -# Wait for a background test to finish -wait_test() { - wait -n - ret=$? +# Count the tests running in the background +BG=0 + +# Run a test in the background +bg_test() { + run_test "$1" & + ((++BG)) +} + +# Reap a finished background test +reap_test() { ((BG--)) - case $ret in + case "$1" in 0) ((++passed)) - return 0 ;; $EX_SKIP) ((++skipped)) - return 0 ;; *) ((++failed)) - return $ret ;; esac } +# Wait for a background test to finish +wait_test() { + local pid + wait -n -ppid + ret=$? + if [ -z "${pid:-}" ]; then + debug "${BASH_SOURCE[0]}" $((LINENO - 3)) "${RED}error $ret${RST}" >&$DUPERR + exit 1 + fi + + reap_test $ret +} + +# Wait until we're ready to run another test +wait_ready() { + if ((${#MAKE[@]})); then + # We'd like to parse the output of jobs -n, but we can't run it in a + # subshell or we won't get the right output + jobs -n >"$TMP/jobs" + while read -r job status ret foo; do + case "$status" in + Done) + reap_test 0 + ;; + Exit) + reap_test $ret + ;; + esac + done <"$TMP/jobs" + + # Read one byte from the ready pipe + read -r -N1 -u$READY_PIPE + elif ((BG >= JOBS)); then + wait_test + fi +} + +# Run make as a co-process to use its job control +comake() { + coproc { + # We can't just use std{in,out}, due to + # https://www.gnu.org/software/make/manual/html_node/Parallel-Input.html + exec {DONE_PIPE}<&0 {READY_PIPE}>&1 + exec "${MAKE[@]}" -s \ + -f "$TESTS/tests.mk" \ + DONE=$DONE_PIPE \ + READY=$READY_PIPE \ + "${TEST_CASES[@]/#/tests/}" \ + /dev/null + } + + # coproc pipes aren't inherited by subshells, so dup them + exec {READY_PIPE}<&${COPROC[0]} {DONE_PIPE}>&${COPROC[1]} +} + # Run all the tests run_tests() { if ((VERBOSE_TESTS)); then @@ -125,17 +194,17 @@ run_tests() { TEST_FMT="." fi - BG=0 + if ((${#MAKE[@]})); then + comake + fi # Turn off set -e (but turn it back on in run_test) set +e for TEST in "${TEST_CASES[@]}"; do - if ((BG >= JOBS)); then - wait_test - if (($? && STOP)); then - break - fi + wait_ready + if (($? && STOP)); then + break fi percent=$((100 * ran / total)) @@ -144,8 +213,8 @@ run_tests() { mkdir -p "$TMP/$TEST" OUT="$TMP/$TEST.out" - bg_test "$TESTS/$TEST.sh" & - ((++BG, ++ran)) + bg_test "$TESTS/$TEST.sh" + ((++ran)) done while ((BG > 0)); do @@ -185,7 +254,7 @@ skip() { caller | { read -r line file printf "${BOL}" - debug "$file" $line "" "$(awk "NR == $line" "$file")" >&$DUPOUT + debug "$file" $line "" >&$DUPOUT } fi diff --git a/tests/tests.mk b/tests/tests.mk new file mode 100644 index 0000000..5bf4f6c --- /dev/null +++ b/tests/tests.mk @@ -0,0 +1,7 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# GNU makefile that exposes make's job control to tests.sh + +tests/%: + bash -c 'printf . >&$(READY) && read -r -N1 -u$(DONE)' diff --git a/tests/util.sh b/tests/util.sh index ec24958..7dba9fb 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -113,9 +113,13 @@ callers() { # Print a message including path, line number, and command debug() { - local file="${1/#*\/tests\//tests/}" - set -- "$file" "${@:2}" - color printf "${BLD}%s:%d:${RST} %s\n %s\n" "$@" + local file="$1" + local line="$2" + local msg="$3" + local cmd="$(awk "NR == $line" "$file" 2>/dev/null)" || : + file="${file/#*\/tests\//tests/}" + + color printf "${BLD}%s:%d:${RST} %s\n %s\n" "$file" "$line" "$msg" "$cmd" } ## Deferred cleanup @@ -163,7 +167,7 @@ pop_defer() { eval "$cmd" || ret=$? if ((ret != 0)); then - debug "$file" $line "${RED}error $ret${RST}" "defer $cmd" >&$DUPERR + debug "$file" $line "${RED}error $ret${RST}" >&$DUPERR fi return $ret -- cgit v1.2.3 From 37caa3d71fd8bb4d0d9204e4a2f5cac234fa25fd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 29 Apr 2024 15:30:39 -0400 Subject: build: Replace `make config` with a `./configure` script This lets us do more traditional out-of-tree builds like $ ../path/to/bfs/configure $ make The .mk files are moved from ./config to ./build, mostly so that ./configure will auto-complete easily. --- .github/workflows/ci.yml | 8 +- .github/workflows/codecov.yml | 2 +- .github/workflows/codeql.yml | 2 +- Makefile | 143 +++++++++++++++--------------- README.md | 4 +- bench/bench.sh | 6 +- build/cc.sh | 16 ++++ build/config.mk | 62 +++++++++++++ build/define-if.sh | 20 +++++ build/deps.mk | 18 ++++ build/empty.c | 6 ++ build/exports.mk | 20 +++++ build/flags.mk | 136 ++++++++++++++++++++++++++++ build/has/acl-get-entry.c | 8 ++ build/has/acl-get-file.c | 8 ++ build/has/acl-get-tag-type.c | 10 +++ build/has/acl-is-trivial-np.c | 12 +++ build/has/acl-trivial.c | 8 ++ build/has/aligned-alloc.c | 8 ++ build/has/confstr.c | 9 ++ build/has/extattr-get-file.c | 10 +++ build/has/extattr-get-link.c | 10 +++ build/has/extattr-list-file.c | 10 +++ build/has/extattr-list-link.c | 10 +++ build/has/fdclosedir.c | 8 ++ build/has/getdents.c | 10 +++ build/has/getdents64-syscall.c | 12 +++ build/has/getdents64.c | 10 +++ build/has/getprogname-gnu.c | 9 ++ build/has/getprogname.c | 9 ++ build/has/max-align-t.c | 8 ++ build/has/pipe2.c | 10 +++ build/has/posix-spawn-addfchdir-np.c | 11 +++ build/has/posix-spawn-addfchdir.c | 11 +++ build/has/st-acmtim.c | 12 +++ build/has/st-acmtimespec.c | 12 +++ build/has/st-birthtim.c | 9 ++ build/has/st-birthtimespec.c | 9 ++ build/has/st-flags.c | 9 ++ build/has/statx-syscall.c | 13 +++ build/has/statx.c | 11 +++ build/has/strerror-l.c | 11 +++ build/has/strerror-r-gnu.c | 11 +++ build/has/strerror-r-posix.c | 11 +++ build/has/tm-gmtoff.c | 9 ++ build/has/uselocale.c | 9 ++ build/header.mk | 69 +++++++++++++++ build/pkgconf.sh | 100 +++++++++++++++++++++ build/pkgs.mk | 36 ++++++++ build/prelude.mk | 133 ++++++++++++++++++++++++++++ build/use/libacl.c | 9 ++ build/use/libcap.c | 9 ++ build/use/libselinux.c | 9 ++ build/use/liburing.c | 9 ++ build/use/oniguruma.c | 9 ++ config/cc.sh | 16 ---- config/config.mk | 63 ------------- config/define-if.sh | 20 ----- config/deps.mk | 18 ---- config/empty.c | 6 -- config/exports.mk | 20 ----- config/flags.mk | 136 ---------------------------- config/has/acl-get-entry.c | 8 -- config/has/acl-get-file.c | 8 -- config/has/acl-get-tag-type.c | 10 --- config/has/acl-is-trivial-np.c | 12 --- config/has/acl-trivial.c | 8 -- config/has/aligned-alloc.c | 8 -- config/has/confstr.c | 9 -- config/has/extattr-get-file.c | 10 --- config/has/extattr-get-link.c | 10 --- config/has/extattr-list-file.c | 10 --- config/has/extattr-list-link.c | 10 --- config/has/fdclosedir.c | 8 -- config/has/getdents.c | 10 --- config/has/getdents64-syscall.c | 12 --- config/has/getdents64.c | 10 --- config/has/getprogname-gnu.c | 9 -- config/has/getprogname.c | 9 -- config/has/max-align-t.c | 8 -- config/has/pipe2.c | 10 --- config/has/posix-spawn-addfchdir-np.c | 11 --- config/has/posix-spawn-addfchdir.c | 11 --- config/has/st-acmtim.c | 12 --- config/has/st-acmtimespec.c | 12 --- config/has/st-birthtim.c | 9 -- config/has/st-birthtimespec.c | 9 -- config/has/st-flags.c | 9 -- config/has/statx-syscall.c | 13 --- config/has/statx.c | 11 --- config/has/strerror-l.c | 11 --- config/has/strerror-r-gnu.c | 11 --- config/has/strerror-r-posix.c | 11 --- config/has/tm-gmtoff.c | 9 -- config/has/uselocale.c | 9 -- config/header.mk | 69 --------------- config/pkgconf.sh | 100 --------------------- config/pkgs.mk | 36 -------- config/prelude.mk | 162 ---------------------------------- config/use/libacl.c | 9 -- config/use/libcap.c | 9 -- config/use/libselinux.c | 9 -- config/use/liburing.c | 9 -- config/use/oniguruma.c | 9 -- configure | 98 ++++++++++++++++++++ docs/BUILDING.md | 47 +++++----- tests/util.sh | 9 +- tests/xspawn.c | 15 +--- 108 files changed, 1199 insertions(+), 1141 deletions(-) create mode 100755 build/cc.sh create mode 100644 build/config.mk create mode 100755 build/define-if.sh create mode 100644 build/deps.mk create mode 100644 build/empty.c create mode 100644 build/exports.mk create mode 100644 build/flags.mk create mode 100644 build/has/acl-get-entry.c create mode 100644 build/has/acl-get-file.c create mode 100644 build/has/acl-get-tag-type.c create mode 100644 build/has/acl-is-trivial-np.c create mode 100644 build/has/acl-trivial.c create mode 100644 build/has/aligned-alloc.c create mode 100644 build/has/confstr.c create mode 100644 build/has/extattr-get-file.c create mode 100644 build/has/extattr-get-link.c create mode 100644 build/has/extattr-list-file.c create mode 100644 build/has/extattr-list-link.c create mode 100644 build/has/fdclosedir.c create mode 100644 build/has/getdents.c create mode 100644 build/has/getdents64-syscall.c create mode 100644 build/has/getdents64.c create mode 100644 build/has/getprogname-gnu.c create mode 100644 build/has/getprogname.c create mode 100644 build/has/max-align-t.c create mode 100644 build/has/pipe2.c create mode 100644 build/has/posix-spawn-addfchdir-np.c create mode 100644 build/has/posix-spawn-addfchdir.c create mode 100644 build/has/st-acmtim.c create mode 100644 build/has/st-acmtimespec.c create mode 100644 build/has/st-birthtim.c create mode 100644 build/has/st-birthtimespec.c create mode 100644 build/has/st-flags.c create mode 100644 build/has/statx-syscall.c create mode 100644 build/has/statx.c create mode 100644 build/has/strerror-l.c create mode 100644 build/has/strerror-r-gnu.c create mode 100644 build/has/strerror-r-posix.c create mode 100644 build/has/tm-gmtoff.c create mode 100644 build/has/uselocale.c create mode 100644 build/header.mk create mode 100755 build/pkgconf.sh create mode 100644 build/pkgs.mk create mode 100644 build/prelude.mk create mode 100644 build/use/libacl.c create mode 100644 build/use/libcap.c create mode 100644 build/use/libselinux.c create mode 100644 build/use/liburing.c create mode 100644 build/use/oniguruma.c delete mode 100755 config/cc.sh delete mode 100644 config/config.mk delete mode 100755 config/define-if.sh delete mode 100644 config/deps.mk delete mode 100644 config/empty.c delete mode 100644 config/exports.mk delete mode 100644 config/flags.mk delete mode 100644 config/has/acl-get-entry.c delete mode 100644 config/has/acl-get-file.c delete mode 100644 config/has/acl-get-tag-type.c delete mode 100644 config/has/acl-is-trivial-np.c delete mode 100644 config/has/acl-trivial.c delete mode 100644 config/has/aligned-alloc.c delete mode 100644 config/has/confstr.c delete mode 100644 config/has/extattr-get-file.c delete mode 100644 config/has/extattr-get-link.c delete mode 100644 config/has/extattr-list-file.c delete mode 100644 config/has/extattr-list-link.c delete mode 100644 config/has/fdclosedir.c delete mode 100644 config/has/getdents.c delete mode 100644 config/has/getdents64-syscall.c delete mode 100644 config/has/getdents64.c delete mode 100644 config/has/getprogname-gnu.c delete mode 100644 config/has/getprogname.c delete mode 100644 config/has/max-align-t.c delete mode 100644 config/has/pipe2.c delete mode 100644 config/has/posix-spawn-addfchdir-np.c delete mode 100644 config/has/posix-spawn-addfchdir.c delete mode 100644 config/has/st-acmtim.c delete mode 100644 config/has/st-acmtimespec.c delete mode 100644 config/has/st-birthtim.c delete mode 100644 config/has/st-birthtimespec.c delete mode 100644 config/has/st-flags.c delete mode 100644 config/has/statx-syscall.c delete mode 100644 config/has/statx.c delete mode 100644 config/has/strerror-l.c delete mode 100644 config/has/strerror-r-gnu.c delete mode 100644 config/has/strerror-r-posix.c delete mode 100644 config/has/tm-gmtoff.c delete mode 100644 config/has/uselocale.c delete mode 100644 config/header.mk delete mode 100755 config/pkgconf.sh delete mode 100644 config/pkgs.mk delete mode 100644 config/prelude.mk delete mode 100644 config/use/libacl.c delete mode 100644 config/use/libcap.c delete mode 100644 config/use/libselinux.c delete mode 100644 config/use/liburing.c delete mode 100644 config/use/oniguruma.c create mode 100755 configure (limited to 'tests/util.sh') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3890bb0..57f59f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: gmake \ oniguruma jobs=$(sysctl -n hw.ncpu) - gmake -j$jobs config + MAKE=gmake ./configure gmake -j$jobs check TEST_FLAGS="--sudo --verbose=skipped" netbsd: @@ -133,7 +133,7 @@ jobs: pkgconf \ tcl-expect jobs=$(sysctl -n hw.ncpu) - make -j$jobs config + ./configure make -j$jobs check TEST_FLAGS="--sudo --verbose=skipped" dragonflybsd: @@ -165,7 +165,7 @@ jobs: run: | chown -R action:action . jobs=$(sysctl -n hw.ncpu) - sudo -u action make config + sudo -u action ./configure sudo -u action make -j$jobs check TEST_FLAGS="--sudo --verbose=skipped" omnios: @@ -198,5 +198,5 @@ jobs: PATH="/usr/xpg4/bin:$PATH" chown -R action:staff . jobs=$(getconf NPROCESSORS_ONLN) - sudo -u action gmake config + sudo -u action MAKE=gmake ./configure sudo -u action gmake -j$jobs check TEST_FLAGS="--sudo --verbose=skipped" diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 2245f40..bb68927 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -25,7 +25,7 @@ jobs: - name: Generate coverage run: | - make config GCOV=y + ./configure GCOV=y make -j$(nproc) check TEST_FLAGS="--sudo" gcov -abcfpu obj/*/*.o diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c21fda5..a0b8fe3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: - name: Configure run: | - make -j$(nproc) config + ./configure - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/Makefile b/Makefile index 981c322..2fb35fd 100644 --- a/Makefile +++ b/Makefile @@ -1,56 +1,50 @@ # Copyright © Tavian Barnes # SPDX-License-Identifier: 0BSD -# This Makefile implements the configuration and build steps for bfs. It is -# portable to both GNU make and most BSD make implementations. To build bfs, -# run +# To build bfs, run # -# $ make config +# $ ./configure # $ make # Utilities and GNU/BSD portability -include config/prelude.mk +include build/prelude.mk # The default build target default: bfs .PHONY: default # Include the generated build config, if it exists --include ${CONFIG} +-include gen/config.mk -## Configuration phase (`make config`) - -# The configuration goal itself -config:: - @+${MAKE} -sf config/config.mk +## Configuration phase (`./configure`) # bfs used to have flag-like targets (`make release`, `make asan ubsan`, etc.). # Direct users to the new configuration system. asan lsan msan tsan ubsan gcov lint release:: - @printf 'error: `%s %s` is no longer supported. ' "${MAKE}" $@ >&2 - @printf 'Use `%s config %s=y` instead.\n' "${MAKE}" $$(echo $@ | tr 'a-z' 'A-Z') >&2 + @printf 'error: `%s %s` is no longer supported. Use `./configure %s=y` instead.\n' \ + "${MAKE}" $@ $$(echo $@ | tr 'a-z' 'A-Z') >&2 @false -# Print an error if `make` is run before `make config` -${CONFIG}:: +# Print an error if `make` is run before `./configure` +gen/config.mk:: @if ! [ -e $@ ]; then \ - printf 'error: You must run `%s config` before `%s`.\n' "${MAKE}" "${MAKE}" >&2; \ + printf 'error: You must run `./configure` before `%s`.\n' "${MAKE}" >&2; \ false; \ fi ## Build phase (`make`) # The main binary -bfs: ${BIN}/bfs +bfs: bin/bfs .PHONY: bfs # All binaries BINS := \ - ${BIN}/bfs \ - ${BIN}/tests/mksock \ - ${BIN}/tests/units \ - ${BIN}/tests/xspawnee \ - ${BIN}/tests/xtouch + bin/bfs \ + bin/tests/mksock \ + bin/tests/units \ + bin/tests/xspawnee \ + bin/tests/xtouch all: ${BINS} .PHONY: all @@ -60,52 +54,50 @@ ALL_CFLAGS = ${CPPFLAGS} ${CFLAGS} ${DEPFLAGS} ALL_LDFLAGS = ${CFLAGS} ${LDFLAGS} # The main binary -${BIN}/bfs: ${LIBBFS} ${OBJ}/src/main.o +bin/bfs: ${LIBBFS} obj/src/main.o ${BINS}: @${MKDIR} ${@D} - +${MSG} "[ LD ] ${TGT}" ${CC} ${ALL_LDFLAGS} ${.ALLSRC} ${LDLIBS} -o $@ + +${MSG} "[ LD ] $@" ${CC} ${ALL_LDFLAGS} ${.ALLSRC} ${LDLIBS} -o $@ ${POSTLINK} # Get the .c file for a .o file -_CSRC = ${@:${OBJ}/%.o=%.c} -CSRC = ${_CSRC:gen/%=${GEN}/%} +CSRC = ${@:obj/%.o=%.c} -# Depend on ${CONFIG} to make sure `make config` runs first, and to rebuild when -# the configuration changes -${OBJS}: ${CONFIG} +# Rebuild when the configuration changes +${OBJS}: gen/config.mk @${MKDIR} ${@D} - ${MSG} "[ CC ] ${_CSRC}" ${CC} ${ALL_CFLAGS} -c ${CSRC} -o $@ + ${MSG} "[ CC ] ${CSRC}" ${CC} ${ALL_CFLAGS} -c ${CSRC} -o $@ # Save the version number to this file, but only update version.c if it changes -${GEN}/version.c.new:: +gen/version.c.new:: @${MKDIR} ${@D} @printf 'const char bfs_version[] = "' >$@ @if [ "$$VERSION" ]; then \ printf '%s' "$$VERSION"; \ - elif test -d .git && command -v git >/dev/null 2>&1; then \ - git describe --always --dirty; \ + elif test -e src/../.git && command -v git >/dev/null 2>&1; then \ + git -C src/.. describe --always --dirty; \ else \ echo "3.1.3"; \ fi | tr -d '\n' >>$@ @printf '";\n' >>$@ -${GEN}/version.c: ${GEN}/version.c.new +gen/version.c: gen/version.c.new @test -e $@ && cmp -s $@ ${.ALLSRC} && rm ${.ALLSRC} || mv ${.ALLSRC} $@ -${OBJ}/gen/version.o: ${GEN}/version.c +obj/gen/version.o: gen/version.c ## Test phase (`make check`) # Unit test binaries UTEST_BINS := \ - ${BIN}/tests/units \ - ${BIN}/tests/xspawnee + bin/tests/units \ + bin/tests/xspawnee # Integration test binaries ITEST_BINS := \ - ${BIN}/tests/mksock \ - ${BIN}/tests/xtouch + bin/tests/mksock \ + bin/tests/xtouch # Build (but don't run) test binaries tests: ${UTEST_BINS} ${ITEST_BINS} @@ -117,45 +109,45 @@ check: unit-tests integration-tests # Run the unit tests unit-tests: ${UTEST_BINS} - ${MSG} "[TEST] tests/units" ${BIN}/tests/units + ${MSG} "[TEST] tests/units" bin/tests/units .PHONY: unit-tests -${BIN}/tests/units: \ +bin/tests/units: \ ${UNIT_OBJS} \ ${LIBBFS} -${BIN}/tests/xspawnee: \ - ${OBJ}/tests/xspawnee.o +bin/tests/xspawnee: \ + obj/tests/xspawnee.o # The different flag combinations we check INTEGRATIONS := default dfs ids eds j1 j2 j3 s INTEGRATION_TESTS := ${INTEGRATIONS:%=check-%} # Check just `bfs` -check-default: ${BIN}/bfs ${ITEST_BINS} +check-default: bin/bfs ${ITEST_BINS} +${MSG} "[TEST] bfs" \ - ./tests/tests.sh --make="${MAKE}" --bfs="${BIN}/bfs" ${TEST_FLAGS} + ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs" ${TEST_FLAGS} # Check the different search strategies -check-dfs check-ids check-eds: ${BIN}/bfs ${ITEST_BINS} +check-dfs check-ids check-eds: bin/bfs ${ITEST_BINS} +${MSG} "[TEST] bfs -S ${@:check-%=%}" \ - ./tests/tests.sh --make="${MAKE}" --bfs="${BIN}/bfs -S ${@:check-%=%}" ${TEST_FLAGS} + ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs -S ${@:check-%=%}" ${TEST_FLAGS} # Check various flags -check-j1 check-j2 check-j3 check-s: ${BIN}/bfs ${ITEST_BINS} +check-j1 check-j2 check-j3 check-s: bin/bfs ${ITEST_BINS} +${MSG} "[TEST] bfs -${@:check-%=%}" \ - ./tests/tests.sh --make="${MAKE}" --bfs="${BIN}/bfs -${@:check-%=%}" ${TEST_FLAGS} + ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs -${@:check-%=%}" ${TEST_FLAGS} # Run the integration tests integration-tests: ${INTEGRATION_TESTS} .PHONY: integration-tests -${BIN}/tests/mksock: \ - ${OBJ}/tests/mksock.o \ +bin/tests/mksock: \ + obj/tests/mksock.o \ ${LIBBFS} -${BIN}/tests/xtouch: \ - ${OBJ}/tests/xtouch.o \ +bin/tests/xtouch: \ + obj/tests/xtouch.o \ ${LIBBFS} # `make distcheck` configurations @@ -183,8 +175,10 @@ DISTCHECK_CONFIG_m32 := EXTRA_CFLAGS="-m32" PKG_CONFIG_LIBDIR=/usr/lib32/pkgconf DISTCHECK_CONFIG_release := RELEASE=y ${DISTCHECKS}:: - +${MAKE} -rs BUILDDIR=${BUILDDIR}/$@ config ${DISTCHECK_CONFIG_${@:distcheck-%=%}} - +${MAKE} -s BUILDDIR=${BUILDDIR}/$@ check TEST_FLAGS="--sudo --verbose=skipped" + @${MKDIR} $@ + @+cd $@ \ + && ../configure ${DISTCHECK_CONFIG_${@:distcheck-%=%}} \ + && ${MAKE} -s check TEST_FLAGS="--sudo --verbose=skipped" ## Packaging (`make install`) @@ -193,44 +187,49 @@ DEST_MANDIR := ${DESTDIR}${MANDIR} install:: ${Q}${MKDIR} ${DEST_PREFIX}/bin - ${MSG} "[INSTALL] bin/bfs" \ - ${INSTALL} -m755 ${BIN}/bfs ${DEST_PREFIX}/bin/bfs + ${MSG} "[INST] bin/bfs" \ + ${INSTALL} -m755 bin/bfs ${DEST_PREFIX}/bin/bfs ${Q}${MKDIR} ${DEST_MANDIR}/man1 - ${MSG} "[INSTALL] man/man1/bfs.1" \ + ${MSG} "[INST] man/man1/bfs.1" \ ${INSTALL} -m644 docs/bfs.1 ${DEST_MANDIR}/man1/bfs.1 ${Q}${MKDIR} ${DEST_PREFIX}/share/bash-completion/completions - ${MSG} "[INSTALL] completions/bfs.bash" \ + ${MSG} "[INST] completions/bfs.bash" \ ${INSTALL} -m644 completions/bfs.bash ${DEST_PREFIX}/share/bash-completion/completions/bfs ${Q}${MKDIR} ${DEST_PREFIX}/share/zsh/site-functions - ${MSG} "[INSTALL] completions/bfs.zsh" \ + ${MSG} "[INST] completions/bfs.zsh" \ ${INSTALL} -m644 completions/bfs.zsh ${DEST_PREFIX}/share/zsh/site-functions/_bfs ${Q}${MKDIR} ${DEST_PREFIX}/share/fish/vendor_completions.d - ${MSG} "[INSTALL] completions/bfs.fish" \ + ${MSG} "[INST] completions/bfs.fish" \ ${INSTALL} -m644 completions/bfs.fish ${DEST_PREFIX}/share/fish/vendor_completions.d/bfs.fish uninstall:: - ${RM} ${DEST_PREFIX}/share/bash-completion/completions/bfs - ${RM} ${DEST_PREFIX}/share/zsh/site-functions/_bfs - ${RM} ${DEST_PREFIX}/share/fish/vendor_completions.d/bfs.fish - ${RM} ${DEST_MANDIR}/man1/bfs.1 - ${RM} ${DEST_PREFIX}/bin/bfs + ${MSG} "[ RM ] completions/bfs.bash" \ + ${RM} ${DEST_PREFIX}/share/bash-completion/completions/bfs + ${MSG} "[ RM ] completions/bfs.zsh" \ + ${RM} ${DEST_PREFIX}/share/zsh/site-functions/_bfs + ${MSG} "[ RM ] completions/bfs.fish" \ + ${RM} ${DEST_PREFIX}/share/fish/vendor_completions.d/bfs.fish + ${MSG} "[ RM ] man/man1/bfs.1" \ + ${RM} ${DEST_MANDIR}/man1/bfs.1 + ${MSG} "[ RM ] bin/bfs" \ + ${RM} ${DEST_PREFIX}/bin/bfs # Check that `make install` works and `make uninstall` removes everything check-install:: - +${MAKE} install DESTDIR=${BUILDDIR}/pkg - +${MAKE} uninstall DESTDIR=${BUILDDIR}/pkg - ${BIN}/bfs ${BUILDDIR}/pkg -not -type d -print -exit 1 - ${RM} -r ${BUILDDIR}/pkg + +${MAKE} install DESTDIR=pkg + +${MAKE} uninstall DESTDIR=pkg + bin/bfs pkg -not -type d -print -exit 1 + ${RM} -r pkg ## Cleanup (`make clean`) # Clean all build products clean:: ${MSG} "[ RM ] bin obj" \ - ${RM} -r ${BIN} ${OBJ} + ${RM} -r bin obj # Clean everything, including generated files distclean: clean ${MSG} "[ RM ] gen" \ - ${RM} -r ${GEN} ${DISTCHECKS} + ${RM} -r gen ${DISTCHECKS} .PHONY: distclean diff --git a/README.md b/README.md index b95c16b..922ebdc 100644 --- a/README.md +++ b/README.md @@ -333,7 +333,7 @@ Once you have the dependencies, you can build bfs. Download one of the [releases](https://github.com/tavianator/bfs/releases) or clone the [git repo](https://github.com/tavianator/bfs). Then run - $ make config + $ ./configure $ make This will build the `./bin/bfs` binary. @@ -343,7 +343,7 @@ Run the test suite to make sure it works correctly: If you're interested in speed, you may want to build the release version instead: - $ make config RELEASE=y + $ ./configure RELEASE=y $ make Finally, if you want to install it globally, run diff --git a/bench/bench.sh b/bench/bench.sh index 1526fe5..ba46599 100644 --- a/bench/bench.sh +++ b/bench/bench.sh @@ -221,7 +221,7 @@ setup() { fi echo "Building bfs ..." - as-user make -s -j"$nproc" RELEASE=y + as-user ./configure RELEASE=y as-user make -s -j"$nproc" all as-user mkdir -p bench/corpus @@ -254,8 +254,8 @@ setup() { echo "Building bfs $commit ..." cd "$worktree" as-user git checkout -qd "$commit" -- - if [ -e config ]; then - as-user make -s -j"$nproc" config RELEASE=1 + if [ -e configure ]; then + as-user ./configure RELEASE=1 as-user make -s -j"$nproc" else as-user make -s -j"$nproc" release diff --git a/build/cc.sh b/build/cc.sh new file mode 100755 index 0000000..45d51ca --- /dev/null +++ b/build/cc.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Run the compiler and check if it succeeded + +set -eu + +TMP=$(mktemp) +trap 'rm -f "$TMP"' EXIT + +( + set -x + $XCC $XCPPFLAGS $XCFLAGS $XLDFLAGS "$@" $XLDLIBS -o "$TMP" +) diff --git a/build/config.mk b/build/config.mk new file mode 100644 index 0000000..153838d --- /dev/null +++ b/build/config.mk @@ -0,0 +1,62 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that implements `./configure` + +include build/prelude.mk +include build/exports.mk + +# All configuration steps +config: gen/config.mk gen/config.h +.PHONY: config + +# Makefile fragments generated by `./configure` +MKS := \ + gen/vars.mk \ + gen/flags.mk \ + gen/deps.mk \ + gen/pkgs.mk + +# The main configuration file, which includes the others +gen/config.mk: ${MKS} + ${MSG} "[ GEN] $@" + @printf '# %s\n' "$@" >$@ + @printf 'include %s\n' ${.ALLSRC} >>$@ + ${VCAT} gen/config.mk +.PHONY: gen/config.mk + +# Saves the configurable variables +gen/vars.mk:: + @${MKDIR} ${@D} + ${MSG} "[ GEN] $@" + @printf '# %s\n' "$@" >$@ + @printf 'PREFIX := %s\n' "$$XPREFIX" >>$@ + @printf 'MANDIR := %s\n' "$$XMANDIR" >>$@ + @printf 'OS := %s\n' "$${OS:-$$(uname)}" >>$@ + @printf 'CC := %s\n' "$$XCC" >>$@ + @printf 'INSTALL := %s\n' "$$XINSTALL" >>$@ + @printf 'MKDIR := %s\n' "$$XMKDIR" >>$@ + @printf 'PKG_CONFIG := %s\n' "$$XPKG_CONFIG" >>$@ + @printf 'RM := %s\n' "$$XRM" >>$@ + ${VCAT} $@ + +# Sets the build flags. This depends on vars.mk and uses a recursive make so +# that the default flags can depend on variables like ${OS}. +gen/flags.mk: gen/vars.mk + @+${MAKE} -sf build/flags.mk $@ +.PHONY: gen/flags.mk + +# Check for dependency generation support +gen/deps.mk: gen/flags.mk + @+${MAKE} -sf build/deps.mk $@ +.PHONY: gen/deps.mk + +# Auto-detect dependencies and their build flags +gen/pkgs.mk: gen/flags.mk + @+${MAKE} -sf build/pkgs.mk $@ +.PHONY: gen/pkgs.mk + +# Compile-time feature detection +gen/config.h: gen/config.mk + @+${MAKE} -sf build/header.mk $@ +.PHONY: gen/config.h diff --git a/build/define-if.sh b/build/define-if.sh new file mode 100755 index 0000000..295ead8 --- /dev/null +++ b/build/define-if.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Output a C preprocessor definition based on whether a command succeeds + +set -eu + +SLUG="${1#build/}" +SLUG="${SLUG%.c}" +MACRO="BFS_$(printf '%s' "$SLUG" | tr '/a-z-' '_A-Z_')" +shift + +if "$@"; then + printf '#define %s true\n' "$MACRO" +else + printf '#define %s false\n' "$MACRO" + exit 1 +fi diff --git a/build/deps.mk b/build/deps.mk new file mode 100644 index 0000000..e8dd9fb --- /dev/null +++ b/build/deps.mk @@ -0,0 +1,18 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that generates gen/deps.mk + +include build/prelude.mk +include gen/vars.mk +include gen/flags.mk +include build/exports.mk + +gen/deps.mk:: + ${MSG} "[ GEN] $@" + printf '# %s\n' "$@" >$@ + if build/cc.sh -MD -MP -MF /dev/null build/empty.c; then \ + printf 'DEPFLAGS := -MD -MP\n'; \ + fi >>$@ 2>$@.log + ${VCAT} $@ + printf -- '-include %s\n' ${OBJS:.o=.d} >>$@ diff --git a/build/empty.c b/build/empty.c new file mode 100644 index 0000000..4fa9a5b --- /dev/null +++ b/build/empty.c @@ -0,0 +1,6 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +int main(void) { + return 0; +} diff --git a/build/exports.mk b/build/exports.mk new file mode 100644 index 0000000..ed19134 --- /dev/null +++ b/build/exports.mk @@ -0,0 +1,20 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile fragment that exports variables used by configuration scripts + +export XPREFIX=${PREFIX} +export XMANDIR=${MANDIR} + +export XCC=${CC} +export XINSTALL=${INSTALL} +export XMKDIR=${MKDIR} +export XPKG_CONFIG=${PKG_CONFIG} +export XRM=${RM} + +export XCPPFLAGS=${CPPFLAGS} +export XCFLAGS=${CFLAGS} +export XLDFLAGS=${LDFLAGS} +export XLDLIBS=${LDLIBS} + +export XNOLIBS=${NOLIBS} diff --git a/build/flags.mk b/build/flags.mk new file mode 100644 index 0000000..0a44e94 --- /dev/null +++ b/build/flags.mk @@ -0,0 +1,136 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that generates gen/flags.mk + +include build/prelude.mk +include gen/vars.mk + +# Configurable flags +CPPFLAGS ?= +CFLAGS ?= \ + -g \ + -Wall \ + -Wformat=2 \ + -Werror=implicit \ + -Wimplicit-fallthrough \ + -Wmissing-declarations \ + -Wshadow \ + -Wsign-compare \ + -Wstrict-prototypes +LDFLAGS ?= +LDLIBS ?= + +export XCPPFLAGS=${CPPFLAGS} +export XCFLAGS=${CFLAGS} +export XLDFLAGS=${LDFLAGS} +export XLDLIBS=${LDLIBS} + +# Immutable flags +export BFS_CPPFLAGS= \ + -Isrc \ + -Igen \ + -D__EXTENSIONS__ \ + -D_ATFILE_SOURCE \ + -D_BSD_SOURCE \ + -D_DARWIN_C_SOURCE \ + -D_DEFAULT_SOURCE \ + -D_GNU_SOURCE \ + -D_POSIX_PTHREAD_SEMANTICS \ + -D_FILE_OFFSET_BITS=64 \ + -D_TIME_BITS=64 +export BFS_CFLAGS= -std=c17 -pthread + +# Platform-specific system libraries +LDLIBS,DragonFly := -lposix1e +LDLIBS,Linux := -lrt +LDLIBS,NetBSD := -lutil +LDLIBS,SunOS := -lsec -lsocket -lnsl +export BFS_LDLIBS=${LDLIBS,${OS}} + +# Build profiles +_ASAN := ${TRUTHY,${ASAN}} +_LSAN := ${TRUTHY,${LSAN}} +_MSAN := ${TRUTHY,${MSAN}} +_TSAN := ${TRUTHY,${TSAN}} +_UBSAN := ${TRUTHY,${UBSAN}} +_GCOV := ${TRUTHY,${GCOV}} +_LINT := ${TRUTHY,${LINT}} +_RELEASE := ${TRUTHY,${RELEASE}} + +# https://github.com/google/sanitizers/issues/342 +TSAN_CPPFLAGS,y := -DBFS_USE_TARGET_CLONES=0 +export TSAN_CPPFLAGS=${TSAN_CPPFLAGS,${_TSAN}} + +ASAN_CFLAGS,y := -fsanitize=address +LSAN_CFLAGS,y := -fsanitize=leak +MSAN_CFLAGS,y := -fsanitize=memory -fsanitize-memory-track-origins +TSAN_CFLAGS,y := -fsanitize=thread +UBSAN_CFLAGS.y := -fsanitize=undefined + +export ASAN_CFLAGS=${ASAN_CFLAGS,${_ASAN}} +export LSAN_CFLAGS=${LSAN_CFLAGS,${_LSAN}} +export MSAN_CFLAGS=${MSAN_CFLAGS,${_MSAN}} +export TSAN_CFLAGS=${TSAN_CFLAGS,${_TSAN}} +export UBSAN_CFLAGS=${UBSAN_CFLAGS,${_UBSAN}} + +SAN_CFLAGS,y := -fno-sanitize-recover=all +INSANE := ${NOT,${_ASAN}${_LSAN}${_MSAN}${_TSAN}${_UBSAN}} +SAN := ${NOT,${INSANE}} +export SAN_CFLAGS=${SAN_CFLAGS,${SAN}} + +# MSAN and TSAN both need all code to be instrumented +YESLIBS := ${NOT,${_MSAN}${_TSAN}} +NOLIBS ?= ${NOT,${YESLIBS}} +export XNOLIBS=${NOLIBS} + +# gcov only intercepts fork()/exec() with -std=gnu* +GCOV_CFLAGS,y := -std=gnu17 --coverage +export GCOV_CFLAGS=${GCOV_CFLAGS,${_GCOV}} + +LINT_CPPFLAGS,y := -D_FORTIFY_SOURCE=3 -DBFS_LINT +LINT_CFLAGS,y := -Werror -O2 + +export LINT_CPPFLAGS=${LINT_CPPFLAGS,${_LINT}} +export LINT_CFLAGS=${LINT_CFLAGS,${_LINT}} + +RELEASE_CPPFLAGS,y := -DNDEBUG +RELEASE_CFLAGS,y := -O3 -flto=auto + +export RELEASE_CPPFLAGS=${RELEASE_CPPFLAGS,${_RELEASE}} +export RELEASE_CFLAGS=${RELEASE_CFLAGS,${_RELEASE}} + +# Set a variable +SETVAR = printf '%s := %s\n' >>$@ + +# Append to a variable, if non-empty +APPEND = append() { test -z "$$2" || printf '%s += %s\n' "$$1" "$$2" >>$@; }; append + +gen/flags.mk:: + ${MSG} "[ GEN] $@" + printf '# %s\n' "$@" >$@ + ${SETVAR} CPPFLAGS "$$BFS_CPPFLAGS" + ${APPEND} CPPFLAGS "$$TSAN_CPPFLAGS" + ${APPEND} CPPFLAGS "$$LINT_CPPFLAGS" + ${APPEND} CPPFLAGS "$$RELEASE_CPPFLAGS" + ${APPEND} CPPFLAGS "$$XCPPFLAGS" + ${APPEND} CPPFLAGS "$$EXTRA_CPPFLAGS" + ${SETVAR} CFLAGS "$$BFS_CFLAGS" + ${APPEND} CFLAGS "$$ASAN_CFLAGS" + ${APPEND} CFLAGS "$$LSAN_CFLAGS" + ${APPEND} CFLAGS "$$MSAN_CFLAGS" + ${APPEND} CFLAGS "$$TSAN_CFLAGS" + ${APPEND} CFLAGS "$$UBSAN_CFLAGS" + ${APPEND} CFLAGS "$$SAN_CFLAGS" + ${APPEND} CFLAGS "$$GCOV_CFLAGS" + ${APPEND} CFLAGS "$$LINT_CFLAGS" + ${APPEND} CFLAGS "$$RELEASE_CFLAGS" + ${APPEND} CFLAGS "$$XCFLAGS" + ${APPEND} CFLAGS "$$EXTRA_CFLAGS" + ${SETVAR} LDFLAGS "$$XLDFLAGS" + ${SETVAR} LDLIBS "$$XLDLIBS" + ${APPEND} LDLIBS "$$EXTRA_LDLIBS" + ${APPEND} LDLIBS "$$BFS_LDLIBS" + ${SETVAR} NOLIBS "$$XNOLIBS" + test "${OS}-${SAN}" != FreeBSD-y || printf 'POSTLINK = elfctl -e +noaslr $$@\n' >>$@ + ${VCAT} $@ diff --git a/build/has/acl-get-entry.c b/build/has/acl-get-entry.c new file mode 100644 index 0000000..3cce771 --- /dev/null +++ b/build/has/acl-get-entry.c @@ -0,0 +1,8 @@ +#include +#include + +int main(void) { + acl_t acl = acl_get_file(".", ACL_TYPE_DEFAULT); + acl_entry_t entry; + return acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); +} diff --git a/build/has/acl-get-file.c b/build/has/acl-get-file.c new file mode 100644 index 0000000..89fbf23 --- /dev/null +++ b/build/has/acl-get-file.c @@ -0,0 +1,8 @@ +#include +#include +#include + +int main(void) { + acl_t acl = acl_get_file(".", ACL_TYPE_DEFAULT); + return acl == (acl_t)NULL; +} diff --git a/build/has/acl-get-tag-type.c b/build/has/acl-get-tag-type.c new file mode 100644 index 0000000..2901956 --- /dev/null +++ b/build/has/acl-get-tag-type.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) { + acl_entry_t entry; + memset(&entry, 0, sizeof(entry)); + acl_tag_t tag; + return acl_get_tag_type(entry, &tag); +} diff --git a/build/has/acl-is-trivial-np.c b/build/has/acl-is-trivial-np.c new file mode 100644 index 0000000..9ca9fc7 --- /dev/null +++ b/build/has/acl-is-trivial-np.c @@ -0,0 +1,12 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + acl_t acl = acl_get_fd(3); + int trivial; + acl_is_trivial_np(acl, &trivial); + return 0; +} diff --git a/build/has/acl-trivial.c b/build/has/acl-trivial.c new file mode 100644 index 0000000..7efc838 --- /dev/null +++ b/build/has/acl-trivial.c @@ -0,0 +1,8 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + return acl_trivial("."); +} diff --git a/build/has/aligned-alloc.c b/build/has/aligned-alloc.c new file mode 100644 index 0000000..4460038 --- /dev/null +++ b/build/has/aligned-alloc.c @@ -0,0 +1,8 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + return !aligned_alloc(_Alignof(void *), sizeof(void *)); +} diff --git a/build/has/confstr.c b/build/has/confstr.c new file mode 100644 index 0000000..58280b4 --- /dev/null +++ b/build/has/confstr.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + confstr(_CS_PATH, NULL, 0); + return 0; +} diff --git a/build/has/extattr-get-file.c b/build/has/extattr-get-file.c new file mode 100644 index 0000000..ac9cf96 --- /dev/null +++ b/build/has/extattr-get-file.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + return extattr_get_file("file", EXTATTR_NAMESPACE_USER, "xattr", NULL, 0); +} diff --git a/build/has/extattr-get-link.c b/build/has/extattr-get-link.c new file mode 100644 index 0000000..c35be5b --- /dev/null +++ b/build/has/extattr-get-link.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + return extattr_get_link("link", EXTATTR_NAMESPACE_USER, "xattr", NULL, 0); +} diff --git a/build/has/extattr-list-file.c b/build/has/extattr-list-file.c new file mode 100644 index 0000000..e68a8bb --- /dev/null +++ b/build/has/extattr-list-file.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + return extattr_list_file("file", EXTATTR_NAMESPACE_USER, NULL, 0); +} diff --git a/build/has/extattr-list-link.c b/build/has/extattr-list-link.c new file mode 100644 index 0000000..49f0ec2 --- /dev/null +++ b/build/has/extattr-list-link.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + return extattr_list_link("link", EXTATTR_NAMESPACE_USER, NULL, 0); +} diff --git a/build/has/fdclosedir.c b/build/has/fdclosedir.c new file mode 100644 index 0000000..f4ad1f5 --- /dev/null +++ b/build/has/fdclosedir.c @@ -0,0 +1,8 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + return fdclosedir(opendir(".")); +} diff --git a/build/has/getdents.c b/build/has/getdents.c new file mode 100644 index 0000000..d0d4228 --- /dev/null +++ b/build/has/getdents.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct dirent de; + getdents(3, &de, 1024); + return 0; +} diff --git a/build/has/getdents64-syscall.c b/build/has/getdents64-syscall.c new file mode 100644 index 0000000..4838c14 --- /dev/null +++ b/build/has/getdents64-syscall.c @@ -0,0 +1,12 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + struct dirent64 de; + syscall(SYS_getdents64, 3, &de, 1024); + return 0; +} diff --git a/build/has/getdents64.c b/build/has/getdents64.c new file mode 100644 index 0000000..1abf36d --- /dev/null +++ b/build/has/getdents64.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct dirent64 de; + getdents64(3, &de, 1024); + return 0; +} diff --git a/build/has/getprogname-gnu.c b/build/has/getprogname-gnu.c new file mode 100644 index 0000000..6b97c5e --- /dev/null +++ b/build/has/getprogname-gnu.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + const char *str = program_invocation_short_name; + return str[0]; +} diff --git a/build/has/getprogname.c b/build/has/getprogname.c new file mode 100644 index 0000000..83dc8e8 --- /dev/null +++ b/build/has/getprogname.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + const char *str = getprogname(); + return str[0]; +} diff --git a/build/has/max-align-t.c b/build/has/max-align-t.c new file mode 100644 index 0000000..96165ce --- /dev/null +++ b/build/has/max-align-t.c @@ -0,0 +1,8 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + return _Alignof(max_align_t); +} diff --git a/build/has/pipe2.c b/build/has/pipe2.c new file mode 100644 index 0000000..4cb43b5 --- /dev/null +++ b/build/has/pipe2.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + int fds[2]; + return pipe2(fds, O_CLOEXEC); +} diff --git a/build/has/posix-spawn-addfchdir-np.c b/build/has/posix-spawn-addfchdir-np.c new file mode 100644 index 0000000..b870a53 --- /dev/null +++ b/build/has/posix-spawn-addfchdir-np.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_addfchdir_np(&actions, 3); + return 0; +} diff --git a/build/has/posix-spawn-addfchdir.c b/build/has/posix-spawn-addfchdir.c new file mode 100644 index 0000000..c52ff81 --- /dev/null +++ b/build/has/posix-spawn-addfchdir.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_addfchdir(&actions, 3); + return 0; +} diff --git a/build/has/st-acmtim.c b/build/has/st-acmtim.c new file mode 100644 index 0000000..d687ab0 --- /dev/null +++ b/build/has/st-acmtim.c @@ -0,0 +1,12 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct stat sb = {0}; + unsigned int a = sb.st_atim.tv_sec; + unsigned int c = sb.st_ctim.tv_sec; + unsigned int m = sb.st_mtim.tv_sec; + return a + c + m; +} diff --git a/build/has/st-acmtimespec.c b/build/has/st-acmtimespec.c new file mode 100644 index 0000000..f747bc0 --- /dev/null +++ b/build/has/st-acmtimespec.c @@ -0,0 +1,12 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct stat sb = {0}; + unsigned int a = sb.st_atimespec.tv_sec; + unsigned int c = sb.st_ctimespec.tv_sec; + unsigned int m = sb.st_mtimespec.tv_sec; + return a + c + m; +} diff --git a/build/has/st-birthtim.c b/build/has/st-birthtim.c new file mode 100644 index 0000000..4964571 --- /dev/null +++ b/build/has/st-birthtim.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct stat sb = {0}; + return sb.st_birthtim.tv_sec; +} diff --git a/build/has/st-birthtimespec.c b/build/has/st-birthtimespec.c new file mode 100644 index 0000000..91a613f --- /dev/null +++ b/build/has/st-birthtimespec.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct stat sb = {0}; + return sb.st_birthtimespec.tv_sec; +} diff --git a/build/has/st-flags.c b/build/has/st-flags.c new file mode 100644 index 0000000..b1d0c32 --- /dev/null +++ b/build/has/st-flags.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct stat sb = {0}; + return sb.st_flags; +} diff --git a/build/has/statx-syscall.c b/build/has/statx-syscall.c new file mode 100644 index 0000000..87ec869 --- /dev/null +++ b/build/has/statx-syscall.c @@ -0,0 +1,13 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include +#include + +int main(void) { + struct statx sb; + syscall(SYS_statx, AT_FDCWD, ".", 0, STATX_BASIC_STATS, &sb); + return 0; +} diff --git a/build/has/statx.c b/build/has/statx.c new file mode 100644 index 0000000..65f1674 --- /dev/null +++ b/build/has/statx.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + struct statx sb; + statx(AT_FDCWD, ".", 0, STATX_BASIC_STATS, &sb); + return 0; +} diff --git a/build/has/strerror-l.c b/build/has/strerror-l.c new file mode 100644 index 0000000..3dcc4d7 --- /dev/null +++ b/build/has/strerror-l.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + locale_t locale = duplocale(LC_GLOBAL_LOCALE); + return !strerror_l(ENOMEM, locale); +} diff --git a/build/has/strerror-r-gnu.c b/build/has/strerror-r-gnu.c new file mode 100644 index 0000000..26ca0ee --- /dev/null +++ b/build/has/strerror-r-gnu.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns a pointer + return *strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/build/has/strerror-r-posix.c b/build/has/strerror-r-posix.c new file mode 100644 index 0000000..41b2d30 --- /dev/null +++ b/build/has/strerror-r-posix.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns an integer + return 2 * strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/build/has/tm-gmtoff.c b/build/has/tm-gmtoff.c new file mode 100644 index 0000000..543df48 --- /dev/null +++ b/build/has/tm-gmtoff.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + struct tm tm = {0}; + return tm.tm_gmtoff; +} diff --git a/build/has/uselocale.c b/build/has/uselocale.c new file mode 100644 index 0000000..a712ff8 --- /dev/null +++ b/build/has/uselocale.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + locale_t locale = uselocale((locale_t)0); + return locale == LC_GLOBAL_LOCALE; +} diff --git a/build/header.mk b/build/header.mk new file mode 100644 index 0000000..3f77ca5 --- /dev/null +++ b/build/header.mk @@ -0,0 +1,69 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that generates gen/config.h + +include build/prelude.mk +include gen/config.mk +include build/exports.mk + +# All header fragments we generate +HEADERS := \ + gen/has/acl-get-entry.h \ + gen/has/acl-get-file.h \ + gen/has/acl-get-tag-type.h \ + gen/has/acl-is-trivial-np.h \ + gen/has/acl-trivial.h \ + gen/has/aligned-alloc.h \ + gen/has/confstr.h \ + gen/has/extattr-get-file.h \ + gen/has/extattr-get-link.h \ + gen/has/extattr-list-file.h \ + gen/has/extattr-list-link.h \ + gen/has/fdclosedir.h \ + gen/has/getdents.h \ + gen/has/getdents64.h \ + gen/has/getdents64-syscall.h \ + gen/has/getprogname.h \ + gen/has/getprogname-gnu.h \ + gen/has/max-align-t.h \ + gen/has/pipe2.h \ + gen/has/posix-spawn-addfchdir.h \ + gen/has/posix-spawn-addfchdir-np.h \ + gen/has/st-acmtim.h \ + gen/has/st-acmtimespec.h \ + gen/has/st-birthtim.h \ + gen/has/st-birthtimespec.h \ + gen/has/st-flags.h \ + gen/has/statx.h \ + gen/has/statx-syscall.h \ + gen/has/strerror-l.h \ + gen/has/strerror-r-gnu.h \ + gen/has/strerror-r-posix.h \ + gen/has/tm-gmtoff.h \ + gen/has/uselocale.h + +# Previously generated by pkgs.mk +PKG_HEADERS := ${ALL_PKGS:%=gen/use/%.h} + +gen/config.h: ${PKG_HEADERS} ${HEADERS} + ${MSG} "[ GEN] $@" + printf '// %s\n' "$@" >$@ + printf '#ifndef BFS_CONFIG_H\n' >>$@ + printf '#define BFS_CONFIG_H\n' >>$@ + cat ${.ALLSRC} >>$@ + printf '#endif // BFS_CONFIG_H\n' >>$@ + cat ${.ALLSRC:%=%.log} >$@.log + ${VCAT} $@ +.PHONY: gen/config.h + +# The short name of the config test +SLUG = ${@:gen/%.h=%} + +${HEADERS}:: + ${MKDIR} ${@D} + if build/define-if.sh ${SLUG} build/cc.sh build/${SLUG}.c >$@ 2>$@.log; then \ + test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✔\n' ${SLUG}.c; \ + else \ + test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✘\n' ${SLUG}.c; \ + fi diff --git a/build/pkgconf.sh b/build/pkgconf.sh new file mode 100755 index 0000000..96e4bf1 --- /dev/null +++ b/build/pkgconf.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# pkg-config wrapper with hardcoded fallbacks + +set -eu + +MODE= +case "${1:-}" in + --*) + MODE="$1" + shift +esac + +if [ $# -lt 1 ]; then + exit +fi + +case "$XNOLIBS" in + y|1) + exit 1 +esac + +if [ -z "$MODE" ]; then + # Check whether the libraries exist at all + for LIB; do + # Check ${USE_$LIB} + USE_LIB="USE_$(printf '%s' "$LIB" | tr 'a-z-' 'A-Z_')" + eval "USE=\"\${$USE_LIB:-}\"" + case "$USE" in + y|1) + continue + ;; + n|0) + exit 1 + ;; + esac + + CFLAGS=$("$0" --cflags "$LIB") || exit 1 + LDFLAGS=$("$0" --ldflags "$LIB") || exit 1 + LDLIBS=$("$0" --ldlibs "$LIB") || exit 1 + build/cc.sh $CFLAGS $LDFLAGS build/use/$LIB.c $LDLIBS || exit 1 + done +fi + +# Defer to pkg-config if possible +if command -v "${XPKG_CONFIG:-}" >/dev/null 2>&1; then + case "$MODE" in + --cflags) + "$XPKG_CONFIG" --cflags "$@" + ;; + --ldflags) + "$XPKG_CONFIG" --libs-only-L --libs-only-other "$@" + ;; + --ldlibs) + "$XPKG_CONFIG" --libs-only-l "$@" + ;; + esac + + exit +fi + +# pkg-config unavailable, emulate it ourselves +CFLAGS="" +LDFLAGS="" +LDLIBS="" + +for LIB; do + case "$LIB" in + libacl) + LDLIB=-lacl + ;; + libcap) + LDLIB=-lcap + ;; + libselinux) + LDLIB=-lselinux + ;; + liburing) + LDLIB=-luring + ;; + oniguruma) + LDLIB=-lonig + ;; + *) + printf 'error: Unknown package %s\n' "$LIB" >&2 + exit 1 + ;; + esac + + LDLIBS="$LDLIBS$LDLIB " +done + +case "$MODE" in + --ldlibs) + printf '%s\n' "$LDLIBS" + ;; +esac diff --git a/build/pkgs.mk b/build/pkgs.mk new file mode 100644 index 0000000..51ca664 --- /dev/null +++ b/build/pkgs.mk @@ -0,0 +1,36 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that generates gen/pkgs.mk + +include build/prelude.mk +include gen/vars.mk +include gen/flags.mk +include build/exports.mk + +HEADERS := ${ALL_PKGS:%=gen/use/%.h} + +gen/pkgs.mk: ${HEADERS} + ${MSG} "[ GEN] $@" + printf '# %s\n' "$@" >$@ + gen() { \ + printf 'PKGS := %s\n' "$$*"; \ + printf 'CFLAGS += %s\n' "$$(build/pkgconf.sh --cflags "$$@")"; \ + printf 'LDFLAGS += %s\n' "$$(build/pkgconf.sh --ldflags "$$@")"; \ + printf 'LDLIBS := %s $${LDLIBS}\n' "$$(build/pkgconf.sh --ldlibs "$$@")"; \ + }; \ + gen $$(grep -l ' true$$' ${.ALLSRC} | sed 's|.*/\(.*\)\.h|\1|') >>$@ + ${VCAT} $@ + +.PHONY: gen/pkgs.mk + +# Convert gen/use/foo.h to foo +PKG = ${@:gen/use/%.h=%} + +${HEADERS}:: + ${MKDIR} ${@D} + if build/define-if.sh use/${PKG} build/pkgconf.sh ${PKG} >$@ 2>$@.log; then \ + test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✔\n' use/${PKG}.c; \ + else \ + test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✘\n' use/${PKG}.c; \ + fi diff --git a/build/prelude.mk b/build/prelude.mk new file mode 100644 index 0000000..b235fa9 --- /dev/null +++ b/build/prelude.mk @@ -0,0 +1,133 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Common makefile utilities. Compatible with both GNU make and most BSD makes. + +# BSD make will chdir into ${.OBJDIR} by default, unless we tell it not to +.OBJDIR: . + +# We don't use any suffix rules +.SUFFIXES: + +# GNU make has $^ for the full list of targets, while BSD make has $> and the +# long-form ${.ALLSRC}. We could write $^ $> to get them both, but that would +# break if one of them implemented support for the other. So instead, bring +# BSD's ${.ALLSRC} to GNU. +.ALLSRC ?= $^ + +# Installation paths +DESTDIR ?= +PREFIX ?= /usr +MANDIR ?= ${PREFIX}/share/man + +# Configurable executables +CC ?= cc +INSTALL ?= install +MKDIR ?= mkdir -p +PKG_CONFIG ?= pkg-config +RM ?= rm -f + +# GNU and BSD make have incompatible syntax for conditionals, but we can do a +# lot with just nested variable expansion. We use "y" as the canonical +# truthy value, and "" (the empty string) as the canonical falsey value. +# +# To normalize a boolean, use ${TRUTHY,${VAR}}, which expands like this: +# +# VAR=y ${TRUTHY,${VAR}} => ${TRUTHY,y} => y +# VAR=1 ${TRUTHY,${VAR}} => ${TRUTHY,1} => y +# VAR=n ${TRUTHY,${VAR}} => ${TRUTHY,n} => [empty] +# VAR=other ${TRUTHY,${VAR}} => ${TRUTHY,other} => [empty] +# VAR= ${TRUTHY,${VAR}} => ${TRUTHY,} => [emtpy] +# +# Inspired by https://github.com/wahern/autoguess +TRUTHY,y := y +TRUTHY,1 := y + +# Boolean operators are also implemented with nested expansion +NOT, := y + +# Normalize ${V} to either "y" or "" +IS_V := ${TRUTHY,${V}} + +# Suppress output unless V=1 +Q, := @ +Q := ${Q,${IS_V}} + +# Show full commands with `make V=1`, otherwise short summaries +MSG = @msg() { \ + MSG="$$1"; \ + shift; \ + test "${IS_V}" || printf '%s\n' "$$MSG"; \ + test "$${1:-}" || return 0; \ + test "${IS_V}" && printf '%s\n' "$$*"; \ + "$$@"; \ + }; \ + msg + +# Maximum width of a short message, to align the ✔/✘ +MSG_WIDTH := 30 + +# cat a file if V=1 +VCAT,y := @cat +VCAT, := @: +VCAT := ${VCAT,${IS_V}} + +# All external dependencies +ALL_PKGS := \ + libacl \ + libcap \ + libselinux \ + liburing \ + oniguruma + +# List all object files here, as they're needed by both `./configure` and `make` + +# All object files except the entry point +LIBBFS := \ + obj/src/alloc.o \ + obj/src/bar.o \ + obj/src/bfstd.o \ + obj/src/bftw.o \ + obj/src/color.o \ + obj/src/ctx.o \ + obj/src/diag.o \ + obj/src/dir.o \ + obj/src/dstring.o \ + obj/src/eval.o \ + obj/src/exec.o \ + obj/src/expr.o \ + obj/src/fsade.o \ + obj/src/ioq.o \ + obj/src/mtab.o \ + obj/src/opt.o \ + obj/src/parse.o \ + obj/src/printf.o \ + obj/src/pwcache.o \ + obj/src/stat.o \ + obj/src/thread.o \ + obj/src/trie.o \ + obj/src/typo.o \ + obj/src/xregex.o \ + obj/src/xspawn.o \ + obj/src/xtime.o \ + obj/gen/version.o + +# Unit test objects +UNIT_OBJS := \ + obj/tests/alloc.o \ + obj/tests/bfstd.o \ + obj/tests/bit.o \ + obj/tests/ioq.o \ + obj/tests/main.o \ + obj/tests/trie.o \ + obj/tests/xspawn.o \ + obj/tests/xtime.o + +# All object files +OBJS := \ + obj/src/main.o \ + obj/tests/mksock.o \ + obj/tests/xspawnee.o \ + obj/tests/xtouch.o \ + ${LIBBFS} \ + ${UNIT_OBJS} diff --git a/build/use/libacl.c b/build/use/libacl.c new file mode 100644 index 0000000..de1fe50 --- /dev/null +++ b/build/use/libacl.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + acl_free(0); + return 0; +} diff --git a/build/use/libcap.c b/build/use/libcap.c new file mode 100644 index 0000000..58e832c --- /dev/null +++ b/build/use/libcap.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + cap_free(0); + return 0; +} diff --git a/build/use/libselinux.c b/build/use/libselinux.c new file mode 100644 index 0000000..bca409d --- /dev/null +++ b/build/use/libselinux.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + freecon(0); + return 0; +} diff --git a/build/use/liburing.c b/build/use/liburing.c new file mode 100644 index 0000000..bea499a --- /dev/null +++ b/build/use/liburing.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + io_uring_free_probe(0); + return 0; +} diff --git a/build/use/oniguruma.c b/build/use/oniguruma.c new file mode 100644 index 0000000..cb17596 --- /dev/null +++ b/build/use/oniguruma.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + onig_free(0); + return 0; +} diff --git a/config/cc.sh b/config/cc.sh deleted file mode 100755 index 45d51ca..0000000 --- a/config/cc.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Run the compiler and check if it succeeded - -set -eu - -TMP=$(mktemp) -trap 'rm -f "$TMP"' EXIT - -( - set -x - $XCC $XCPPFLAGS $XCFLAGS $XLDFLAGS "$@" $XLDLIBS -o "$TMP" -) diff --git a/config/config.mk b/config/config.mk deleted file mode 100644 index 280c6ac..0000000 --- a/config/config.mk +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile fragment that implements `make config` - -include config/prelude.mk -include config/exports.mk - -# All configuration steps -config: ${CONFIG} ${GEN}/config.h -.PHONY: config - -# Makefile fragments generated by `make config` -MKS := \ - ${GEN}/vars.mk \ - ${GEN}/flags.mk \ - ${GEN}/deps.mk \ - ${GEN}/pkgs.mk - -# The main configuration file, which includes the others -${CONFIG}: ${MKS} - ${MSG} "[ GEN] ${TGT}" - @printf '# %s\n' "${TGT}" >$@ - @printf 'include $${GEN}/%s\n' ${MKS:${GEN}/%=%} >>$@ - ${VCAT} ${CONFIG} -.PHONY: ${CONFIG} - -# Saves the configurable variables -${GEN}/vars.mk:: - @${MKDIR} ${@D} - ${MSG} "[ GEN] ${TGT}" - @printf '# %s\n' "${TGT}" >$@ - @printf 'PREFIX := %s\n' "$$XPREFIX" >>$@ - @printf 'MANDIR := %s\n' "$$XMANDIR" >>$@ - @printf 'OS := %s\n' "$${OS:-$$(uname)}" >>$@ - @printf 'CC := %s\n' "$$XCC" >>$@ - @printf 'INSTALL := %s\n' "$$XINSTALL" >>$@ - @printf 'MKDIR := %s\n' "$$XMKDIR" >>$@ - @printf 'PKG_CONFIG := %s\n' "$$XPKG_CONFIG" >>$@ - @printf 'RM := %s\n' "$$XRM" >>$@ - @printf 'PKGS :=\n' >>$@ - ${VCAT} $@ - -# Sets the build flags. This depends on vars.mk and uses a recursive make so -# that the default flags can depend on variables like ${OS}. -${GEN}/flags.mk: ${GEN}/vars.mk - @+${MAKE} -sf config/flags.mk $@ -.PHONY: ${GEN}/flags.mk - -# Check for dependency generation support -${GEN}/deps.mk: ${GEN}/flags.mk - @+${MAKE} -sf config/deps.mk $@ -.PHONY: ${GEN}/deps.mk - -# Auto-detect dependencies and their build flags -${GEN}/pkgs.mk: ${GEN}/flags.mk - @+${MAKE} -sf config/pkgs.mk $@ -.PHONY: ${GEN}/pkgs.mk - -# Compile-time feature detection -${GEN}/config.h: ${CONFIG} - @+${MAKE} -sf config/header.mk $@ -.PHONY: ${GEN}/config.h diff --git a/config/define-if.sh b/config/define-if.sh deleted file mode 100755 index 059c1ac..0000000 --- a/config/define-if.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Output a C preprocessor definition based on whether a command succeeds - -set -eu - -SLUG="${1#config/}" -SLUG="${SLUG%.c}" -MACRO="BFS_$(printf '%s' "$SLUG" | tr '/a-z-' '_A-Z_')" -shift - -if "$@"; then - printf '#define %s true\n' "$MACRO" -else - printf '#define %s false\n' "$MACRO" - exit 1 -fi diff --git a/config/deps.mk b/config/deps.mk deleted file mode 100644 index ac394a5..0000000 --- a/config/deps.mk +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile that generates gen/deps.mk - -include config/prelude.mk -include ${GEN}/vars.mk -include ${GEN}/flags.mk -include config/exports.mk - -${GEN}/deps.mk:: - ${MSG} "[ GEN] ${TGT}" - printf '# %s\n' "${TGT}" >$@ - if config/cc.sh -MD -MP -MF /dev/null config/empty.c; then \ - printf 'DEPFLAGS = -MD -MP\n'; \ - fi >>$@ 2>$@.log - ${VCAT} $@ - printf -- '-include %s\n' ${OBJS:.o=.d} >>$@ diff --git a/config/empty.c b/config/empty.c deleted file mode 100644 index 4fa9a5b..0000000 --- a/config/empty.c +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -int main(void) { - return 0; -} diff --git a/config/exports.mk b/config/exports.mk deleted file mode 100644 index ed19134..0000000 --- a/config/exports.mk +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile fragment that exports variables used by configuration scripts - -export XPREFIX=${PREFIX} -export XMANDIR=${MANDIR} - -export XCC=${CC} -export XINSTALL=${INSTALL} -export XMKDIR=${MKDIR} -export XPKG_CONFIG=${PKG_CONFIG} -export XRM=${RM} - -export XCPPFLAGS=${CPPFLAGS} -export XCFLAGS=${CFLAGS} -export XLDFLAGS=${LDFLAGS} -export XLDLIBS=${LDLIBS} - -export XNOLIBS=${NOLIBS} diff --git a/config/flags.mk b/config/flags.mk deleted file mode 100644 index 837c30f..0000000 --- a/config/flags.mk +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile that generates gen/flags.mk - -include config/prelude.mk -include ${GEN}/vars.mk - -# Configurable flags -CPPFLAGS ?= -CFLAGS ?= \ - -g \ - -Wall \ - -Wformat=2 \ - -Werror=implicit \ - -Wimplicit-fallthrough \ - -Wmissing-declarations \ - -Wshadow \ - -Wsign-compare \ - -Wstrict-prototypes -LDFLAGS ?= -LDLIBS ?= - -export XCPPFLAGS=${CPPFLAGS} -export XCFLAGS=${CFLAGS} -export XLDFLAGS=${LDFLAGS} -export XLDLIBS=${LDLIBS} - -# Immutable flags -export BFS_CPPFLAGS= \ - -Isrc \ - -I${GEN} \ - -D__EXTENSIONS__ \ - -D_ATFILE_SOURCE \ - -D_BSD_SOURCE \ - -D_DARWIN_C_SOURCE \ - -D_DEFAULT_SOURCE \ - -D_GNU_SOURCE \ - -D_POSIX_PTHREAD_SEMANTICS \ - -D_FILE_OFFSET_BITS=64 \ - -D_TIME_BITS=64 -export BFS_CFLAGS= -std=c17 -pthread - -# Platform-specific system libraries -LDLIBS,DragonFly := -lposix1e -LDLIBS,Linux := -lrt -LDLIBS,NetBSD := -lutil -LDLIBS,SunOS := -lsec -lsocket -lnsl -export BFS_LDLIBS=${LDLIBS,${OS}} - -# Build profiles -_ASAN := ${TRUTHY,${ASAN}} -_LSAN := ${TRUTHY,${LSAN}} -_MSAN := ${TRUTHY,${MSAN}} -_TSAN := ${TRUTHY,${TSAN}} -_UBSAN := ${TRUTHY,${UBSAN}} -_GCOV := ${TRUTHY,${GCOV}} -_LINT := ${TRUTHY,${LINT}} -_RELEASE := ${TRUTHY,${RELEASE}} - -# https://github.com/google/sanitizers/issues/342 -TSAN_CPPFLAGS,y := -DBFS_USE_TARGET_CLONES=0 -export TSAN_CPPFLAGS=${TSAN_CPPFLAGS,${_TSAN}} - -ASAN_CFLAGS,y := -fsanitize=address -LSAN_CFLAGS,y := -fsanitize=leak -MSAN_CFLAGS,y := -fsanitize=memory -fsanitize-memory-track-origins -TSAN_CFLAGS,y := -fsanitize=thread -UBSAN_CFLAGS.y := -fsanitize=undefined - -export ASAN_CFLAGS=${ASAN_CFLAGS,${_ASAN}} -export LSAN_CFLAGS=${LSAN_CFLAGS,${_LSAN}} -export MSAN_CFLAGS=${MSAN_CFLAGS,${_MSAN}} -export TSAN_CFLAGS=${TSAN_CFLAGS,${_TSAN}} -export UBSAN_CFLAGS=${UBSAN_CFLAGS,${_UBSAN}} - -SAN_CFLAGS,y := -fno-sanitize-recover=all -INSANE := ${NOT,${_ASAN}${_LSAN}${_MSAN}${_TSAN}${_UBSAN}} -SAN := ${NOT,${INSANE}} -export SAN_CFLAGS=${SAN_CFLAGS,${SAN}} - -# MSAN and TSAN both need all code to be instrumented -YESLIBS := ${NOT,${_MSAN}${_TSAN}} -NOLIBS ?= ${NOT,${YESLIBS}} -export XNOLIBS=${NOLIBS} - -# gcov only intercepts fork()/exec() with -std=gnu* -GCOV_CFLAGS,y := -std=gnu17 --coverage -export GCOV_CFLAGS=${GCOV_CFLAGS,${_GCOV}} - -LINT_CPPFLAGS,y := -D_FORTIFY_SOURCE=3 -DBFS_LINT -LINT_CFLAGS,y := -Werror -O2 - -export LINT_CPPFLAGS=${LINT_CPPFLAGS,${_LINT}} -export LINT_CFLAGS=${LINT_CFLAGS,${_LINT}} - -RELEASE_CPPFLAGS,y := -DNDEBUG -RELEASE_CFLAGS,y := -O3 -flto=auto - -export RELEASE_CPPFLAGS=${RELEASE_CPPFLAGS,${_RELEASE}} -export RELEASE_CFLAGS=${RELEASE_CFLAGS,${_RELEASE}} - -# Set a variable -SETVAR = printf '%s := %s\n' >>$@ - -# Append to a variable, if non-empty -APPEND = append() { test -z "$$2" || printf '%s += %s\n' "$$1" "$$2" >>$@; }; append - -${GEN}/flags.mk:: - ${MSG} "[ GEN] ${TGT}" - printf '# %s\n' "${TGT}" >$@ - ${SETVAR} CPPFLAGS "$$BFS_CPPFLAGS" - ${APPEND} CPPFLAGS "$$TSAN_CPPFLAGS" - ${APPEND} CPPFLAGS "$$LINT_CPPFLAGS" - ${APPEND} CPPFLAGS "$$RELEASE_CPPFLAGS" - ${APPEND} CPPFLAGS "$$XCPPFLAGS" - ${APPEND} CPPFLAGS "$$EXTRA_CPPFLAGS" - ${SETVAR} CFLAGS "$$BFS_CFLAGS" - ${APPEND} CFLAGS "$$ASAN_CFLAGS" - ${APPEND} CFLAGS "$$LSAN_CFLAGS" - ${APPEND} CFLAGS "$$MSAN_CFLAGS" - ${APPEND} CFLAGS "$$TSAN_CFLAGS" - ${APPEND} CFLAGS "$$UBSAN_CFLAGS" - ${APPEND} CFLAGS "$$SAN_CFLAGS" - ${APPEND} CFLAGS "$$GCOV_CFLAGS" - ${APPEND} CFLAGS "$$LINT_CFLAGS" - ${APPEND} CFLAGS "$$RELEASE_CFLAGS" - ${APPEND} CFLAGS "$$XCFLAGS" - ${APPEND} CFLAGS "$$EXTRA_CFLAGS" - ${SETVAR} LDFLAGS "$$XLDFLAGS" - ${SETVAR} LDLIBS "$$XLDLIBS" - ${APPEND} LDLIBS "$$EXTRA_LDLIBS" - ${APPEND} LDLIBS "$$BFS_LDLIBS" - ${SETVAR} NOLIBS "$$XNOLIBS" - test "${OS}-${SAN}" != FreeBSD-y || printf 'POSTLINK = elfctl -e +noaslr $$@\n' >>$@ - ${VCAT} $@ diff --git a/config/has/acl-get-entry.c b/config/has/acl-get-entry.c deleted file mode 100644 index 3cce771..0000000 --- a/config/has/acl-get-entry.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -int main(void) { - acl_t acl = acl_get_file(".", ACL_TYPE_DEFAULT); - acl_entry_t entry; - return acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); -} diff --git a/config/has/acl-get-file.c b/config/has/acl-get-file.c deleted file mode 100644 index 89fbf23..0000000 --- a/config/has/acl-get-file.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -#include - -int main(void) { - acl_t acl = acl_get_file(".", ACL_TYPE_DEFAULT); - return acl == (acl_t)NULL; -} diff --git a/config/has/acl-get-tag-type.c b/config/has/acl-get-tag-type.c deleted file mode 100644 index 2901956..0000000 --- a/config/has/acl-get-tag-type.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include - -int main(void) { - acl_entry_t entry; - memset(&entry, 0, sizeof(entry)); - acl_tag_t tag; - return acl_get_tag_type(entry, &tag); -} diff --git a/config/has/acl-is-trivial-np.c b/config/has/acl-is-trivial-np.c deleted file mode 100644 index 9ca9fc7..0000000 --- a/config/has/acl-is-trivial-np.c +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include - -int main(void) { - acl_t acl = acl_get_fd(3); - int trivial; - acl_is_trivial_np(acl, &trivial); - return 0; -} diff --git a/config/has/acl-trivial.c b/config/has/acl-trivial.c deleted file mode 100644 index 7efc838..0000000 --- a/config/has/acl-trivial.c +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - return acl_trivial("."); -} diff --git a/config/has/aligned-alloc.c b/config/has/aligned-alloc.c deleted file mode 100644 index 4460038..0000000 --- a/config/has/aligned-alloc.c +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - return !aligned_alloc(_Alignof(void *), sizeof(void *)); -} diff --git a/config/has/confstr.c b/config/has/confstr.c deleted file mode 100644 index 58280b4..0000000 --- a/config/has/confstr.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - confstr(_CS_PATH, NULL, 0); - return 0; -} diff --git a/config/has/extattr-get-file.c b/config/has/extattr-get-file.c deleted file mode 100644 index ac9cf96..0000000 --- a/config/has/extattr-get-file.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - return extattr_get_file("file", EXTATTR_NAMESPACE_USER, "xattr", NULL, 0); -} diff --git a/config/has/extattr-get-link.c b/config/has/extattr-get-link.c deleted file mode 100644 index c35be5b..0000000 --- a/config/has/extattr-get-link.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - return extattr_get_link("link", EXTATTR_NAMESPACE_USER, "xattr", NULL, 0); -} diff --git a/config/has/extattr-list-file.c b/config/has/extattr-list-file.c deleted file mode 100644 index e68a8bb..0000000 --- a/config/has/extattr-list-file.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - return extattr_list_file("file", EXTATTR_NAMESPACE_USER, NULL, 0); -} diff --git a/config/has/extattr-list-link.c b/config/has/extattr-list-link.c deleted file mode 100644 index 49f0ec2..0000000 --- a/config/has/extattr-list-link.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - return extattr_list_link("link", EXTATTR_NAMESPACE_USER, NULL, 0); -} diff --git a/config/has/fdclosedir.c b/config/has/fdclosedir.c deleted file mode 100644 index f4ad1f5..0000000 --- a/config/has/fdclosedir.c +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - return fdclosedir(opendir(".")); -} diff --git a/config/has/getdents.c b/config/has/getdents.c deleted file mode 100644 index d0d4228..0000000 --- a/config/has/getdents.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct dirent de; - getdents(3, &de, 1024); - return 0; -} diff --git a/config/has/getdents64-syscall.c b/config/has/getdents64-syscall.c deleted file mode 100644 index 4838c14..0000000 --- a/config/has/getdents64-syscall.c +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - struct dirent64 de; - syscall(SYS_getdents64, 3, &de, 1024); - return 0; -} diff --git a/config/has/getdents64.c b/config/has/getdents64.c deleted file mode 100644 index 1abf36d..0000000 --- a/config/has/getdents64.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct dirent64 de; - getdents64(3, &de, 1024); - return 0; -} diff --git a/config/has/getprogname-gnu.c b/config/has/getprogname-gnu.c deleted file mode 100644 index 6b97c5e..0000000 --- a/config/has/getprogname-gnu.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - const char *str = program_invocation_short_name; - return str[0]; -} diff --git a/config/has/getprogname.c b/config/has/getprogname.c deleted file mode 100644 index 83dc8e8..0000000 --- a/config/has/getprogname.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - const char *str = getprogname(); - return str[0]; -} diff --git a/config/has/max-align-t.c b/config/has/max-align-t.c deleted file mode 100644 index 96165ce..0000000 --- a/config/has/max-align-t.c +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - return _Alignof(max_align_t); -} diff --git a/config/has/pipe2.c b/config/has/pipe2.c deleted file mode 100644 index 4cb43b5..0000000 --- a/config/has/pipe2.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include - -int main(void) { - int fds[2]; - return pipe2(fds, O_CLOEXEC); -} diff --git a/config/has/posix-spawn-addfchdir-np.c b/config/has/posix-spawn-addfchdir-np.c deleted file mode 100644 index b870a53..0000000 --- a/config/has/posix-spawn-addfchdir-np.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - posix_spawn_file_actions_t actions; - posix_spawn_file_actions_init(&actions); - posix_spawn_file_actions_addfchdir_np(&actions, 3); - return 0; -} diff --git a/config/has/posix-spawn-addfchdir.c b/config/has/posix-spawn-addfchdir.c deleted file mode 100644 index c52ff81..0000000 --- a/config/has/posix-spawn-addfchdir.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - posix_spawn_file_actions_t actions; - posix_spawn_file_actions_init(&actions); - posix_spawn_file_actions_addfchdir(&actions, 3); - return 0; -} diff --git a/config/has/st-acmtim.c b/config/has/st-acmtim.c deleted file mode 100644 index d687ab0..0000000 --- a/config/has/st-acmtim.c +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct stat sb = {0}; - unsigned int a = sb.st_atim.tv_sec; - unsigned int c = sb.st_ctim.tv_sec; - unsigned int m = sb.st_mtim.tv_sec; - return a + c + m; -} diff --git a/config/has/st-acmtimespec.c b/config/has/st-acmtimespec.c deleted file mode 100644 index f747bc0..0000000 --- a/config/has/st-acmtimespec.c +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct stat sb = {0}; - unsigned int a = sb.st_atimespec.tv_sec; - unsigned int c = sb.st_ctimespec.tv_sec; - unsigned int m = sb.st_mtimespec.tv_sec; - return a + c + m; -} diff --git a/config/has/st-birthtim.c b/config/has/st-birthtim.c deleted file mode 100644 index 4964571..0000000 --- a/config/has/st-birthtim.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct stat sb = {0}; - return sb.st_birthtim.tv_sec; -} diff --git a/config/has/st-birthtimespec.c b/config/has/st-birthtimespec.c deleted file mode 100644 index 91a613f..0000000 --- a/config/has/st-birthtimespec.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct stat sb = {0}; - return sb.st_birthtimespec.tv_sec; -} diff --git a/config/has/st-flags.c b/config/has/st-flags.c deleted file mode 100644 index b1d0c32..0000000 --- a/config/has/st-flags.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct stat sb = {0}; - return sb.st_flags; -} diff --git a/config/has/statx-syscall.c b/config/has/statx-syscall.c deleted file mode 100644 index 87ec869..0000000 --- a/config/has/statx-syscall.c +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include -#include - -int main(void) { - struct statx sb; - syscall(SYS_statx, AT_FDCWD, ".", 0, STATX_BASIC_STATS, &sb); - return 0; -} diff --git a/config/has/statx.c b/config/has/statx.c deleted file mode 100644 index 65f1674..0000000 --- a/config/has/statx.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include - -int main(void) { - struct statx sb; - statx(AT_FDCWD, ".", 0, STATX_BASIC_STATS, &sb); - return 0; -} diff --git a/config/has/strerror-l.c b/config/has/strerror-l.c deleted file mode 100644 index 3dcc4d7..0000000 --- a/config/has/strerror-l.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include -#include - -int main(void) { - locale_t locale = duplocale(LC_GLOBAL_LOCALE); - return !strerror_l(ENOMEM, locale); -} diff --git a/config/has/strerror-r-gnu.c b/config/has/strerror-r-gnu.c deleted file mode 100644 index 26ca0ee..0000000 --- a/config/has/strerror-r-gnu.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include - -int main(void) { - char buf[256]; - // Check that strerror_r() returns a pointer - return *strerror_r(ENOMEM, buf, sizeof(buf)); -} diff --git a/config/has/strerror-r-posix.c b/config/has/strerror-r-posix.c deleted file mode 100644 index 41b2d30..0000000 --- a/config/has/strerror-r-posix.c +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include -#include - -int main(void) { - char buf[256]; - // Check that strerror_r() returns an integer - return 2 * strerror_r(ENOMEM, buf, sizeof(buf)); -} diff --git a/config/has/tm-gmtoff.c b/config/has/tm-gmtoff.c deleted file mode 100644 index 543df48..0000000 --- a/config/has/tm-gmtoff.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - struct tm tm = {0}; - return tm.tm_gmtoff; -} diff --git a/config/has/uselocale.c b/config/has/uselocale.c deleted file mode 100644 index a712ff8..0000000 --- a/config/has/uselocale.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - locale_t locale = uselocale((locale_t)0); - return locale == LC_GLOBAL_LOCALE; -} diff --git a/config/header.mk b/config/header.mk deleted file mode 100644 index 50ad5e8..0000000 --- a/config/header.mk +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile that generates gen/config.h - -include config/prelude.mk -include ${GEN}/config.mk -include config/exports.mk - -# All header fragments we generate -HEADERS := \ - ${GEN}/has/acl-get-entry.h \ - ${GEN}/has/acl-get-file.h \ - ${GEN}/has/acl-get-tag-type.h \ - ${GEN}/has/acl-is-trivial-np.h \ - ${GEN}/has/acl-trivial.h \ - ${GEN}/has/aligned-alloc.h \ - ${GEN}/has/confstr.h \ - ${GEN}/has/extattr-get-file.h \ - ${GEN}/has/extattr-get-link.h \ - ${GEN}/has/extattr-list-file.h \ - ${GEN}/has/extattr-list-link.h \ - ${GEN}/has/fdclosedir.h \ - ${GEN}/has/getdents.h \ - ${GEN}/has/getdents64.h \ - ${GEN}/has/getdents64-syscall.h \ - ${GEN}/has/getprogname.h \ - ${GEN}/has/getprogname-gnu.h \ - ${GEN}/has/max-align-t.h \ - ${GEN}/has/pipe2.h \ - ${GEN}/has/posix-spawn-addfchdir.h \ - ${GEN}/has/posix-spawn-addfchdir-np.h \ - ${GEN}/has/st-acmtim.h \ - ${GEN}/has/st-acmtimespec.h \ - ${GEN}/has/st-birthtim.h \ - ${GEN}/has/st-birthtimespec.h \ - ${GEN}/has/st-flags.h \ - ${GEN}/has/statx.h \ - ${GEN}/has/statx-syscall.h \ - ${GEN}/has/strerror-l.h \ - ${GEN}/has/strerror-r-gnu.h \ - ${GEN}/has/strerror-r-posix.h \ - ${GEN}/has/tm-gmtoff.h \ - ${GEN}/has/uselocale.h - -# Previously generated by pkgs.mk -PKG_HEADERS := ${ALL_PKGS:%=${GEN}/use/%.h} - -${GEN}/config.h: ${PKG_HEADERS} ${HEADERS} - ${MSG} "[ GEN] ${TGT}" - printf '// %s\n' "${TGT}" >$@ - printf '#ifndef BFS_CONFIG_H\n' >>$@ - printf '#define BFS_CONFIG_H\n' >>$@ - cat ${.ALLSRC} >>$@ - printf '#endif // BFS_CONFIG_H\n' >>$@ - cat ${.ALLSRC:%=%.log} >$@.log - ${VCAT} $@ -.PHONY: ${GEN}/config.h - -# The short name of the config test -SLUG = ${@:${GEN}/%.h=%} - -${HEADERS}:: - ${MKDIR} ${@D} - if config/define-if.sh ${SLUG} config/cc.sh config/${SLUG}.c >$@ 2>$@.log; then \ - test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✔\n' ${SLUG}.c; \ - else \ - test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✘\n' ${SLUG}.c; \ - fi diff --git a/config/pkgconf.sh b/config/pkgconf.sh deleted file mode 100755 index 365ed61..0000000 --- a/config/pkgconf.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/sh - -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# pkg-config wrapper with hardcoded fallbacks - -set -eu - -MODE= -case "${1:-}" in - --*) - MODE="$1" - shift -esac - -if [ $# -lt 1 ]; then - exit -fi - -case "$XNOLIBS" in - y|1) - exit 1 -esac - -if [ -z "$MODE" ]; then - # Check whether the libraries exist at all - for LIB; do - # Check ${USE_$LIB} - USE_LIB="USE_$(printf '%s' "$LIB" | tr 'a-z-' 'A-Z_')" - eval "USE=\"\${$USE_LIB:-}\"" - case "$USE" in - y|1) - continue - ;; - n|0) - exit 1 - ;; - esac - - CFLAGS=$("$0" --cflags "$LIB") || exit 1 - LDFLAGS=$("$0" --ldflags "$LIB") || exit 1 - LDLIBS=$("$0" --ldlibs "$LIB") || exit 1 - config/cc.sh $CFLAGS $LDFLAGS config/use/$LIB.c $LDLIBS || exit 1 - done -fi - -# Defer to pkg-config if possible -if command -v "${XPKG_CONFIG:-}" >/dev/null 2>&1; then - case "$MODE" in - --cflags) - "$XPKG_CONFIG" --cflags "$@" - ;; - --ldflags) - "$XPKG_CONFIG" --libs-only-L --libs-only-other "$@" - ;; - --ldlibs) - "$XPKG_CONFIG" --libs-only-l "$@" - ;; - esac - - exit -fi - -# pkg-config unavailable, emulate it ourselves -CFLAGS="" -LDFLAGS="" -LDLIBS="" - -for LIB; do - case "$LIB" in - libacl) - LDLIB=-lacl - ;; - libcap) - LDLIB=-lcap - ;; - libselinux) - LDLIB=-lselinux - ;; - liburing) - LDLIB=-luring - ;; - oniguruma) - LDLIB=-lonig - ;; - *) - printf 'error: Unknown package %s\n' "$LIB" >&2 - exit 1 - ;; - esac - - LDLIBS="$LDLIBS$LDLIB " -done - -case "$MODE" in - --ldlibs) - printf '%s\n' "$LDLIBS" - ;; -esac diff --git a/config/pkgs.mk b/config/pkgs.mk deleted file mode 100644 index 898f262..0000000 --- a/config/pkgs.mk +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Makefile that generates gen/pkgs.mk - -include config/prelude.mk -include ${GEN}/vars.mk -include ${GEN}/flags.mk -include config/exports.mk - -HEADERS := ${ALL_PKGS:%=${GEN}/use/%.h} - -${GEN}/pkgs.mk: ${HEADERS} - ${MSG} "[ GEN] ${TGT}" - printf '# %s\n' "${TGT}" >$@ - gen() { \ - printf 'PKGS := %s\n' "$$*"; \ - printf 'CFLAGS += %s\n' "$$(config/pkgconf.sh --cflags "$$@")"; \ - printf 'LDFLAGS += %s\n' "$$(config/pkgconf.sh --ldflags "$$@")"; \ - printf 'LDLIBS := %s $${LDLIBS}\n' "$$(config/pkgconf.sh --ldlibs "$$@")"; \ - }; \ - gen $$(grep -l ' true$$' ${.ALLSRC} | sed 's|.*/\(.*\)\.h|\1|') >>$@ - ${VCAT} $@ - -.PHONY: ${GEN}/pkgs.mk - -# Convert ${GEN}/use/foo.h to foo -PKG = ${@:${GEN}/use/%.h=%} - -${HEADERS}:: - ${MKDIR} ${@D} - if config/define-if.sh use/${PKG} config/pkgconf.sh ${PKG} >$@ 2>$@.log; then \ - test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✔\n' use/${PKG}.c; \ - else \ - test "${IS_V}" || printf '[ CC ] %-${MSG_WIDTH}s ✘\n' use/${PKG}.c; \ - fi diff --git a/config/prelude.mk b/config/prelude.mk deleted file mode 100644 index 109e60c..0000000 --- a/config/prelude.mk +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright © Tavian Barnes -# SPDX-License-Identifier: 0BSD - -# Common makefile utilities. Compatible with both GNU make and most BSD makes. - -# BSD make will chdir into ${.OBJDIR} by default, unless we tell it not to -.OBJDIR: . - -# We don't use any suffix rules -.SUFFIXES: - -# GNU make has $^ for the full list of targets, while BSD make has $> and the -# long-form ${.ALLSRC}. We could write $^ $> to get them both, but that would -# break if one of them implemented support for the other. So instead, bring -# BSD's ${.ALLSRC} to GNU. -.ALLSRC ?= $^ - -# For out-of-tree builds, e.g. -# -# $ make config BUILDDIR=/path/to/build/dir -# $ make BUILDDIR=/path/to/build/dir -BUILDDIR ?= . - -# Shorthand for build subdirectories -BIN := ${BUILDDIR}/bin -GEN := ${BUILDDIR}/gen -OBJ := ${BUILDDIR}/obj - -# GNU make strips a leading ./ from target names, so do the same for BSD make -BIN := ${BIN:./%=%} -GEN := ${GEN:./%=%} -OBJ := ${OBJ:./%=%} - -# The configuration file generated by `make config` -CONFIG := ${GEN}/config.mk - -# Installation paths -DESTDIR ?= -PREFIX ?= /usr -MANDIR ?= ${PREFIX}/share/man - -# GNU make supports `export VAR`, but BSD make requires `export VAR=value`. -# Sadly, GNU make gives a recursion error on `export VAR=${VAR}`. -_BUILDDIR := ${BUILDDIR} -export BUILDDIR=${_BUILDDIR} - -# Configurable executables; can be overridden with -# -# $ make config CC=clang -CC ?= cc -INSTALL ?= install -MKDIR ?= mkdir -p -PKG_CONFIG ?= pkg-config -RM ?= rm -f - -# GNU and BSD make have incompatible syntax for conditionals, but we can do a -# lot with just nested variable expansion. We use "y" as the canonical -# truthy value, and "" (the empty string) as the canonical falsey value. -# -# To normalize a boolean, use ${TRUTHY,${VAR}}, which expands like this: -# -# VAR=y ${TRUTHY,${VAR}} => ${TRUTHY,y} => y -# VAR=1 ${TRUTHY,${VAR}} => ${TRUTHY,1} => y -# VAR=n ${TRUTHY,${VAR}} => ${TRUTHY,n} => [empty] -# VAR=other ${TRUTHY,${VAR}} => ${TRUTHY,other} => [empty] -# VAR= ${TRUTHY,${VAR}} => ${TRUTHY,} => [emtpy] -# -# Inspired by https://github.com/wahern/autoguess -TRUTHY,y := y -TRUTHY,1 := y - -# Boolean operators are also implemented with nested expansion -NOT, := y - -# Normalize ${V} to either "y" or "" -IS_V := ${TRUTHY,${V}} - -# Suppress output unless V=1 -Q, := @ -Q := ${Q,${IS_V}} - -# The current target, with ${BUILDDIR} stripped for shorter messages -TGT = ${@:${BUILDDIR}/%=%} - -# Show full commands with `make V=1`, otherwise short summaries -MSG = @msg() { \ - MSG="$$1"; \ - shift; \ - test "${IS_V}" || printf '%s\n' "$$MSG"; \ - test "$${1:-}" || return 0; \ - test "${IS_V}" && printf '%s\n' "$$*"; \ - "$$@"; \ - }; \ - msg - -# Maximum width of a short message, to align the ✔/✘ -MSG_WIDTH := 30 - -# cat a file if V=1 -VCAT,y := @cat -VCAT, := @: -VCAT := ${VCAT,${IS_V}} - -# All external dependencies -ALL_PKGS := \ - libacl \ - libcap \ - libselinux \ - liburing \ - oniguruma - -# List all object files here, as they're needed by both `make config` and `make` - -# All object files except the entry point -LIBBFS := \ - ${OBJ}/src/alloc.o \ - ${OBJ}/src/bar.o \ - ${OBJ}/src/bfstd.o \ - ${OBJ}/src/bftw.o \ - ${OBJ}/src/color.o \ - ${OBJ}/src/ctx.o \ - ${OBJ}/src/diag.o \ - ${OBJ}/src/dir.o \ - ${OBJ}/src/dstring.o \ - ${OBJ}/src/eval.o \ - ${OBJ}/src/exec.o \ - ${OBJ}/src/expr.o \ - ${OBJ}/src/fsade.o \ - ${OBJ}/src/ioq.o \ - ${OBJ}/src/mtab.o \ - ${OBJ}/src/opt.o \ - ${OBJ}/src/parse.o \ - ${OBJ}/src/printf.o \ - ${OBJ}/src/pwcache.o \ - ${OBJ}/src/stat.o \ - ${OBJ}/src/thread.o \ - ${OBJ}/src/trie.o \ - ${OBJ}/src/typo.o \ - ${OBJ}/src/xregex.o \ - ${OBJ}/src/xspawn.o \ - ${OBJ}/src/xtime.o \ - ${OBJ}/gen/version.o - -# Unit test objects -UNIT_OBJS := \ - ${OBJ}/tests/alloc.o \ - ${OBJ}/tests/bfstd.o \ - ${OBJ}/tests/bit.o \ - ${OBJ}/tests/ioq.o \ - ${OBJ}/tests/main.o \ - ${OBJ}/tests/trie.o \ - ${OBJ}/tests/xspawn.o \ - ${OBJ}/tests/xtime.o - -# All object files -OBJS := \ - ${OBJ}/src/main.o \ - ${OBJ}/tests/mksock.o \ - ${OBJ}/tests/xspawnee.o \ - ${OBJ}/tests/xtouch.o \ - ${LIBBFS} \ - ${UNIT_OBJS} diff --git a/config/use/libacl.c b/config/use/libacl.c deleted file mode 100644 index de1fe50..0000000 --- a/config/use/libacl.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - acl_free(0); - return 0; -} diff --git a/config/use/libcap.c b/config/use/libcap.c deleted file mode 100644 index 58e832c..0000000 --- a/config/use/libcap.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - cap_free(0); - return 0; -} diff --git a/config/use/libselinux.c b/config/use/libselinux.c deleted file mode 100644 index bca409d..0000000 --- a/config/use/libselinux.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - freecon(0); - return 0; -} diff --git a/config/use/liburing.c b/config/use/liburing.c deleted file mode 100644 index bea499a..0000000 --- a/config/use/liburing.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - io_uring_free_probe(0); - return 0; -} diff --git a/config/use/oniguruma.c b/config/use/oniguruma.c deleted file mode 100644 index cb17596..0000000 --- a/config/use/oniguruma.c +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -#include - -int main(void) { - onig_free(0); - return 0; -} diff --git a/configure b/configure new file mode 100755 index 0000000..6920212 --- /dev/null +++ b/configure @@ -0,0 +1,98 @@ +#!/bin/sh + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# bfs build configuration script + +set -eu + +help() { + cat <] [CC=...] [CFLAGS=...] [...] + +Compiler configuration: + + CC + The C compiler to use + CPPFLAGS + C preprocessor flags + CFLAGS + C compiler flags + LDFLAGS + Linker flags + LDLIBS + Dynamic libraries to link + + EXTRA_CPPFLAGS + EXTRA_CFLAGS + EXTRA_LDFLAGS + EXTRA_LDLIBS + Adds to the default flags, instead of replacing them + +Build profiles: + + RELEASE=y + Enable optimizations, disable assertions + ASAN=y + LSAN=y + MSAN=y + TSAN=y + UBSAN=y + Enable sanitizers + GCOV=y + Enable code coverage instrumentation + +External dependencies: + + PKG_CONFIG + The pkg-config binary to use + + USE_LIBACL=[y|n] + USE_LIBCAP=[y|n] + USE_LIBSELINUX=[y|n] + USE_LIBURIG=[y|n] + USE_ONIGURUMA=[y|n] + Enable or disable external dependencies + +Packaging configuration: + + PREFIX + Set the installation prefix (default: /usr) + MANDIR + Set the man page directory (default: \$PREFIX/share/man) +EOF +} + +for arg; do + case "$arg" in + --help) + help + exit 0 + ;; + -*|*=*) + continue # make flag (-j2) or variable (CC=clang) + ;; + *) + printf 'error: Unrecognized option "%s"\n\n' "$arg" >&2 + help >&2 + exit 1 + ;; + esac +done + +# Get the relative path to the source tree based on how the script was run +DIR=$(dirname -- "$0") + +# Set up symbolic links for out-of-tree builds +for f in Makefile build completions docs src tests; do + test -e "$f" || ln -s "$DIR/$f" "$f" +done + +# Infer -jN unless MAKEFLAGS is set +j= +if ! [ "${MAKEFLAGS+y}" ]; then + j="-j$({ nproc || sysctl -n hw.ncpu || getconf _NPROCESSORS_ONLN || echo 1; } 2>/dev/null)" +fi + +${MAKE:-make} $j -rsf build/config.mk "$@" diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 4ed139c..db5d721 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -4,10 +4,9 @@ Building `bfs` Compiling --------- -`bfs` uses [GNU Make](https://www.gnu.org/software/make/) as its build system. A simple invocation of - $ make config + $ ./configure $ make should build `bfs` successfully. @@ -18,7 +17,6 @@ For example, to use all your cores, run `make -j$(nproc)`. | Command | Description | |------------------|---------------------------------------------------------------| -| `make config` | Configures the build system | | `make` | Builds just the `bfs` binary | | `make all` | Builds everything, including the tests (but doesn't run them) | | `make check` | Builds everything, and runs the tests | @@ -33,13 +31,13 @@ The configuration system provides a few shorthand flags for handy configurations | Command | Description | |-------------------------|-------------------------------------------------------------| -| `make config RELEASE=y` | Build `bfs` with optimizations, LTO, and without assertions | -| `make config ASAN=y` | Enable [AddressSanitizer] | -| `make config LSAN=y` | Enable [LeakSanitizer] | -| `make config MSAN=y` | Enable [MemorySanitizer] | -| `make config TSAN=y` | Enable [ThreadSanitizer] | -| `make config UBSAN=y` | Enable [UndefinedBehaviorSanitizer] | -| `make config GCOV=y` | Enable [code coverage] | +| `./configure RELEASE=y` | Build `bfs` with optimizations, LTO, and without assertions | +| `./configure ASAN=y` | Enable [AddressSanitizer] | +| `./configure LSAN=y` | Enable [LeakSanitizer] | +| `./configure MSAN=y` | Enable [MemorySanitizer] | +| `./configure TSAN=y` | Enable [ThreadSanitizer] | +| `./configure UBSAN=y` | Enable [UndefinedBehaviorSanitizer] | +| `./configure GCOV=y` | Enable [code coverage] | [AddressSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizer [LeakSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#stand-alone-mode @@ -48,21 +46,20 @@ The configuration system provides a few shorthand flags for handy configurations [UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html [code coverage]: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html -You can combine multiple profiles (e.g. `make config ASAN=y UBSAN=y`), but not all of them will work together. +You can combine multiple profiles (e.g. `./configure ASAN=y UBSAN=y`), but not all of them will work together. ### Flags -Other flags can be specified on the `make config` command line or in the environment. +Other flags can be specified on the `./configure` command line or in the environment. Here are some of the common ones; check the [`Makefile`](/Makefile) for more. | Flag | Description | |-------------------------------------|----------------------------------------------------| -| `CC` | The C compiler to use, e.g. `make config CC=clang` | +| `CC` | The C compiler to use, e.g. `./configure CC=clang` | | `CFLAGS`
`EXTRA_CFLAGS` | Override/add to the default compiler flags | | `LDFLAGS`
`EXTRA_LDFLAGS` | Override/add to the linker flags | | `USE_LIBACL`
`USE_LIBCAP`
... | Enable/disable [optional dependencies] | | `TEST_FLAGS` | `tests.sh` flags for `make check` | -| `BUILDDIR` | The build output directory (default: `.`) | | `DESTDIR` | The root directory for `make install` | | `PREFIX` | The installation prefix (default: `/usr`) | | `MANDIR` | The man page installation directory | @@ -72,9 +69,9 @@ Here are some of the common ones; check the [`Makefile`](/Makefile) for more. ### Dependencies `bfs` depends on some system libraries for some of its features. -These dependencies are optional, and can be turned off in `make config` if necessary by setting the appropriate variable to `n` (e.g. `make config USE_ONIGURUMA=n`). +These dependencies are optional, and can be turned off in `./configure` if necessary by setting the appropriate variable to `n` (e.g. `./configure USE_ONIGURUMA=n`). -| Dependency | Platforms | `make config` flag | +| Dependency | Platforms | `./configure` flag | |--------------|------------|--------------------| | [libacl] | Linux only | `USE_LIBACL` | | [libcap] | Linux only | `USE_LIBCAP` | @@ -90,22 +87,28 @@ These dependencies are optional, and can be turned off in `make config` if neces ### Dependency tracking -The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in the [`Makefile`](/Makefile)). +The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in [`build/deps.mk`](/build/deps.mk)). So if you edit a header file, `make` will rebuild the necessary object files ensuring they don't go out of sync. We also add a dependency on the current configuration, so you can change configurations and rebuild without having to `make clean`. - -We go one step further than most build systems by tracking the flags that were used for the previous compilation. -That means you can change configurations without having to `make clean`. For example, - $ make config + $ ./configure $ make - $ make config RELEASE=y + $ ./configure RELEASE=y $ make will build the project in debug mode and then rebuild it in release mode. +### Out-of-tree builds + +You can set up an out-of-tree build by running the `configure` script from another directory, for example: + + $ mkdir out + $ cd out + $ ../configure + $ make + Testing ------- diff --git a/tests/util.sh b/tests/util.sh index 7dba9fb..3969db5 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -12,12 +12,9 @@ _realpath() ( ) # Globals -TESTS=$(_realpath "$TESTS") -if [ "${BUILDDIR-}" ]; then - BIN=$(_realpath "$BUILDDIR/bin") -else - BIN=$(_realpath "$TESTS/../bin") -fi +ROOT=$(_realpath "$(dirname -- "$TESTS")") +TESTS="$ROOT/tests" +BIN="$ROOT/bin" MKSOCK="$BIN/tests/mksock" XTOUCH="$BIN/tests/xtouch" UNAME=$(uname) diff --git a/tests/xspawn.c b/tests/xspawn.c index 7362aa5..785ea48 100644 --- a/tests/xspawn.c +++ b/tests/xspawn.c @@ -64,27 +64,20 @@ static bool check_use_path(bool use_posix) { spawn.flags &= ~BFS_SPAWN_USE_POSIX; } - const char *builddir = getenv("BUILDDIR"); - dchar *bin = dstrprintf("%s/bin", builddir ? builddir : "."); - ret &= bfs_pcheck(bin, "dstrprintf()"); - if (!ret) { - goto destroy; - } - - ret &= bfs_pcheck(bfs_spawn_addopen(&spawn, 10, bin, O_RDONLY | O_DIRECTORY, 0) == 0); + ret &= bfs_pcheck(bfs_spawn_addopen(&spawn, 10, "bin", O_RDONLY | O_DIRECTORY, 0) == 0); ret &= bfs_pcheck(bfs_spawn_adddup2(&spawn, 10, 11) == 0); ret &= bfs_pcheck(bfs_spawn_addclose(&spawn, 10) == 0); ret &= bfs_pcheck(bfs_spawn_addfchdir(&spawn, 11) == 0); ret &= bfs_pcheck(bfs_spawn_addclose(&spawn, 11) == 0); if (!ret) { - goto bin; + goto destroy; } // Check that $PATH is resolved in the parent's environment char **envp; ret &= bfs_pcheck(envp = envdup()); if (!ret) { - goto bin; + goto destroy; } // Check that $PATH is resolved after the file actions @@ -138,8 +131,6 @@ env: free(*var); } free(envp); -bin: - dstrfree(bin); destroy: ret &= bfs_pcheck(bfs_spawn_destroy(&spawn) == 0); out: -- cgit v1.2.3