Initial commit.
commit
7be1efdd03
|
@ -0,0 +1,445 @@
|
|||
#!/usr/bin/env zsh
|
||||
|
||||
# TODO:
|
||||
# - Make more checks about whether the “things” built and installed are C.
|
||||
# (stuff *will* break if you add non-C things as targets)
|
||||
# - Clean some more (or a lot). I mean, this script could even be reused if
|
||||
# it were cleaner, more readable and somewhat more documented.
|
||||
#
|
||||
# WARNINGS and LIMITATIONS:
|
||||
# - Using a relative path in DESTDIR= *will* fail.
|
||||
#
|
||||
|
||||
# Script output
|
||||
|
||||
function info {
|
||||
echo "${fg_bold[green]}-- ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function warning {
|
||||
echo "${fg_bold[yellow]}-- $@${reset_color}" >&2
|
||||
}
|
||||
|
||||
function error {
|
||||
echo "${fg_bold[red]}-- ERROR: $@${reset_color}" >&2
|
||||
}
|
||||
|
||||
# Makefiles’ output
|
||||
|
||||
function write {
|
||||
echo "$@" >> $Makefile
|
||||
}
|
||||
|
||||
function CC {
|
||||
echo "${fg_bold[blue]} [CC] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function LD {
|
||||
echo "${fg_bold[green]} [LD] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function IN {
|
||||
echo "${fg_bold[red]} [IN] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function LN {
|
||||
echo "${fg_bold[yellow]} [LN] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function RM {
|
||||
echo "${fg_bold[white]} [RM] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function DIR {
|
||||
echo "${fg_bold[magenta]} [DIR] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
function TAR {
|
||||
echo "${fg_bold[yellow]} [TAR] ${fg_bold[white]}$@${reset_color}"
|
||||
}
|
||||
|
||||
# Specialized helpers
|
||||
|
||||
function subdirs {
|
||||
for DIR in ${subdirs[@]}; do
|
||||
if $gnu; then
|
||||
write "\t@echo ' ${fg_bold[red]}>> ${fg_bold[magenta]}`pwd`/${DIR}${reset_color}'"
|
||||
fi
|
||||
|
||||
write -n "\t${Q}(cd \"${DIR}\" && $MAKE"
|
||||
|
||||
if $gnu; then
|
||||
write -n " --no-print-directory"
|
||||
fi
|
||||
|
||||
write -n ' Q=$(Q) CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" DESTDIR="$(DESTDIR)"'
|
||||
|
||||
for name value in ${variables[@]}; do
|
||||
write -n " ${name}=\"\$(${name})\""
|
||||
done
|
||||
|
||||
for name path in ${prefixes[@]}; do
|
||||
write -n " ${name}=\"\$(${name})\""
|
||||
done
|
||||
|
||||
if (( $# > 0 )); then
|
||||
write -n " $@"
|
||||
fi
|
||||
|
||||
write ")"
|
||||
|
||||
if $gnu; then
|
||||
write "\t@echo ' ${fg_bold[red]}<< ${fg_bold[magenta]}`pwd`/${DIR}${reset_color}'"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function get_distfiles {
|
||||
for file in "${dist[@]}" $(echo ${sources[@]}) $(echo ${depends[@]}); do
|
||||
echo "$file"
|
||||
done
|
||||
|
||||
typeset -a src
|
||||
src=($(echo ${sources[@]}))
|
||||
for file in ${src[@]}; do
|
||||
typeset file="${file%.c}.h"
|
||||
if [[ -e "$file" ]]; then
|
||||
echo "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
for target in ${targets[@]}; do
|
||||
if exists "${type[$target]}.distfiles"; then
|
||||
"${type[$target]}.distfiles"
|
||||
fi
|
||||
done
|
||||
|
||||
for dir in ${subdirs[@]}; do
|
||||
(
|
||||
unset dist sources depends subdirs
|
||||
typeset -a dist
|
||||
typeset -A sources depends
|
||||
|
||||
cd "$dir"
|
||||
. ./project.zsh
|
||||
for file in $(get_distfiles); do
|
||||
local file="${dir}/${file}"
|
||||
while [[ "$file" =~ "\.\./" ]]; do
|
||||
file="${file/[a-z]*\/\.\.\//}"
|
||||
done
|
||||
|
||||
echo "${file}"
|
||||
done
|
||||
)
|
||||
done
|
||||
}
|
||||
|
||||
function exists {
|
||||
[[ "$(whence -w ${1})" != "${1}: none" ]]
|
||||
}
|
||||
|
||||
function duplicated {
|
||||
local elem="$1"
|
||||
local count=0
|
||||
shift 1
|
||||
local i
|
||||
for i in $@; do
|
||||
if [[ "$elem" == "$i" ]]; then
|
||||
((count++))
|
||||
|
||||
if (( $count > 1 )); then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
for i in build/*.zsh; do
|
||||
. $i
|
||||
done
|
||||
|
||||
##
|
||||
# And so it begins
|
||||
##
|
||||
|
||||
function main {
|
||||
typeset -a prefixes directories
|
||||
typeset -A ldflags cflags sources type depends install
|
||||
|
||||
prefixes=(
|
||||
PREFIX '/usr/local'
|
||||
BINDIR '$(PREFIX)/bin'
|
||||
LIBDIR '$(PREFIX)/lib'
|
||||
SHAREDIR '$(PREFIX)/share'
|
||||
INCLUDEDIR '$(PREFIX)/include'
|
||||
)
|
||||
|
||||
if [[ -f project.zsh && -r project.zsh ]]; then
|
||||
. ./project.zsh
|
||||
else
|
||||
error "No “project.zsh” found in $(pwd)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
: > $Makefile
|
||||
|
||||
if [[ -n "$package" && -n "$version" ]]; then
|
||||
export package version
|
||||
|
||||
write "PACKAGE = '$package'"
|
||||
write "VERSION = '$version'"
|
||||
write
|
||||
else
|
||||
if $root; then
|
||||
error "No \$package or no \$version defined in your project.zsh!"
|
||||
error "Making tarballs and other stuff will be disabled."
|
||||
error "(please note that those variables should be defined only..."
|
||||
error " ... in the root directory of your project’s repository)"
|
||||
|
||||
root=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Got some issues of PATH being replaced by a value of $path…
|
||||
for prefix _path in ${prefixes[@]}; do
|
||||
write "$prefix := $_path"
|
||||
done
|
||||
|
||||
for var val in ${variables[@]}; do
|
||||
write "$var := ${val}"
|
||||
done
|
||||
|
||||
write
|
||||
|
||||
write "CC := ${CC:-cc}"
|
||||
write "CFLAGS := ${CFLAGS}"
|
||||
write "LDFLAGS := ${LDFLAGS}"
|
||||
write
|
||||
|
||||
write "Q := @"
|
||||
write
|
||||
|
||||
write -n "all: "
|
||||
(( ${#targets[@]} > 0 )) && write -n " ${targets[@]}"
|
||||
(( ${#subdirs[@]} > 0 )) && write -n " subdirs"
|
||||
|
||||
if $gnu; then
|
||||
write "\n"
|
||||
else
|
||||
write "\n\t@:\n"
|
||||
fi
|
||||
|
||||
for target in ${targets[@]}; do
|
||||
(
|
||||
typeset -a src
|
||||
src=($(echo ${sources[$target]}))
|
||||
local installdir="${install[$target]}"
|
||||
|
||||
if exists "${type[$target]}.build"; then
|
||||
${type[$target]}.build
|
||||
else
|
||||
if ! exists "${type[$target]}.test"; then
|
||||
error "No predefined rule for the following type: ${type[$target]}"
|
||||
error " (expect trouble, nothing’s gonna work!)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if exists "${type[$target]}.install"; then
|
||||
${type[$target]}.install
|
||||
else
|
||||
if [[ -z "${installdir}" ]]; then
|
||||
error "No install[${type[${target}]}] and no default installation directory."
|
||||
error "Your “install” rule will be broken!"
|
||||
else
|
||||
write "${target}.install: \$(DESTDIR)${installdir}"
|
||||
write "\t@echo '$(IN ${installdir}/${target})'"
|
||||
write "\t${Q}install -m755 $target \$(DESTDIR)${installdir}/$target"
|
||||
write
|
||||
fi
|
||||
fi
|
||||
|
||||
if exists "${type[$target]}.clean"; then
|
||||
${type[$target]}.clean
|
||||
else
|
||||
write "${target}.clean:"
|
||||
write "\t@echo '$(RM ${target})'"
|
||||
write "\t${Q}rm -f ${target}"
|
||||
write
|
||||
fi
|
||||
|
||||
if exists "${type[$target]}.uninstall"; then
|
||||
${type[$target]}.uninstall
|
||||
else
|
||||
write "${target}.uninstall:"
|
||||
write "\t@echo '$(RM "${installdir}/${target}")'"
|
||||
write "\t${Q}rm -f '\$(DESTDIR)${installdir}/${target}'"
|
||||
write
|
||||
fi
|
||||
|
||||
if exists "${type[$target]}.test"; then
|
||||
${type[$target]}.test
|
||||
fi
|
||||
)
|
||||
done
|
||||
|
||||
for dir in ${directories[@]}; do
|
||||
write "\$(DESTDIR)${dir}:"
|
||||
write "\t@echo '$(DIR ${dir})'"
|
||||
write "\t${Q}mkdir -p \$(DESTDIR)${dir}"
|
||||
done
|
||||
|
||||
for dir __ in ${prefixes[@]}; do
|
||||
write "\$(DESTDIR)\$(${dir}):"
|
||||
write "\t@echo '$(DIR "\$(${dir})")'"
|
||||
write "\t${Q}mkdir -p \$(DESTDIR)\$(${dir})"
|
||||
done
|
||||
|
||||
(( ${#subdirs[@]} > 0 )) && {
|
||||
write "subdirs:"
|
||||
subdirs
|
||||
write
|
||||
}
|
||||
|
||||
write -n "install: subdirs.install"
|
||||
for target in ${targets[@]}; do
|
||||
write -n " ${target}.install"
|
||||
done
|
||||
write "\n\t@:\n"
|
||||
|
||||
write "subdirs.install:"
|
||||
subdirs install
|
||||
write
|
||||
|
||||
write -n "uninstall: subdirs.uninstall"
|
||||
for target in ${targets[@]}; do
|
||||
write -n " ${target}.uninstall"
|
||||
done
|
||||
write "\n\t@:\n"
|
||||
|
||||
write "subdirs.uninstall:"
|
||||
subdirs uninstall
|
||||
write
|
||||
|
||||
write -n "test: all subdirs subdirs.test"
|
||||
for target in ${targets[@]}; do
|
||||
if exists ${type[$target]}.test; then
|
||||
write -n " ${target}.test"
|
||||
fi
|
||||
done
|
||||
write "\n\t@:\n"
|
||||
|
||||
write "subdirs.test:"
|
||||
subdirs test
|
||||
write
|
||||
|
||||
write -n "clean:"
|
||||
(( ${#targets[@]} > 0 )) && {
|
||||
for target in ${targets[@]}; do
|
||||
write -n " ${target}.clean"
|
||||
(
|
||||
typeset -a src
|
||||
src=($(echo ${sources[$target]}))
|
||||
|
||||
for file in ${src[@]}; do
|
||||
write -n " ${file%.c}.o.clean"
|
||||
done
|
||||
)
|
||||
done
|
||||
}
|
||||
write
|
||||
(( ${#subdirs[@]} > 0 )) && subdirs clean
|
||||
write
|
||||
|
||||
write "distclean: clean"
|
||||
(( ${#subdirs[@]} > 0 )) && subdirs distclean
|
||||
write
|
||||
|
||||
if $root; then
|
||||
write "dist: dist-gz dist-xz dist-bz2"
|
||||
write "\t"$Q'rm -- $(PACKAGE)-$(VERSION)'
|
||||
write
|
||||
|
||||
write "distdir:"
|
||||
write "\t"$Q'rm -rf -- $(PACKAGE)-$(VERSION)'
|
||||
write "\t"$Q'ln -s -- . $(PACKAGE)-$(VERSION)'
|
||||
write
|
||||
|
||||
typeset -a distfiles
|
||||
distfiles=($(get_distfiles))
|
||||
local i
|
||||
|
||||
for i in {1..${#distfiles[@]}}; do
|
||||
if duplicated "${distfiles[${i}]}" "${distfiles[@]}"; then
|
||||
distfiles[${i}]=
|
||||
fi
|
||||
done
|
||||
|
||||
for i flag in gz z xz J bz2 j; do
|
||||
write "dist-${i}: \$(PACKAGE)-\$(VERSION).tar.$i"
|
||||
write "\$(PACKAGE)-\$(VERSION).tar.$i: distdir"
|
||||
write "\t@echo '$(TAR "\$(PACKAGE)-\$(VERSION).tar.$i")'"
|
||||
write "\t${Q}tar c${flag}f \$(PACKAGE)-\$(VERSION).tar.$i \\"
|
||||
for i in {1..${#distfiles}}; do
|
||||
if [[ -n "${distfiles[$i]}" ]]; then
|
||||
write -n "\t\t\$(PACKAGE)-\$(VERSION)/${distfiles[$i]}"
|
||||
if (( i != ${#distfiles} )); then
|
||||
write " \\"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
write "\n"
|
||||
done
|
||||
fi
|
||||
|
||||
for i in ${subdirs[@]}; do
|
||||
(
|
||||
cd $i
|
||||
unset subdirs targets dist sources ldflags depends install type variables
|
||||
typeset -A sources ldflags depends install type variables
|
||||
typeset -a targets dist
|
||||
root=false main $i
|
||||
)
|
||||
done
|
||||
|
||||
write ".PHONY: all subdirs clean distclean dist install uninstall"
|
||||
write
|
||||
}
|
||||
|
||||
export Makefile=Makefile
|
||||
export MAKE='$(MAKE)'
|
||||
export Q='$(Q)'
|
||||
export gnu=false
|
||||
|
||||
while (($# > 0)); do
|
||||
case "$1" in
|
||||
-c|--colors)
|
||||
autoload -U colors
|
||||
colors
|
||||
;;
|
||||
-g|--gnu)
|
||||
export gnu=true
|
||||
;;
|
||||
-h|--help)
|
||||
echo "usage: $0 [OPTIONS]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Print this help message."
|
||||
echo " -c, --colors Use colors in your Makefiles"
|
||||
echo " (relies on zsh/colors and your current \$TERM)"
|
||||
echo " -g, --gnu Sell your soul for gmake-dependent features."
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
error "unrecognised parameter: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
shift 1
|
||||
done
|
||||
|
||||
echo "Generating Makefiles..."
|
||||
root=true main
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
function binary.build {
|
||||
write -n "${target}:"
|
||||
for i in ${src[@]}; do
|
||||
write -n " ${i%.*}.o"
|
||||
done
|
||||
write " ${depends[$target]}"
|
||||
write "\t@echo '$(LD ${target})'"
|
||||
write "\t$Q\$(CC) -o ${target} \$(LDFLAGS) ${ldflags[$target]} ${src[@]//.c/.o}"
|
||||
write
|
||||
|
||||
for i in ${src[@]}; do
|
||||
write -n "${i%.c}.o: ${i}"
|
||||
|
||||
for h in *.h; do
|
||||
if grep -q "#include \"$h\"" $i; then
|
||||
write -n " $h"
|
||||
fi
|
||||
done
|
||||
write
|
||||
|
||||
write "\t@echo '$(CC ${i%.c}.o)'"
|
||||
write "\t$Q\$(CC) \$(CFLAGS) ${cflags[$target]} -c ${i}"
|
||||
write
|
||||
done
|
||||
}
|
||||
|
||||
function binary.install {
|
||||
local install="${install[$target]:-\$(BINDIR)}"
|
||||
write "${target}.install: ${target}"
|
||||
write "\t@echo '$(IN "${install}/${target}")'"
|
||||
write "\t${Q}install -m0755 ${target} \$(DESTDIR)${install}/${target}"
|
||||
write
|
||||
}
|
||||
|
||||
function binary.uninstall {
|
||||
local install="${install[$target]:-\$(BINDIR)}"
|
||||
write "${target}.uninstall:"
|
||||
write "\t@echo '$(RM ${install}/${target})'"
|
||||
write "\t${Q}rm -f '\$(DESTDIR)${install}/${target}'"
|
||||
write
|
||||
}
|
||||
|
||||
function binary.clean {
|
||||
write "${target}.clean:"
|
||||
write "\t@echo '$(RM ${target})'"
|
||||
write "\t${Q}rm -f ${target}"
|
||||
write
|
||||
|
||||
for i in ${src[@]}; do
|
||||
write "${i%.c}.o.clean:"
|
||||
write "\t@echo '$(RM ${i%.c}.o)'"
|
||||
write "\t${Q}rm -f ${i%.c}.o"
|
||||
write
|
||||
done
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
function script.build {
|
||||
write -n "${target}:"
|
||||
|
||||
if [[ -e "${target}.in" ]]; then
|
||||
write " ${target}.in"
|
||||
write "\tcat ${target}.in > ${target}"
|
||||
write "\tchmod +x ${target}"
|
||||
fi
|
||||
|
||||
write "\n"
|
||||
}
|
||||
|
||||
function script.install {
|
||||
binary.install "$@"
|
||||
}
|
||||
|
||||
function script.uninstall {
|
||||
binary.uninstall "$@"
|
||||
}
|
||||
|
||||
function script.clean {
|
||||
write "${target}.clean:"
|
||||
|
||||
if [[ -e "${target}.in" ]]; then
|
||||
write "\t@echo '$(RM ${target})'"
|
||||
write "\t${Q}rm -f ${target}"
|
||||
fi
|
||||
|
||||
write
|
||||
}
|
||||
|
||||
function script.distfiles {
|
||||
if [[ -e "${target}.in" ]]; then
|
||||
echo "${target}.in"
|
||||
else
|
||||
echo "${target}"
|
||||
fi
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
package=build_zsh
|
||||
version=0.1
|
||||
|
||||
targets=(build.zsh)
|
||||
type[build.zsh]=script
|
||||
|
||||
dist=(build/*.zsh project.zsh Makefile)
|
||||
|
Loading…
Reference in New Issue