Have `make install' write the Python version number in the #!
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 11 Jun 2008 08:36:23 +0000 (09:36 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 11 Jun 2008 08:36:23 +0000 (09:36 +0100)
The Xen tools contain a number of Python extensions written in C.  The
C API to Python, used by these extensions, is not stable from one
version of Python to the next.

Our build system uses whatever version of Python is the default on the
build system at that time to build these extensions.  However, the
actual scripts such as `xm' use  #!/usr/bin/env python  which uses
whichever version of Python is the default on the deployment system at
the time of invocation.

If for any reason these two versions of Python are not the same (eg,
because the system is built on one computer and executed on another,
or because the system's gains a more recent Python installation
alongside the original which changes the previous default), warnings
and failures occur.

In this patch I arrange for Python scripts to be installed via a
special wrapper around `install', which determines the build-time
Python version and path and then writes that into the #! line at the
point of `make install' (or `make dist').  (It can also be overridden
by setting PYTHON_PATH.)

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
tools/Rules.mk
tools/misc/Makefile
tools/python/get-path [new file with mode: 0755]
tools/python/install-wrap [new file with mode: 0755]

index 29639a341d931253062e53d0b1832fddc0c4fa41..41a92a28bc13456c0ae0e5322ce7323ad77b420a 100644 (file)
@@ -35,6 +35,11 @@ LDFLAGS += $(shell getconf LFS_LDFLAGS)
 CFLAGS-$(CONFIG_X86_32) += $(call cc-option,$(CC),-mno-tls-direct-seg-refs)
 CFLAGS += $(CFLAGS-y)
 
+DEFAULT_PYTHON_PATH := $(shell $(XEN_ROOT)/tools/python/get-path)
+PYTHON_PATH ?= $(DEFAULT_PYTHON_PATH)
+INSTALL_PYTHON_PROG = $(XEN_ROOT)/tools/python/install-wrap \
+"$(PYTHON_PATH)" $(INSTALL_PROG)
+
 # Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers)
 check-$(CONFIG_X86) = $(call cc-ver-check,CC,0x030400,\
                         "Xen requires at least gcc-3.4")
index 42968d8f57c31d377d7e0c844ff7ae93cca228b4..b8eec1605dc8e582be5ecabe198535cd2dd38a29 100644 (file)
@@ -32,8 +32,8 @@ build: $(TARGETS)
 install: build
        $(INSTALL_DIR) $(DESTDIR)$(BINDIR)
        $(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
-       $(INSTALL_PROG) $(INSTALL_BIN) $(DESTDIR)$(BINDIR)
-       $(INSTALL_PROG) $(INSTALL_SBIN) $(DESTDIR)$(SBINDIR)
+       $(INSTALL_PYTHON_PROG) $(INSTALL_BIN) $(DESTDIR)$(BINDIR)
+       $(INSTALL_PYTHON_PROG) $(INSTALL_SBIN) $(DESTDIR)$(SBINDIR)
        set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d install-recurse; done
 
 .PHONY: clean
diff --git a/tools/python/get-path b/tools/python/get-path
new file mode 100755 (executable)
index 0000000..ae67279
--- /dev/null
@@ -0,0 +1,22 @@
+#! /usr/bin/env bash
+set -e
+
+check () {
+       set +e
+       p=`type -p python$v`
+       r=$?
+       set -e
+       if [ $r = 0 ]; then
+               echo >&2 "${0##*/}: will use #!$p for python programs"
+               printf "%s\n" "$p"
+               exit 0
+       fi
+}
+
+v="$(python -V 2>&1)"
+v="${v#* }"
+check
+v="${v%.*}"
+check
+echo >&2 'python version not determined, will use env to find python at runtime'
+printf "/usr/bin/env python\n"
diff --git a/tools/python/install-wrap b/tools/python/install-wrap
new file mode 100755 (executable)
index 0000000..29db25d
--- /dev/null
@@ -0,0 +1,44 @@
+#! /usr/bin/env bash
+# usage:
+#  .../install-wrap $(PYTHON_PATH) install <options-to-install> <src>... <dest>
+# where
+#  PYTHON_PATH is what to put after #! and may be `/usr/bin/env python'
+#
+# Used via $(INSTALL_PYTHON_PROG) in Rules.mk; PYTHON_PATH comes from
+# .../get-path alongside this script
+
+set -e
+if [ $# -lt 2 ]; then echo >&2 "${0##*/}: too few arguments"; exit 1; fi
+pythonpath="$1"; shift
+
+install=("$1"); shift
+srcs=()
+
+while [ $# != 0 ]; do
+       case "$1" in
+       -|--)   install=("${install[@]}" "$1"); shift; break ;;
+       -*)     install=("${install[@]}" "$1"); shift ;;
+       *)      break ;;
+       esac
+done
+while [ $# -gt 1 ]; do
+       srcs=("${srcs[@]}" "$1"); shift
+done
+dest="$1"; shift
+
+destf="$dest"
+for srcf in "${srcs[@]}"; do
+       if test -d "$dest"; then
+               destf="$dest/${srcf%%*/}";
+       fi
+       org="$(sed -n '2q; /^#! *\/usr\/bin\/env python *$/p' $srcf)"
+       if [ "x$org" = x ]; then
+               "${install[@]}" "$srcf" "$destf"
+               continue
+       fi
+       tmpf="$destf.tmp"
+       "${install[@]}" "$srcf" "$tmpf"
+       printf >"$tmpf" "#!%s\n" "$pythonpath"
+       sed -e 1d "$srcf" >>"$tmpf"
+       mv -f "$tmpf" "$destf"
+done