效果展示
生成的makefile
是这样的效果:
# automake version 1.0
CC = gcc
BIN = pkg
OBJ = pkg.o
LIB =
INC =
FLAGS = $(INC) -Wall
pkg: $(OBJ)
$(CC) $(OBJ) -o $(BIN) $(LIB)
pkg.o: pkg.c err.h color.h
$(CC) -c pkg.c -o pkg.o $(FLAGS)
.PHONY: clean
clean:
rm $(OBJ) $(BIN)
使用方法
- 会在当前路径下生成名为
makefile
的文件。 - 会编译当前目录下所有
.c
文件,自动处理依赖关系(额外库(LIB
)和头文件路径(INC
)要手动添加)。 - 额外库(
LIB
)和头文件路径(INC
)会留空,不需要请手动移除对应代码(FLAGS
变量中的$(INC)
、链接命令中的的$(LIB)
)。
$automake
Usage: automake <target.c>
$automake pkg.c
Succeed!
target.c
是你的main()
函数所在.c
文件,生成的可执行程序名为main()
所在.c
文件的文件名去掉后缀名。
源代码
#!/bin/bash
RED="\033[0;31m"
GREEN="\033[0;32m"
NONE="\033[0m"
if [ $# != 1 ]
then
printf "${RED}Usage: automake <target.c>\n${NONE}"
exit 0
fi
makefile="makefile"
target=$(echo $1|sed 's/.c$//g')
allCFiles=$(ls *.c)
#needCFiles="$(gcc -MM ${target}.c | grep -o '\S*\.c')"
needCFiles=${allCFiles}
OBJ=$(echo ${needCFiles} | sed 's/\.c/\.o/g')
INC=""
CC="gcc"
LIB=""
BIN=${target}
FLAGS="-Wall"
echo "# automake version 1.0" > ${makefile}
echo "CC = ${CC}" >> ${makefile}
echo "BIN = ${BIN}" >> ${makefile}
echo "OBJ = ${OBJ}" >> ${makefile}
echo "LIB = ${LIB}" >> ${makefile}
echo "INC = ${INC}" >> ${makefile}
echo "FLAGS = \$(INC) ${FLAGS}" >> ${makefile}
echo "" >> ${makefile}
echo "${target}: \$(OBJ)" >> ${makefile}
echo -e "\t\$(CC) \$(OBJ) -o \$(BIN) \$(LIB)" >> ${makefile}
for file in ${needCFiles}
do
echo $(gcc -MM ${file}) >> ${makefile}
file=$(echo ${file} | sed 's/.c//g')
echo -e "\t\$(CC) -c ${file}.c -o ${file}.o \$(FLAGS)" >> ${makefile}
done
echo "" >> ${makefile}
echo ".PHONY: clean" >> ${makefile}
echo "clean:" >> ${makefile}
echo -e "\trm \$(OBJ) \$(BIN)" >> ${makefile}
printf "${GREEN}Succeed!\n${NONE}"
改进版
$automake
Usgae: automake <main C file> [options] [file]...
Options:
-e <excluded files>
Exclude the files from makefile.
-o <outfile>
Specify the outfile.
-n
Do not add @ before cmd, which forbid echo of makefile.
增加了三个参数:
-e
可以在生成makefile
时添加排除选项。-o
指定makefile
文件名。-n
开启makefile
命令回显。
#!/bin/bash
version='1.0'
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
LYELLOW="\033[1;33m"
NONE="\033[0m"
usage="${YELLOW}\
Usgae: automake <main C file> [options] [file]...
Options:
-e <excluded files>
Exclude the files from makefile.
-o <outfile>
Specify the outfile.
-n
Do not add @ before cmd, which forbid echo of makefile.\n${NONE}"
#print C source file names n current path and return 0.
# args: none
# return: 0
# example: find_source_files
find_source_files()
{
filename_end_with_point_c=$(ls | grep ".*\.c")
sourceFiles=""
for file in ${filename_end_with_point_c}
do
if [ -f ${file} ]
then
index=${#sourceFiles[*]}
sourceFiles[$index]=${file}
fi
done
printf "${sourceFiles[*]}"
return 0
}
# print exchange suffix and print
# args: filenames, old suffix, new suffix
# return: 0
# example: exchange_suffix "1.c 2.c 3.c" .c .o
# exchange_suffix "1.c 2.c 3.c" ".c" '.o'
exchange_suffix()
{
if [ $# -ne 3 ]
then
return -1
fi
file_names=$1
old_suffix=$(echo $2|sed 's/\./\\\./g')
new_suffix=$(echo $3|sed 's/\./\\\./g')
exchaned=""
for name in ${file_names}
do
name=$(echo ${name} | sed "s/${old_suffix}/${new_suffix}/g")
index=${#exchanged[*]}
exchanged[$index]="${name}"
done
printf "${exchanged[*]}"
return 0
}
main()
{
if [ $# -eq 0 ]
then
printf "${usage}"
exit 0
fi
if [ ! -f $1 ]
then
printf "${YELLOW}Invalid main C file.${NONE}\n"
exit 0
fi
main_c_file="/tmp/main_c_file"
echo -n "$1" > ${main_c_file}
shift
excluded_files="/tmp/excluded_files"
outfile="/tmp/outfile"
cmd_echo="true"
is_finding_excluded_files="false"
echo -n "" > ${excluded_files}
echo -n "" > ${outfile}
while [ $# -ne 0 ]
do
OPTIND=1
if getopts "e:o:nv" option
then
case "$option"
in
e) echo ${OPTARG} >> ${excluded_files}
shift 2
is_finding_excluded_files="true";;
o) echo ${OPTARG} >> ${outfile}
shift 2
is_finding_excluded_files="false";;
n) cmd_echo="false"
shift
is_finding_excluded_files="false";;
?) printf "${usage}"
exit 0;;
esac
fi
if [ $# -eq 0 ]
then
break
fi
if [ "$(echo "N$1"|grep -o 'N-')" != "N-" ]
then
if [ $is_finding_excluded_files == "true" ]
then
echo $1 >> ${excluded_files}
shift
else
printf "${usage}"
exit 0
fi
fi
done
makefile="makefile"
if [ "$(cat $outfile)" != "" ]
then
makefile="$(cat $outfile)"
fi
all_source_files="/tmp/all_source_files"
echo -n "" > "$all_source_files"
for file in $(find_source_files)
do
echo "$file" >> "$all_source_files"
done
same_files="/tmp/same_files"
tmp_file="/tmp/tmp_file"
echo -n "" > ${same_files}
for file in $(cat ${all_source_files} ${excluded_files}|sort|uniq -d)
do
echo ${file} >> ${same_files}
done
for file in $(cat ${same_files})
do
grep "${file}" -v ${all_source_files} > ${tmp_file}
mv ${tmp_file} ${all_source_files}
done
sourceFiles="$(cat ${all_source_files})"
if [ $cmd_echo == "true" ]
then
cmd_echo="@"
else
cmd_echo=""
fi
OBJ=$(exchange_suffix "${sourceFiles}" .c .o)
CC="gcc"
INC=""
LIB=""
BIN="$(exchange_suffix "$(cat ${main_c_file})" '.c' '')"
FLAGS="-Wall"
echo "CC = ${CC}" > ${makefile}
echo "BIN = ${BIN}" >> ${makefile}
echo "OBJ = ${OBJ}" >> ${makefile}
echo "LIB = ${LIB}" >> ${makefile}
echo "INC = ${INC}" >> ${makefile}
echo "FLAGS = \$(INC) ${FLAGS}" >> ${makefile}
echo "" >> ${makefile}
echo "${BIN}: \$(OBJ)" >> ${makefile}
echo -e "\t${cmd_echo}\$(CC) \$(OBJ) -o \$(BIN) \$(LIB)" >> ${makefile}
for file in ${sourceFiles}
do
rule=$(gcc -MM ${file})
echo "${rule}" >> ${makefile}
file=$(exchange_suffix "${file}" '.c' '')
cmd="\t${cmd_echo}\$(CC) -c ${file}.c -o ${file}.o \$(FLAGS)"
echo -e ${cmd} >> ${makefile}
done
echo "" >> ${makefile}
echo ".PHONY: clean" >> ${makefile}
echo "clean:" >> ${makefile}
printf "\t${cmd_echo}rm \$(OBJ) \$(BIN)" >> ${makefile}
printf "${LYELLOW}Succeed!\n${NONE}"
}
main $*