Ulrich Spoerlein wrote:
> I wrote a script 

That got stripped by the mailling lists ... second try. You can also
fetch it from

http://coyote.dnsalias.net/create_pkg_makefile.sh

Ulrich Spoerlein
-- 
"The trouble with the dictionary is you have to know how the word is
spelled before you can look it up to see how it is spelled."
-- Will Cuppy
#!/usr/bin/env zsh
# vi:set sw=2 tw=78:
#
# "THE BEER-WARE LICENSE" (Revision 42):
# <[EMAIL PROTECTED]> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return. Ulrich Spoerlein
# 
# What this is:
# 
# This script will output a Makefile, that is self-contained and suitable for
# building individual sets of packages with maximum parallelism.
#
# Who it is for:
#
# For people needing to build clean packages, probably with a custom
# make.conf, for system deployment.
#
# How it works:
# 
# It will recursively walk the $PORTS tree for the specified package origins
# (or all POs if none are given) and create the correct dependency tree plus
# targets to build those packages.
#
# To guarantee a clean package without "contamination", as can happen by
# configure scripts picking up random installed libraries, it uses a clean
# "installworld" provided by either an unionfs mount or by copying the tree to
# the destination. (There are a some problems with unionfs mounts, if packages
# don't build, try the cpio method first.)
#
# How to use:
# 
# First, you need to create a clean environment:
# cd $SRC && make buildworld installworld distribution DESTDIR=$ROOT/live
# mkdir -p $ROOT/live/usr/ports $ROOT/distfiles $ROOT/obj $ROOT/packages/All
#
# Since we can't change make(1)s .OBJDIR to some arbitrary value, create an
# obj link to the package directory:
# ln -sf $ROOT/packages/All obj
#
# Create a make.conf with your desired flags, set CONF=$PWD/make.conf # 
(default)
# vi make.conf
#
# And torture your machine 
# ./create_pkg_makefiles.sh editors/vim x11/kde3 | make -f- -j4 all
# 
# To watch the build progressing, use something like:
# while sleep 3; do screen -r; done
#
# The Makefile for all ports can be created by:
# ./create_pkg_makefiles.sh > Makefile
#
# The special "check" target will only print what packages would be build;
# use it in conjunction with "all" or your desired package origins.
# make -j4 check editors/vim x11/kde3
# make check all
#
# To update all your installed packages, a heavy handed approach would be to:
# cp /etc/make.conf .
# ./create_pkg_makefiles.sh `pkg_info -qao` | make -f- -j2 all
# pkg_delete -fa
# pkg_add -F $ROOT/packages/All/*
# 


# User configuration
ROOT=/vol
PORTS=/usr/ports
SRC=/usr/src
CONF=$PWD/make.conf
#CONF=/etc/make.conf
# End of user configuration.

# Global hash, saving pkg-origin -> pkg-name. Is also used to look up
# which pkg-origins have already been checked.
typeset -A pkg

print_make_header()
{
  cat <<EOS
# Root dir of build space
R=${ROOT}
B=\$R/live
O=\$R/obj
PKG=\$R/packages
DIST=\$R/distfiles

# Source directories
S=${SRC}
P=${PORTS}
CONF=${CONF}

# Choose your poison
MK_LIVE_TREE= cd \$B && find . | cpio --quiet -dump \$O/\$\$po
UNMK_LIVE_TREE= rm -rf \$O/\$\$po

#MK_LIVE_TREE= zfs clone ...
#UNMK_LIVE_TREE= zfs remove clone ...

MK_LIVE_TREE= mount -t unionfs -o below,noatime \$B \$O/\$\$po
UNMK_LIVE_TREE= umount \$O/\$\$po; rm -rf \$O/\$\$po

CLEAN_BUILD_SPACE=clean_build_space() { set +e; po=\$\$1; shift; \
  umount \$O/\$\$po/usr/ports/packages; \
  umount \$O/\$\$po/usr/ports/distfiles; \
  umount \$O/\$\$po/usr/ports; \
  umount \$O/\$\$po/usr/src; \
  umount \$O/\$\$po/compat/linux/proc; \
  umount \$O/\$\$po/dev; \
  \${UNMK_LIVE_TREE}; return 0; }; clean_build_space

CREATE_BUILD_SPACE=create_build_space() { po=\$\$1; shift; \
  mkdir -p \$O/\$\$po/usr/ports; \
  mkdir -p \$O/\$\$po/compat/linux/proc; \
  \${MK_LIVE_TREE}; \
  mount -t devfs devfs \$O/\$\$po/dev; \
  mount -t linprocfs linprocfs \$O/\$\$po/compat/linux/proc; \
  mount -t nullfs -oro \$S \$O/\$\$po/usr/src; \
  mount -t nullfs -oro \$P \$O/\$\$po/usr/ports; \
  mount -t nullfs \${DIST} \$O/\$\$po/usr/ports/distfiles; \
  mount -t nullfs \${PKG} \$O/\$\$po/usr/ports/packages; \
  test ! -r "\${CONF}" || cp \${CONF} \$O/\$\$po/etc; }; create_build_space

# The su(1) is required to have a fresh environment, otherwise the
# make(1) vars of -jX will interfere with the package build.
# screen(1) will always exit with code 0, use test(1) outside of screen
# to figure out if everything went well.
CREATE_PACKAGE=create_package() { set -e; po=\$\$1; shift; \
  cd \$O/\$\$po && screen -L -D -m chroot . time -lp -o time.out sh -ec "\
  for dep in \${.ALLSRC}; do \
    echo \"Adding package \\\$\${dep}\"; \
    PKG_PATH=/usr/ports/packages/All pkg_add -F \\\$\${dep%.tbz}; \
  done; \
  su -l root -c \"make -C /usr/ports/\$\$po WRKDIRPREFIX=/usr/obj \
  BATCH=yes build package\""; \
  test -f \${PKG}/All/\${.TARGET}; }; create_package

PARSE_TIME=parse_time() { po=\$\$1; shift; \
        awk -v po=\$\$po '/real/{r=\$\$2} /user/{u=\$\$2} \
        /sys/{s=\$\$2}  /resident set size/{rss=\$\$1} \
        END{print po ": real " r " user " u " sys " s " rss " rss}' \
        \$O/\$\$po/time.out 2>/dev/null; }; parse_time

.SILENT:

check:

EOS
}

print_pkg()
{
  local po
  po=$1; shift

  cat <<EOS
$po: ${pkg[$po]}
${pkg[$po]}: $*
.if make(check)
        echo "$po: Building \${.TARGET} <= \${.ALLSRC}"
.else
        for dep in $*; do test -f \${PKG}/All/\$\$dep || \\
        (echo \"$po: Missing dep \$\$dep, skipped\"; exit 1); done
        echo '$po: Preparing build space'
        \${CLEAN_BUILD_SPACE} $po 2>/dev/null
        \${CREATE_BUILD_SPACE} $po
        echo '$po: Building package'
        \${CREATE_PACKAGE} $po
        \${PARSE_TIME} $po
        echo '$po: Cleaning build space'
        \${CLEAN_BUILD_SPACE} $po
.endif

EOS
}

get_pkg_recursive()
{
  local po list depport deplist level
  po=$1; shift
  level="${1}="; shift

  # Don't revisit already visited nodes
  if [ -n "$pkg[$po]" ]; then
    return
  fi

  if [ -z "$pkg[$po]" ]; then
    pkg[$po]=$(make -C $po __MAKE_CONF=$CONF -V PKGNAME).tbz
  fi
  printf "%-45s %s\n" "$level > $po" $pkg[$po] >&2

  # Get dependency dirs
  list=$(make -C $po __MAKE_CONF=$CONF -V _DEPEND_DIRS | sed "s|${PORTS}/*||g")

  for depport in `eval echo $list`; do
    if [ -z "$pkg[$depport]" ]; then
      get_pkg_recursive $depport $level
    fi
    case "$deplist" in
      *${pkg[$depport]}*) ;;
      *) deplist="$deplist ${pkg[$depport]}" ;;
    esac
  done
  echo "$level < $po" >&2
  print_pkg $po `eval echo $deplist`
}

# Main entry point
print_make_header

cd $PORTS
if [ "$#" -gt 0 ]; then
  for po; do
    get_pkg_recursive $po ""
  done
else
  for sub in $(make -C $PORTS -V SUBDIR); do
    for port in $(make -C $PORTS/$sub -V SUBDIR); do
      get_pkg_recursive $sub/$port ""
    done
  done
fi

printf "\nall: $pkg\n"

Attachment: pgpqnIvcE9wkW.pgp
Description: PGP signature

Reply via email to