tools: Add create-ccan-tree utility
authorJeremy Kerr <jk@ozlabs.org>
Wed, 16 May 2012 03:02:56 +0000 (11:02 +0800)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 17 May 2012 03:43:05 +0000 (13:13 +0930)
Add a script to create a ccan source tree for inclusion into projects'
distributed code.

create-ccan-tree takes a list of ccan modules and copies them, plus any
dependent modules, into a target directory. Enough build infrastructure
is added to build libccan.a from the ccan modules.

Typical usage for my project that uses talloc and read-write-all:

  lib/ccan.git/tools/create-ccan-tree --exclude-tests \
lib/ccan/ talloc read-write-all

- this uses a git submodule in $PWDlib/ccan.git to create a source tree
in $PWD/lib/ccan, containing code for talloc and read-write-all.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
tools/create-ccan-tree [new file with mode: 0755]

diff --git a/tools/create-ccan-tree b/tools/create-ccan-tree
new file mode 100755 (executable)
index 0000000..106b7a5
--- /dev/null
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+progname=$(basename $0)
+
+usage() {
+       cat >&2 <<EOF
+Usage: $progname [options] <outdir> <depends>...
+
+options:
+  -t, --exclude-tests         exclude test/ directories from ccan modules
+  -c, --exclude-configurator  exclude configurator. config.h must be
+                              supplied by another method (eg, autotools)
+EOF
+}
+
+# parse options, setting the following flags
+exclude_tests=
+exclude_configurator=
+
+opts=$(getopt -o tc --long exclude-tests,exclude-configurator -n $progname \
+               -- "$@")
+
+if [ $? != 0 ]
+then
+       usage
+       exit 1
+fi
+
+eval set -- "$opts"
+
+while :
+do
+       case "$1" in
+               -t|--exclude-tests)
+                       exclude_tests=1
+                       shift
+                       ;;
+               -c|--exclude-configurator)
+                       exclude_configurator=1
+                       shift
+                       ;;
+               --)
+                       shift
+                       break
+                       ;;
+               *)
+                       echo "Internal error!">&2
+                       exit 1
+                       ;;
+       esac
+done
+
+# we need at least two non-option arguments: outdir and a list of ccan
+# modules
+if [ $# -lt 2 ]
+then
+       usage
+       exit 1
+fi
+
+srcdir=$(dirname $0)/../
+outdir="$1"
+shift
+modules="$@"
+
+if [ -e "$outdir" ]
+then
+       echo "Output directory '$outdir' already exists" >&2
+       exit 1
+fi
+
+tmpdir="$(mktemp -d)"
+# sanity check, we don't want to be overwriting stuff in arbitrary dirs
+[ $? -eq 0 -a -d "${tmpdir}" ] || exit 1
+
+# We'll need the ccan_depends tool, but also a clean source tree. Build
+# tools/ccan_depends, and store it in $tmpdir for later use
+
+echo "Building ccan_depends"
+ccan_depends="$tmpdir/ccan_depends"
+make -s -C "$srcdir" tools/ccan_depends
+[ $? -eq 0 ] || exit 1
+cp "$srcdir/tools/ccan_depends" "$ccan_depends"
+
+echo "Cleaning source tree"
+make -s -C "$srcdir" clean
+[ $? -eq 0 ] || exit 1
+
+# clean up on error
+trap 'rm -rf $tmpdir' EXIT
+
+# generate list of directories to copy
+for module in $modules
+do
+       # ccan_depends takes a directory name
+       module_dir="$srcdir/ccan/$module"
+
+       # we need the module itself...
+       echo "ccan/$module"
+
+       # .. plus dependencies
+       "$ccan_depends" "$module_dir"
+
+       if [ $? -ne 0 ]
+       then
+               echo "Invalid ccan module '$module'?" >&2
+               exit 1
+       fi
+done |
+sort -u |
+while read dir
+do
+       module_srcdir="$srcdir/$dir"
+       module_destdir="$tmpdir/$dir"
+       echo "Adding $dir"
+       mkdir -p "$(dirname "$module_destdir")"
+       cp -a "$module_srcdir" "$module_destdir"
+       if [ -n "$exclude_tests" ]
+       then
+               rm -rf "$module_destdir/test"
+       fi
+done
+
+# we're done with the dependency-tracking, remove the tool from our
+# temporary directory
+rm "$ccan_depends"
+
+echo "Adding licenses"
+license_dir="$tmpdir/licenses"
+mkdir "$license_dir"
+
+find "$tmpdir" -type l -name LICENSE |
+while read license
+do
+       license_link=$(readlink "$license")
+       licence_file=$(basename "$license_link")
+       license_src="$srcdir/licenses/$licence_file"
+       license_dest="$license_dir/$license_file"
+       cp "$license_src" "$license_dest"
+done
+
+# add ccan Makefile
+echo "Adding build infrastructure"
+cp "$srcdir/Makefile-ccan" "$tmpdir/"
+
+# add top-level Makefile
+top_makefile="$tmpdir/Makefile"
+cat > "$top_makefile" << EOF
+all: libccan.a
+
+include Makefile-ccan
+EOF
+
+# optionally add configurator, and relevant parts to top-level Makefile
+if [ -z "$exclude_configurator" ]
+then
+       echo "Adding configurator"
+       mkdir -p "$tmpdir/tools/configurator"
+       cp -a "$srcdir/tools/configurator" "$tmpdir/tools/"
+
+       cat >> "$top_makefile" <<EOF
+tools/configurator/configurator: tools/configurator/configurator.c
+
+config.h: tools/configurator/configurator Makefile Makefile-ccan
+       tools/configurator/configurator \$(CC) \$(CCAN_CFLAGS) > \$@ \\
+               || rm -f \$@
+
+objs = \$(patsubst %.c, %.o, \$(wildcard ccan/*/*.c))
+\$(objs): config.h
+
+EOF
+fi
+
+mv "$tmpdir" "$outdir"
+echo "Done. ccan source tree built in $outdir"
+
+trap - EXIT