python: Generate files into build directory
authorAlon Bar-Lev <alon.barlev@gmail.com>
Sat, 1 Apr 2017 23:29:52 +0000 (02:29 +0300)
committerJustus Winter <justus@g10code.com>
Wed, 5 Apr 2017 12:48:47 +0000 (14:48 +0200)
* lang/python/setup.py.in: Generate files within BuildExtFirstHack
adjust build flags at this point instead of global.
* lang/python/Makefile.am: Remove logic of separate source directory per
python version in favor of build directory.
* lang/python/tests/run-tests.py: Adjust build directory location.
--

Generate files into build directory, leaving the source directory clean.
Use the same source directory for multiple python version build. Result
of 'prepare' target is a standard distutil layout that can be used
easily by downstream to build all python targets in-place.

Signed-off-by: Alon Bar-Lev <alon.barlev@gmail.com>
lang/python/Makefile.am
lang/python/setup.py.in
lang/python/tests/run-tests.py

index a18a014..b9145f5 100644 (file)
@@ -27,70 +27,45 @@ EXTRA_DIST = \
 
 SUBDIRS = . tests
 
-COPY_FILES = \
-       $(srcdir)/gpgme.i \
-       $(srcdir)/README \
-       $(srcdir)/MANIFEST.in \
-       $(srcdir)/gpgme-h-clean.py \
-       $(srcdir)/examples \
-       $(srcdir)/helpers.c $(srcdir)/helpers.h $(srcdir)/private.h
-
-COPY_FILES_GPG = \
-       $(srcdir)/gpg/callbacks.py \
-       $(srcdir)/gpg/constants \
-       $(srcdir)/gpg/core.py \
-       $(srcdir)/gpg/errors.py \
-       $(srcdir)/gpg/__init__.py \
-       $(srcdir)/gpg/results.py \
-       $(srcdir)/gpg/util.py
-
 .PHONY: prepare
-prepare:
-       test -n "$(PREPAREDIR)"
-       $(MKDIR_P)              "$(PREPAREDIR)/gpg"
-       cp -R $(COPY_FILES)     "$(PREPAREDIR)"
-       cp setup.py             "$(PREPAREDIR)"
-       cp gpg/version.py       "$(PREPAREDIR)/gpg"
-       ln -sf "$(abs_top_srcdir)/src/data.h" "$(PREPAREDIR)"
-       ln -sf "$(abs_top_builddir)/config.h" "$(PREPAREDIR)"
-       cp -R $(COPY_FILES_GPG) "$(PREPAREDIR)/gpg"
+prepare: copystamp
 
 # For VPATH builds we need to copy some files because Python's
 # distutils are not VPATH-aware.
-copystamp: $(COPY_FILES) $(COPY_FILES_GPG)
-       set -e ; for VERSION in $(PYTHON_VERSIONS); do \
-         $(MAKE) PREPAREDIR=python$${VERSION}-gpg prepare; \
-       done
+copystamp:
+       ln -sf "$(abs_top_srcdir)/src/data.h" .
+       ln -sf "$(abs_top_builddir)/config.h" .
        touch $@
 
 all-local: copystamp
        set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
          PYTHON="$$1" ; shift ; \
-         cd python$${VERSION}-gpg && \
          CFLAGS="$(CFLAGS)" \
          abs_top_builddir="$(abs_top_builddir)" \
-           $$PYTHON setup.py build --verbose ; \
-         cd .. ; \
+           $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
        done
 
-python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
 python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
-       cd python$(PYTHON_VERSION)-gpg && \
+       $(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
        CFLAGS="$(CFLAGS)" \
        abs_top_builddir="$(abs_top_builddir)" \
-         $(PYTHON) setup.py sdist --verbose
-       gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz
+         $(PYTHON) setup.py sdist --verbose --dist-dir=python$(PYTHON_VERSION)-gpg-dist \
+               --manifest=python$(PYTHON_VERSION)-gpg-dist/MANIFEST
+       gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz
 
 .PHONY: sdist
-sdist: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
-       python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
+sdist: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
 
 .PHONY: upload
-upload: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
-        python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
+upload: python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz \
+        python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz.asc
        twine upload $^
 
-CLEANFILES = copystamp
+CLEANFILES = copystamp \
+       config.h \
+       data.h \
+       files.txt \
+       install_files.txt
 
 # Remove the rest.
 #
@@ -104,22 +79,22 @@ clean-local:
        done
 
 install-exec-local:
-       rm -f install_files.txt
        set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
          PYTHON="$$1" ; shift ; \
-         cd python$${VERSION}-gpg ; \
          abs_top_builddir="$(abs_top_builddir)" \
-         $$PYTHON setup.py install \
-         --prefix $(DESTDIR)$(prefix) \
+         $$PYTHON setup.py \
+         build \
+         --build-base=python$${VERSION}-gpg \
+         install \
+         --prefix "$(DESTDIR)$(prefix)" \
          --record files.txt \
          --verbose ; \
-         cat files.txt >> ../install_files.txt ; \
+         cat files.txt >> install_files.txt ; \
          rm files.txt ; \
-         cd .. ; \
        done
-       $(MKDIR_P) $(DESTDIR)$(pythondir)/gpg
-       mv install_files.txt $(DESTDIR)$(pythondir)/gpg
+       $(MKDIR_P) "$(DESTDIR)$(pythondir)/gpg"
+       mv install_files.txt "$(DESTDIR)$(pythondir)/gpg"
 
 uninstall-local:
-       xargs <$(DESTDIR)$(pythondir)/gpg/install_files.txt -- rm -rf --
-       rm -rf -- $(DESTDIR)$(pythondir)/gpg
+       xargs < "$(DESTDIR)$(pythondir)/gpg/install_files.txt" -- rm -rf --
+       rm -rf -- "$(DESTDIR)$(pythondir)/gpg"
index 8ddbf27..6692de6 100755 (executable)
@@ -21,6 +21,7 @@
 from distutils.core import setup, Extension
 import os, os.path, sys
 import glob
+import shutil
 import subprocess
 
 # Out-of-tree build of the gpg bindings.
@@ -89,14 +90,6 @@ if not os.path.exists(gpg_error_h):
         glob.glob(os.path.join(gpg_error_prefix, "include",
                                "*", "gpg-error.h"))[0]
 
-print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
-
-# Cleanup gpgme.h from deprecated functions and typedefs.
-subprocess.check_call([sys.executable, "gpgme-h-clean.py", gpgme_h],
-                      stdout=open("gpgme.h", "w"))
-subprocess.check_call([sys.executable, "gpgme-h-clean.py", gpg_error_h],
-                      stdout=open("errors.i", "w"))
-
 define_macros = []
 libs = getconfig('libs')
 
@@ -149,14 +142,47 @@ if uname_s.startswith("MINGW32"):
 # http://stackoverflow.com/questions/12491328/python-distutils-not-include-the-swig-generated-module
 from distutils.command.build import build
 class BuildExtFirstHack(build):
+
+    def _generate(self):
+        print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
+
+        # Cleanup gpgme.h from deprecated functions and typedefs.
+        # Keep timestamp to avoid rebuild
+        if not os.path.exists(self.build_base):
+            os.makedirs(self.build_base)
+
+        for src, dst in (
+            (gpgme_h, os.path.join(self.build_base, "gpgme.h")),
+            (gpg_error_h, os.path.join(self.build_base, "errors.i"))
+        ):
+            subprocess.check_call([sys.executable, "gpgme-h-clean.py", src],
+                                  stdout=open(dst, "w"))
+            shutil.copystat(src, dst)
+
+        # Copy due to http://bugs.python.org/issue2624
+        # Avoid creating in srcdir
+        shutil.copy2("gpgme.i", self.build_base)
+
     def run(self):
+        self._generate()
+
+        # Append generated files via build_base
+        if not os.path.exists(os.path.join(self.build_lib, "gpg")):
+            os.makedirs(os.path.join(self.build_lib, "gpg"))
+
+        swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
+        swig_opts.extend(['-I' + self.build_base, '-outdir', os.path.join(self.build_lib, 'gpg')])
+        include_dirs.append(self.build_base)
+
         self.run_command('build_ext')
         build.run(self)
 
 py3 = [] if sys.version_info.major < 3 else ['-py3']
-swige = Extension("gpg._gpgme", ["gpgme.i", "helpers.c"],
-                  swig_opts = ['-threads',
-                               '-outdir', 'gpg'] + py3 + extra_swig_opts,
+swig_sources = ['helpers.c']
+swig_opts = ['-threads'] + py3 + extra_swig_opts
+swige = Extension("gpg._gpgme",
+                  sources = swig_sources,
+                  swig_opts = swig_opts,
                   include_dirs = include_dirs,
                   define_macros = define_macros,
                   library_dirs = library_dirs,
index 9e061d8..9e2fb78 100644 (file)
@@ -71,7 +71,6 @@ for interpreter in args.interpreters:
 
     pattern = os.path.join(args.builddir, "..",
                            "python{0}-gpg".format(version),
-                           "build",
                            "lib*"+version)
     builddirs = glob.glob(pattern)
     if len(builddirs) == 0: