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