#!/bin/bash REP_CC=cc REP_CXX=c++ REP_INCLUDE='-I$(HOME)/projects/include -I/usr/include' REP_LIBRARIES= REP_TARGET=target SMAKE_DIR=~/dev/bash/smake/etc/smake HELP_FILE=$SMAKE_DIR/help.smk ENV_FILE=$SMAKE_DIR/env.smk BUILD_FILE=$SMAKE_DIR/build.smk RULES_FILE=$SMAKE_DIR/rules.smk # Debug DEBUG=1 # Parameters processing TEMP=`getopt -o hc:x:i:l:t: --long help,cc:,cxx:,include:,libraries:,target: -- "$@"` eval set -- "$TEMP" while true ; do case "$1" in -h|--help) echo "Usage: smake.sh [key]... [goal]..." ; echo "Keys:" echo -e "-h, --help\t\t\tShow this help and exit." echo -e "-c [CC], --cc [CC]\t\tUse CC as C compiler." echo -e "-x [CXX], --cxx [CXX]\t\tUse CXX as C++ compiler." echo -e "-i [INC], --include [INC]\tSet INC as include path." echo -e "-l [LIB], --libraries [LIB]\tSet LIB as libraries that must be linked with." echo -e "-t [TGT], --target [TGT]\tSet TGT as target name." echo echo -e "This program works on any Linux with GNU Baurne's shell" echo -e "Report bugs to " exit 0 ; ;; -c|--cc) REP_CC=$2 ; echo "CC=$REP_CC" ; shift 2 ;; -x|--cxx) REP_CXX=$2 ; echo "CXX=$REP_CXX" ; shift 2 ;; -i|--include) REP_INCLUDE=$2 ; echo "INCLUDE=$REP_INCLUDE"; shift 2 ;; -l|--libraries) REP_LIBRARIES=$2 ; echo "LIBRARIES=$REP_LIBRARIES"; shift 2 ;; -t|--target) REP_TARGET=$2 ; echo "TARGET=$REP_TARGET"; shift 2 ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done # ======= Help ======= cat $HELP_FILE > Makefile echo >> Makefile # ======= Test for target ======= [ ! -f $REP_TARGET.c ] && echo "$REP_TARGET.c doesn't exist" && exit -1 # ======= Environment ======= sed "s~REP_CC~$REP_CC~ ; s~REP_CXX~$REP_CXX~ ; \ s~REP_LIBRARIES~$REP_LIBRARIES~ ; s~REP_TARGET~$REP_TARGET~" $ENV_FILE >> Makefile # INCLUDE0, INCLUDE1, INCLUDE2, ... REP_INCLUDE=`echo $REP_INCLUDE | sed "s~-I~~g"` i=1 for d in $REP_INCLUDE; do echo "INCLUDE$i=$d" >> Makefile i=$((i+1)) done echo -n "INCLUDE=" >> Makefile i=1 for d in $REP_INCLUDE; do if [ $i != 1 ]; then echo -n ' ' >> Makefile fi echo -n '-I$(INCLUDE'$i')' >> Makefile i=$((i+1)) done echo >> Makefile echo >> Makefile # ======= Build ======= cat $BUILD_FILE >> Makefile echo >> Makefile # ======= Rules ======= cat $RULES_FILE >> Makefile REP_INCLUDE=`echo $REP_INCLUDE | sed "s~-I~~g ; s~\\$(HOME)~${HOME}~g"` flist[0]=$REP_TARGET.c fpath[0]=$REP_TARGET.c nfiles=1 nparsed=0 fdeplist[0]=`remove_c_comments.pl $REP_TARGET.c | grep -P '^[\t ]*#include[\t ]*"' | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` files_not_found= while [ $nfiles != $nparsed ]; do for f in ${fdeplist[$nparsed]}; do extension=`basename $f | sed 's~.*\.~~g'` f=`echo $f | sed "s~.$extension$~~"` extensions=$extension [[ "$extension" == h || "$extension" == hpp || "$extension" == "hxx" || "$extension" == "hh" ]] && extensions="$extension c cpp cxx cc" already_in_list=false for ext in $extensions; do for i in `seq 0 $((nfiles))`; do if [ "${flist[$i]}" == "$f.$ext" ]; then already_in_list=true break; fi done [ $already_in_list == true ] && continue F= for d in . $REP_INCLUDE; do if [ -f "$d/$f.$ext" ]; then F="$d/$f.$ext" elif [ -f "$d/`basename $f.$ext`" ]; then F="$d/`basename $f.$ext`" fi if [ "$F" != "" ]; then flist[$nfiles]=$f.$ext fpath[$nfiles]=$F fdeplist[$nfiles]=`remove_c_comments.pl $F | grep -P '^[\t ]*#include[\t ]*"' | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` let nfiles++ break fi done [[ "$F" == "" && "$ext" == "$extension" ]] && files_not_found=`echo "$files_not_found\n$f.$ext" | sort -u` [[ "$F" != "" && "$ext" != "$extension" ]] && break done [ $already_in_list == true ] && continue done let nparsed++ done for i in `seq 0 $((nfiles-1))`; do echo ${flist[$i]}:${fdeplist[$i]} done # ======= Target rules ======= echo 'target_objs = \' >> Makefile carry=false for i in `seq 0 $((nfiles-1))`; do extension=`basename ${flist[$i]} | sed 's~.*\.~~g'` f=`echo ${flist[$i]} | sed "s~.$extension$~~"` [[ "$extension" != c && "$extension" != cpp && "$extension" != cxx && "$extension" != cc ]] && continue [ $carry == true ] && echo ' \' >> Makefile echo -ne "\t`basename $f.o`" >> Makefile carry=true done echo >> Makefile # ======= Warning ======= files_not_found=`echo -e "$files_not_found" | sort -u` if [ "$files_not_found" != "" ]; then echo WARNING: Include files not found: $files_not_found fi ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### exit 0 cat $RULES_FILE >> Makefile REP_INCLUDE=`echo $REP_INCLUDE | sed "s~-I~~g ; s~\\$(HOME)~${HOME}~"` # --- Target deplist --- target_dep_lst=`remove_c_comments.pl $REP_TARGET.c | grep -P '^[\t ]*#include[\t ]*"' | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` files_not_found= while [[ "$target_dep_lst" != "$old_target_dep_lst" ]]; do old_target_dep_lst=$target_dep_lst for f in $target_dep_lst; do F="" for d in . $REP_INCLUDE; do if [ -f "$d/$f" ]; then F="$d/$f" C=`echo $f | sed 's~\.h$~\.c~'` if [ -f "$d/$C" ]; then target_dep_lst="$target_dep_lst $C" fi break fi done if [ "$F" == "" ]; then files_not_found="$files_not_found\n$f" continue fi target_dep_lst="$target_dep_lst "`remove_c_comments.pl $F \ | grep -P '^[\t ]*#include[\t ]*"' \ | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` target_dep_lst=`echo $target_dep_lst | sed 's~ ~\n~g' | sort -u` done done if [ $DEBUG == 1 ]; then echo -e "target_dep_lst:\n`echo $target_dep_lst | sed -e 's~ ~\n~g' | sed 's~\(^..\)~ \1~g'`" fi # --- Target's objects --- target_obj_lst=`echo "$target_dep_lst" | grep -P '.c$' | sed -e 's~.c$~.o~'` if [ $DEBUG == 1 ]; then echo -e "target_obj_lst:\n`echo $target_obj_lst | sed -e 's~ ~\n~g' | sed 's~\(^..\)~ \1~g'`" fi # --- Target's target ;) --- echo "target_objs = \\" >> Makefile for to in $target_obj_lst; do echo -e "\t$to \\" >> Makefile done echo >> Makefile echo '$(TARGET): $(target_objs)' >> Makefile echo -e '\t$(CC) $(LDFLAGS) -o $@ $(target_objs)' >> Makefile echo >> Makefile # --- Object files deplist --- for cf in `echo "$target_dep_lst" | grep -P '.c$'`; do CF="" for d in . $REP_INCLUDE; do if [ -f "$d/$cf" ]; then CF="$d/$cf" break fi done if [ "$CF" == "" ]; then files_not_found="$files_not_found\n$cf" continue fi to=`basename "$cf" | sed 's~.c$~.o~'` target_dep_lst="$CF "`remove_c_comments.pl $CF | grep -P '^[\t ]*#include[\t ]*"' | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` old_target_dep_lst= files_not_found= while [[ "$target_dep_lst" != "$old_target_dep_lst" ]]; do old_target_dep_lst=$target_dep_lst for f in $target_dep_lst; do F="" for d in . $REP_INCLUDE; do if [ -f "$d/$f" ]; then F="$d/$f" break fi done if [ "$F" == "" ]; then files_not_found="$files_not_found\n$f" continue fi target_dep_lst="$target_dep_lst "`remove_c_comments.pl $F \ | grep -P '^[\t ]*#include[\t ]*"' \ | sed 's~[^"]*"\([^"]*\)".*~\1~' | sort -u` target_dep_lst=`echo $target_dep_lst | sed 's~ ~\n~g' | sort -u` done done target_dep_lst= for f in $old_target_dep_lst; do F="" for d in . $REP_INCLUDE; do if [ -f "$d/$f" ]; then F="$d/$f" break fi done if [ "$F" == "" ]; then files_not_found="$files_not_found\n$f" continue fi target_dep_lst=`echo "$F $target_dep_lst" | sed 's~ ~\n~g' | sort -u` done echo "$to: \\" >> Makefile for td in $target_dep_lst; do td=`echo "$td" | sed "s~^\./~~ ; s~^\./~~ ; s~${HOME}~$\(HOME\)~"` echo -e "\t$td \\" >> Makefile done echo >> Makefile done # ======= Warning ======= files_not_found=`echo -e "$files_not_found" | sort -u` if [ "$files_not_found" != "" ]; then echo WARNING: Include files not found: $files_not_found fi