added 'new' functionality and reworked colors

This commit is contained in:
Noah Swerhun 2021-12-30 15:28:23 -06:00
parent a24e95fbb6
commit 1e31497a15

136
cbuild.sh
View file

@ -2,10 +2,10 @@
# Written by Noah Swerhun # Written by Noah Swerhun
# https://noahsw.xyz # https://noahsw.xyz
# Development: https://git.noahsw.xyz/cbuild.sh/log.html # Development: https://git.noahsw.xyz/cbuild.sh/log.html
# --- USER CONFIG --- # --- USER CONFIG ---
CC="gcc" CC="gcc"
CFLAGS="-Wall -Wpedantic" CFLAGS="-Wall -Wpedantic"
LDFLAGS="" LDFLAGS=""
LDLIBS="" LDLIBS=""
@ -13,19 +13,29 @@ TARGET="a.out"
SRCDIR="src" SRCDIR="src"
OBJDIR="obj" OBJDIR="obj"
MAKEFILE=".makefile" MAKEFILE=".makefile"
HEADER_DIR="include"
# ------------------- # -------------------
PROG_COMMAND="./cbuild.sh __progress__" PROG_COMMAND="./cbuild.sh __progress__"
SRC="$(find ${SRCDIR} -name '*\.c')" SRC="$(find ${SRCDIR} -name '*\.c' 2> /dev/null)"
OBJ="$(find ${SRCDIR} -name '*\.c' | OBJ="$(find ${SRCDIR} -name '*\.c' 2> /dev/null |
sed "s/${SRCDIR}\//${OBJDIR}\//" | sed "s/${SRCDIR}\//${OBJDIR}\//" |
sed "s/\.c$/.o/" | sed "s/\.c$/.o/" |
tr '\n' ' ')" tr '\n' ' ')"
srcnum="$(find ${SRCDIR} -name '*\.c' -exec printf %c {} + | wc -c)" srcnum="$(find ${SRCDIR} -name '*\.c' -exec printf %c {} + 2> /dev/null | wc -c)"
clear_formatting="\033[0m"
bold="\033[1m"
info_color="\033[34m" # default: "\033[34m" - blue
err_color="\033[31m" # default: "\033[31m" - red
build_progress_color="\033[35m" # default: "\033[35m" - magenta
build_info_color="\033[32m" # default: "\033[32m" - green
link_info_color="\033[36m" # default: "\033[36m" - cyan
usage() { usage() {
cat <<EOF less <<EOF
cbuild.sh: A simple, customizable, automated, and portable build script for C cbuild.sh: A simple, customizable, automated, and portable build script for C
projects. This script works by automatically detecting .c source files in projects. This script works by automatically detecting .c source files in
SRCDIR, generating a makefile, compiling them into objects in OBJDIR, and SRCDIR, generating a makefile, compiling them into objects in OBJDIR, and
@ -44,18 +54,34 @@ Customization:
(default: src) (default: src)
OBJDIR the directory where compiled objects will be placed. (default: obj) OBJDIR the directory where compiled objects will be placed. (default: obj)
MAKEFILE the filename of the generated makefile (default: .makefile) MAKEFILE the filename of the generated makefile (default: .makefile)
HEADER_DIR the directory in which header files will be placed by the 'new'
command. Note that this is relative to SRCDIR. Setting this to
'.' means headers will be placed in the same directory as
source files. Setting this to 'include' means headers will be
placed in SRCDIR/include. (defualt: include)
Usage: Usage:
./cbuild.sh [COMMAND] ./cbuild.sh [COMMAND]
COMMAND: COMMAND:
--help display this help message
build generate the makefile, compile objects and link target. build generate the makefile, compile objects and link target.
clean remove makefile, objects, and target. clean remove makefile, objects, and target.
buildcn clean, and then build. buildcn clean, and then build.
generate ONLY generate the makefile. generate ONLY generate the makefile.
run [ARGS] build, then execute TARGET with arguments ARGS. run [ARGS] build, then execute TARGET with arguments ARGS.
init equivalent to 'new module main' (see below).
dryrun print all commands that will be executed during the build process dryrun print all commands that will be executed during the build process
to stdout. to stdout.
new header [NAME] [...]
generate a header file with name NAME in HEADER_DIR. Multiple
NAMEs may be provided. Including '.h' in NAME is optional.
new module [NAME] [...]
generate a new source file NAME.c in SRCDIR and a new header
NAME.h in HEADER_DIR. Multiple NAMEs may be provided.
EOF EOF
} }
@ -70,11 +96,15 @@ export_vars() {
} }
info() { info() {
printf "[*] %s\n" "$@" printf "${info_color}${bold}[*]${clear_formatting}\
${info_color} %s${clear_formatting} %s${info_color} %s${clear_formatting}\n" \
"${1}" "${2}" "${3}"
} }
err() { err() {
printf "[!] %s\n" "$@" printf "${err_color}${bold}[!]${clear_formatting}\
${err_color} %s${clear_formatting} %s${err_color} %s${clear_formatting}\n" \
"${1}" "${2}" "${3}"
} }
gen_makefile() { gen_makefile() {
@ -124,7 +154,7 @@ build() {
export_vars export_vars
make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}" > .cbuild_prog.tmp make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}" > .cbuild_prog.tmp
if [ "$(cat .cbuild_prog.tmp)" = 0 ]; then if [ "$(cat .cbuild_prog.tmp)" = 0 ]; then
info "Target ${TARGET} up to date" info "Target" "${TARGET}" "up to date"
rm .cbuild_prog.tmp rm .cbuild_prog.tmp
return 0; return 0;
fi fi
@ -150,9 +180,9 @@ clean() {
run() { run() {
build || exit $? build || exit $?
args="$@" args="$@"
info "Running ./${TARGET} ${args}" info "Running" "./${TARGET} ${args}"
"./${TARGET}" $@ || "./${TARGET}" $@ ||
err "Run FAILURE ./${TARGET} returned $?" err "Run FAILURE" "./${TARGET}" "returned $?"
} }
dry_run() { dry_run() {
@ -161,17 +191,86 @@ dry_run() {
make -f "${MAKEFILE}" -e "${TARGET}" -n make -f "${MAKEFILE}" -e "${TARGET}" -n
} }
new() {
case $1 in
header)
shift 1
for arg in $@; do
if [ "${arg}" != "__MODULE__" ]; then
path="${SRCDIR}/${HEADER_DIR}/${arg%.h}.h"
clean_path="${path//.\//}"
macro="$(basename ${clean_path} .h | tr '[a-z]' '[A-Z]')"
[ ! -d "$(dirname ${clean_path})" ] &&
mkdir -p "$(dirname ${clean_path})"
if [ ! -f "${clean_path}" ]; then
cat > "${clean_path}" <<EOF
#ifndef ${macro}_H
#define ${macro}_H
#endif
EOF
else
[ "${2}" != "__MODULE__" ] &&
err "Header" "${clean_path}" "already exists"
fi
[ "${2}" != "__MODULE__" ] &&
info "Created header" "${clean_path}"
fi
done
;;
module)
shift 1
for arg in $@; do
./cbuild.sh new header "${arg}" '__MODULE__'
path="${SRCDIR}/${arg}.c"
if [ "${HEADER_DIR}" = "." ]; then
include="./$(basename ${arg}).h"
else
include="$(dirname ${path#${SRCDIR}/} |
sed -e 's/\/[A-z]*/\/../g' \
-e 's/[A-z]*\//..\//' \
-e 's/^[A-z]*$/../')/${HEADER_DIR}/${arg}.h"
fi
[ ! -d "$(dirname ${path})" ] &&
mkdir -p "$(dirname ${path})"
if [ ! -f "${path}" ]; then
cat > "${path}" <<EOF
#include "${include}"
EOF
[ "${arg}" != "main" ] && echo >> "${path}" ||
cat >> "${path}" <<EOF
int main(int argc, char **argv) {
return 0;
}
EOF
else
err "Module" "${path%.c}" "already exists"
return 1
fi
info "Created module" "${path%.c}"
done
;;
esac
}
__progress__() { __progress__() {
ntargets=$(cat .cbuild_prog.tmp) ntargets=$(cat .cbuild_prog.tmp)
export_vars export_vars
rtargets="$(make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}")" rtargets="$(make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}")"
targetno=$((${ntargets} - ${rtargets} + 1)) targetno=$((${ntargets} - ${rtargets} + 1))
if [ "${1}" = "object" ]; then if [ "${1}" = "object" ]; then
printf '[%3d/%d] ' "${targetno}" "${ntargets}" printf "${build_progress_color}${bold}[%3d/%d]${clear_formatting} " \
printf 'Building ' "${targetno}" "${ntargets}"
printf "${build_info_color}Building${clear_formatting} "
elif [ "${1}" = "link" ]; then elif [ "${1}" = "link" ]; then
printf '[%3d/%d] ' "${targetno}" "${ntargets}" printf "${link_info_color}${bold}[%3d/%d]${clear_formatting} " "${targetno}" "${ntargets}"
printf 'Linking ' printf "${link_info_color}${bold}Linking${clear_formatting} "
fi fi
echo "${2}" echo "${2}"
@ -184,6 +283,9 @@ case $1 in
generate) gen_makefile && info "Done";; generate) gen_makefile && info "Done";;
run) shift 1 && run $@;; run) shift 1 && run $@;;
dryrun) dry_run;; dryrun) dry_run;;
new) shift 1 && new $@;;
init) new module main;;
-h|--help|help) usage;;
__progress__) __progress__ "${2}" "${3}";; __progress__) __progress__ "${2}" "${3}";;
*) usage;; *) echo "Invalid command. Try --help";;
esac esac