C Cheatsheet

build.sh

#!/usr/bin/env bash

set -Eeuo pipefail

INFILE=$(basename "$1")
INDIR=$(dirname "$1")
FILENAME=${INFILE%%.*}
OBJECTFILE="$FILENAME.o"
BUILDNAME="latest_$FILENAME"

mkdir -p ../build
pushd ../build > /dev/null || exit

# echo "1 $1"
# echo "INDIR: $INDIR"
# echo "INFILE: $INFILE"
# echo "FILENAME: $FILENAME"
# echo "BUILDNAME: $BUILDNAME"

rm -f -- "$BUILDNAME"

if [[ ( "$INFILE" == *.asm ) || ( "$INFILE" == *.s ) ]]; then
    nasm -f elf -g -F stabs -o "$OBJECTFILE" "$1"
    ld -m elf_i386 -o "$BUILDNAME" "$OBJECTFILE"

    # nasm -f elf64 -o "$OBJECTFILE" "$1"
    # nasm -f elf -o "$OBJECTFILE" "$1"
    # ld -m elf_i386 -o "$BUILDNAME" "$OBJECTFILE"
    # gcc -m32 -o "$BUILDNAME" "$OBJECTFILE"
elif [[ "$INFILE" == *.c ]]; then
    gcc -g "$1" -o "$BUILDNAME" -ldl

    # gcc -Wall \
        #     -Wextra \
        #     -Wpedantic \
        #     -Wformat=2 \
        #     -Wno-unused-parameter \
        #     -Wshadow \
        #     -Wwrite-strings \
        #     -Wstrict-prototypes \
        #     -Wmissing-prototypes \
        #     -Wold-style-definition \
        #     -Wredundant-decls \
        #     -Wnested-externs \
        #     -Wmissing-include-dirs \
        #     -g "$1" \
        #     -o "$BUILDNAME"

    # gcc \
        #     -Wall \
        #     -Wextra \
        #     -std=c89 \
        #     -pedantic \
        #     -Wmissing-prototypes \
        #     -Wstrict-prototypes \
        #     -Wold-style-definition \
        #     -g "$1" \
        #     -o "$BUILDNAME"

elif [[ "$INFILE" == *.cc ]] || [[ "$INFILE" == *.cpp ]]; then
    g++ "$1" -o "$BUILDNAME" -g "$(sdl2-config --cflags --libs)"
else
    echo "Invalid file type: \"$INFILE\""
    exit 1
fi

# Toggle debug mode with:
#
#    export DEV_DEBUG=1
#
# Run with GDB when /* GDB */ comment exists in source.  Run with
# Valgrind otherwise.
if [ -z "$DEV_DEBUG" ]; then
    ./"$BUILDNAME"
else
    # Needs trailing '|| true' because 'set -e' causes the script to
    # exit immediately if grep finds nothing (fails)
    BREAKPOINT=$(grep -nrIH '/\* GDB \*/' "$INDIR") || true

    if [ -n "$BREAKPOINT" ]; then
        # Look for comment /* GDB */ in source.  Construct GDB init which sets
        # breakpoints at these locations.  First, use a "here document" to
        # create the basic GDB init.  Next, find where the debug comments are
        # and insert them into the GDB init.  Finally, run GDB.
        #
        # Finding the debug comments and inserting them is done by:
        #
        #   1. grep: find files and line numbers matching debug comment
        #
        #       ./path/to/my-file1-with-debug-comment.c:18:  /* GDB */
        #
        #   2. sed: remove the debug comment from grep output
        #
        #       ./path/to/my-file1-with-debug-comment.c:18
        #
        #   3. awk: write a 'b' in front of each filename to indicate a breakpoint
        #
        #       b ./path/to/my-file1-with-debug-comment.c:18
        #
        #   4. grep: remove the leading period from the awk results
        #
        #       b /path/to/my-file1-with-debug-comment.c:18
        #
        # Example 'run_debug.gdbinit':
        #
        #     # Tell GDB where to look for separate debugging files
        #     set debug-file-directory ~/.guix-profile/lib/debug
        #
        #     # Authorize extensions found in the store, such as the
        #     # pretty-printers of libstdc++
        #     set auto-load safe-path /gnu/store/*/lib
        #
        #     # Run GDB with the following breakpoints
        #     file ./latest_build
        #     b /path/to/my-file1-with-debug-comment.c:18
        #     b /path/to/my-file2-with-debug-comment.c:7
        #
        # See: https://stackoverflow.com/a/45450083
        cat > run_debug.gdbinit <<EOF
# Tell GDB where to look for separate debugging files
set debug-file-directory ~/.guix-profile/lib/debug

# Authorize extensions found in the store, such as the
# pretty-printers of libstdc++
set auto-load safe-path /gnu/store/*/lib

# Run GDB with the following breakpoints
file ./$BUILDNAME
EOF
        # -n, --line-number
        # -r, --recursive
        # -I, --binary-files=without-match; if null input, assume no match
        # -H, --with-filename; print file name for each match.
        # BREAKPOINT is grep -nrIH "/\* GDB \*/" $INDIR
        echo "$BREAKPOINT" |
            sed "s/\(^[^:]\+:[^:]\+\):.*$/\1/g" |
            awk '{print "b" " " $AWK_DUMMY_VARIBLE }'|
            grep -v "$(echo "$0" | sed "s/.*\\///g")" >> run_debug.gdbinit

        # -ex, --eval-command; call 'run' as initial command
        gdb --quiet --init-command ./run_debug.gdbinit --eval-command=run
    else
        # Check for memory leaks when not actively debugging
        valgrind --quiet --exit-on-first-error=yes --error-exitcode=1 --leak-check=yes ./"$BUILDNAME"
    fi
fi

popd > /dev/null
2024-03-31

Powered by peut-publier

©2024 Excalamus.com