#!/bin/sh ##################### # # name: gcci (gcci.sh) # vers: 0.2a # date: 012507 # first: 012507 # auth: "Keith Beckman" # site: http://alphahelical.com/code/scripts/gcci # desc: gcci is a C language script interpreter front-end for gcc. It allows C # programs to be shebanged and run like other shell scripts. gcci caches # executable code, only recompiling scripts when they have been changed # since a previous invocation. Files are cached temporarily by default, # identified by based on file digest (to allow users of editors which # create separate tempfiles for separate script invocations to avail # themselves of caching. Files interpreted with the -p flag set are # identified by path hash and mtime, allowing faster cache lookup and # execution. Arguments prior to the filename not identified as gcci # arguments are passed to gcc as CFLAGS (and LDFLAGS in the case of '-l*' # options). All arguments following the filename are passed to the # executable as its parameters (as in other script interpreters). # # todo: stdin as a script source would be nice # automated cache cleanup, though not a big problem, given -p/-t # see http://yost.com/computers/compileAndGo/index.html # # bugs: getopts is not supported, so all flags must be specified as # separate tokens # # license: gcci is copyright 2006 Keith Beckman and is licensed under the # GNU General Public License v2 (http://gnu.org/licenses/gpl.txt) # ##################### ####configuration#### datadir="${HOME}/etc/gcci" tempdir="${HOME}/tmp/gcci" verbosity=1 gcc_cmd='gcc -O0' verstring='gcci v0.1a 012507 Keith Beckman' ##end configuration## print_usage () { cat < gcci -V test.ci EOS } ###Process Options### while [ "$1" != "" ]; do case "$1" in '-g'|'--purge') purge=1 ;; '-p'|'--permanent') rundir="$datadir" ;; '-t'|'--temporary') rundir="$tempdir" ;; '-q'|'--quiet') verbosity=0 ;; '-V'|'--verbose') verbosity=2 ;; '-h'|'--help'|'-u'|'--usage') print_usage exit ;; '-v'|'--version') echo "$verstring" exit ;; *) if [ -f "$1" ]; then infile="$1" shift while [ "$1" != "" ]; do execparms="${execparms} ${1}" shift done else if [[ $(grep -q '^-l' <<< "$1") -eq 0 ]]; then LDFLAGS="${LDFLAGS} ${1}" else CFLAGS="${CFLAGS} ${1}" fi fi ;; esac shift done ###Set/Check Defaults### if [ "$infile" == "" ]; then echo "No source file specified." >&2 exit -1 fi if [ "$rundir" == "" ]; then rundir="$tempdir" fi if [ ! -d "$rundir" ]; then mkdir -p "$rundir" fi if [ ! -d "$rundir" ]; then echo "gcci: Unable to create cache directory '${rundir}'." >&2 fi ###Cache Lookup### if [ "$rundir" == "$tempdir" ]; then # for temporary caches, hash file hash=$(md5 < "$infile"); else # for permanent caches, hash path hash=$(md5 <<< "$infile"); fi srcfile="${rundir}/${hash}.c" execfile="${rundir}/${hash}" if [ "$rundir" == "$tempdir" ]; then # for temporary caches, rebuild on file hash if [ ! -f "$execfile" ]; then rebuild=1 fi else # for permanent caches, rebuild on mtime if [ "$execfile" -ot "$infile" ]; then rebuild=1 fi fi function jit_compile () { tail -n +2 "$infile" > "$srcfile" if [[ $verbosity -lt 1 ]]; then $gcc_cmd $CFLAGS -o "$execfile" "$srcfile" $LDFLAGS 2> /dev/null else $gcc_cmd $CFLAGS -o "$execfile" "$srcfile" $LDFLAGS fi gccexit=$? if [[ $gccexit -ne 0 ]]; then echo "gcci: gcc failed with error code $gccexit" >&2 exit $gccexit; fi if [[ $purge -eq 1 ]]; then rm "$srcfile" fi } if [[ $rebuild -eq 0 ]]; then if [[ $verbosity -gt 1 ]]; then echo "gcci: Using cached executable for '${infile}'." >&2 fi else if [[ $verbosity -gt 1 ]]; then echo "gcci: Rebuilding executable for '${infile}'." >&2 fi jit_compile fi $execfile $execparms