Using C/C++ as a scripting language (Part 1)
Those familiar with web development will probably have used some form of hot module reloading. This dramatically reduces the development to test iteration time. It is also very common to run a Javascript file via node path/to/file.js
or similar. Since I've been preferring C/C++ lately, how can these conveniences be ported to a lower-level language?
Typically when starting a C/C++ project there is this annoying step of setting up a build system. Makefiles, CMake, Ninja, Gyp, Gn, Bake, Meson, etc, etc... Many of these do not play well together and encourage you to buy fully into them to manage dependencies and do a bunch of things that are not even remotely needed to solve the problem at hand.
So what is the problem at hand? Lowering the friction between writing a C file, building, and launching it. I want it to feel effortless to create a new c project.
Goals:
- no noticeable compile step (e.g.,
c path/to/file.c
immediately executes) - hot reload
- for trivial scripts, do not require a compiler / libc
First round: Bash scripts
~/bin/c.sh
#!/usr/bin/bash
CPATH=$(dirname "${BASH_SOURCE[0]}")
SRC=$1
DST=$(mktemp)
EXT="${SRC##*.}"
# Allow the source file to include some C flags that is requires
FOUND_CFLAGS=$(
grep "#pragma CFLAGS=" $SRC \
| sed 's/#pragma CFLAGS=//' \
| paste -s -d " " -
)
CFLAGS="$CFLAGS $FOUND_CFLAGS"
CC=clang++
if [ ${SRC: -2} == ".c" ]; then
CC=clang
fi
$CC $SRC -O3 -g $CFLAGS -o $DST &&
chmod +x $DST &&
$DST ${@:2} &&
rm $DST
in ~/.bashrc
# compile and run a .c/cpp file
c() {
~/bin/c.sh $@
}
# recompile + relaunch a .c/cpp file
cwatch() {
rp=$(realpath $1)
rd=$(dirname $rp)
# Note: you might want to add --poll 100ms if you are working under WSL
watchexec --clear=reset --restart --poll 100ms -w $rd "bash ~/bin/c.sh $@"
}
Usage:
c path/to/file.{c,cpp}
cwatch path/to/file.{c,cpp}
Issues:
- does not maintain state across reloads
- no persistent state (e.g., if we created a window it would flash + muck with focus)
- requires *nix and an installed compiler
#include
ed files are not scanned for#pragma CFLAGS