cbuild.sh/cbuild.sh

190 lines
4.9 KiB
Bash
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Written by Noah Swerhun
# https://noahsw.xyz
# Development: https://git.noahsw.xyz/cbuild.sh/log.html
# --- USER CONFIG ---
CC="gcc"
CFLAGS="-Wall -Wpedantic"
LDFLAGS=""
LDLIBS=""
TARGET="a.out"
SRCDIR="src"
OBJDIR="obj"
MAKEFILE=".makefile"
# -------------------
PROG_COMMAND="./cbuild.sh __progress__"
SRC="$(find ${SRCDIR} -name '*\.c')"
OBJ="$(find ${SRCDIR} -name '*\.c' |
sed "s/${SRCDIR}\//${OBJDIR}\//" |
sed "s/\.c$/.o/" |
tr '\n' ' ')"
srcnum="$(find ${SRCDIR} -name '*\.c' -exec printf %c {} + | wc -c)"
usage() {
cat <<EOF
cbuild.sh: A simple, customizable, automated, and portable build script for C
projects. This script works by automatically detecting .c source files in
SRCDIR, generating a makefile, compiling them into objects in OBJDIR, and
finally linking them to TARGET.
Customization:
Open cbuild.sh in your editor and navigate to the USER CONFIG section (at
the top of the file).
CC the compiler to use (default: gcc)
CFLAGS compilation flags (default: -Wall -Wpedantic)
LDFLAGS linker flags (default: none)
LDLIBS linker libraries (default: none)
TARGET final target to link (default: a.out)
SRCDIR the directory where the script will search for .c source files
(default: src)
OBJDIR the directory where compiled objects will be placed. (default: obj)
MAKEFILE the filename of the generated makefile (default: .makefile)
Usage:
./cbuild.sh [COMMAND]
COMMAND:
build generate the makefile, compile objects and link target.
clean remove makefile, objects, and target.
buildcn clean, and then build.
generate ONLY generate the makefile.
run [ARGS] build, then execute TARGET with arguments ARGS.
dryrun print all commands that will be executed during the build process
to stdout.
EOF
}
export_vars() {
export CC
export CFLAGS
export LDFLAGS
export LDLIBS
export TARGET
export OBJ
export PROG_COMMAND
}
info() {
printf "[*] %s\n" "$@"
}
err() {
printf "[!] %s\n" "$@"
}
gen_makefile() {
info "Generating makefile..."
[ -f "${MAKEFILE}" ] && chmod +w "${MAKEFILE}"
cat > "${MAKEFILE}" <<'EOF'
##########################
# GENERATED BY cbuild.sh #
# DO NOT MODIFY BY HAND #
##########################
.POSIX:
$(TARGET): $(OBJ)
@$(PROG_COMMAND) link $(TARGET)
@$(CC) $(LDFLAGS) -o $(TARGET) $(OBJ) $(LDLIBS)
EOF
i=1
echo "${SRC}" | while read srcname; do
objname="$(echo "${srcname}" |
sed "s/${SRCDIR}\//${OBJDIR}\//" |
sed "s/\.c$/.o/")"
includes="$(grep '#include ".*"' ${srcname} |
awk -F\" '{ print $2 }')"
printf "%s: %s " "${objname}" "${srcname}" >> "${MAKEFILE}"
for line in $includes; do
printf "%s " "${file%$(basename ${file})}${line}" >> "${MAKEFILE}"
done
printf "\n" >> "${MAKEFILE}"
printf "\t@%s object %s\n" \
'$(PROG_COMMAND)' "${objname}" >> "${MAKEFILE}"
printf "\t@%s %s -o %s -c %s\n" '$(CC)' '$(CFLAGS)' \
"${objname}" "${srcname}" >> "${MAKEFILE}"
i=$((${i}+1))
done
chmod -w "${MAKEFILE}"
}
build() {
gen_makefile
[ ! -d "${OBJDIR}" ] && mkdir "${OBJDIR}"
export_vars
make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}" > .cbuild_prog.tmp
if [ "$(cat .cbuild_prog.tmp)" = 0 ]; then
info "Target ${TARGET} up to date"
rm .cbuild_prog.tmp
return 0;
fi
info "Beginning build..."
make -f "${MAKEFILE}" -e "${TARGET}"
ret=$?
[ "${ret}" = 0 ] &&
info "Build SUCCESSFUL" ||
err "Build FAILURE"
rm .cbuild_prog.tmp
return "${ret}"
}
clean() {
[ -d "${OBJDIR}" ] &&
rm -rf "${OBJDIR}"
[ -f "${MAKEFILE}" ] &&
chmod +w "${MAKEFILE}"
[ -f "${TARGET}" ] && [ -f "${MAKEFILE}" ] &&
rm "${TARGET}" "${MAKEFILE}"
}
run() {
build || exit $?
args="$@"
info "Running ./${TARGET} ${args}"
"./${TARGET}" $@ ||
err "Run FAILURE ./${TARGET} returned $?"
}
dry_run() {
gen_makefile
export_vars
make -f "${MAKEFILE}" -e "${TARGET}" -n
}
__progress__() {
ntargets=$(cat .cbuild_prog.tmp)
export_vars
rtargets="$(make -f "${MAKEFILE}" -e "${TARGET}" -n | grep -c "^${CC}")"
targetno=$((${ntargets} - ${rtargets} + 1))
if [ "${1}" = "object" ]; then
printf '[%3d/%d] ' "${targetno}" "${ntargets}"
printf 'Building '
elif [ "${1}" = "link" ]; then
printf '[%3d/%d] ' "${targetno}" "${ntargets}"
printf 'Linking '
fi
echo "${2}"
}
case $1 in
build) build;;
clean) clean;;
buildcn) clean ; build;;
generate) gen_makefile && info "Done";;
run) shift 1 && run $@;;
dryrun) dry_run;;
__progress__) __progress__ "${2}" "${3}";;
*) usage;;
esac