Blame lang/python/setup.py.in

Packit d7e8d0
#!/usr/bin/env python
Packit d7e8d0
Packit Service 30b792
# Copyright (C) 2016-2018 g10 Code GmbH
Packit d7e8d0
# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
Packit d7e8d0
# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
Packit d7e8d0
#
Packit d7e8d0
#    This library is free software; you can redistribute it and/or
Packit d7e8d0
#    modify it under the terms of the GNU Lesser General Public
Packit d7e8d0
#    License as published by the Free Software Foundation; either
Packit d7e8d0
#    version 2.1 of the License, or (at your option) any later version.
Packit d7e8d0
#
Packit d7e8d0
#    This library is distributed in the hope that it will be useful,
Packit d7e8d0
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
#    Lesser General Public License for more details.
Packit d7e8d0
#
Packit d7e8d0
#    You should have received a copy of the GNU Lesser General Public
Packit d7e8d0
#    License along with this library; if not, write to the Free Software
Packit d7e8d0
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
Packit d7e8d0
Packit d7e8d0
from distutils.core import setup, Extension
Packit Service 30b792
from distutils.command.build import build
Packit Service 30b792
Packit d7e8d0
import glob
Packit Service 30b792
import os
Packit Service 30b792
import os.path
Packit d7e8d0
import re
Packit d7e8d0
import shutil
Packit d7e8d0
import subprocess
Packit Service 30b792
import sys
Packit d7e8d0
Packit d7e8d0
# Out-of-tree build of the gpg bindings.
Packit Service 30b792
gpg_error_config = ['gpg-error-config']
Packit Service 30b792
gpgme_config_flags = ['--thread=pthread']
Packit Service 30b792
gpgme_config = ['gpgme-config'] + gpgme_config_flags
Packit Service 30b792
gpgme_h = ''
Packit d7e8d0
include_dirs = [os.getcwd()]
Packit d7e8d0
library_dirs = []
Packit d7e8d0
in_tree = False
Packit d7e8d0
extra_swig_opts = []
Packit d7e8d0
extra_macros = dict()
Packit d7e8d0
Packit Service 30b792
top_builddir = os.environ.get('top_builddir')
Packit d7e8d0
if top_builddir:
Packit d7e8d0
    # In-tree build.
Packit d7e8d0
    in_tree = True
Packit Service 30b792
    gpgme_config = [os.path.join(top_builddir, 'src/gpgme-config')
Packit Service 30b792
                    ] + gpgme_config_flags
Packit Service 30b792
    gpgme_h = os.path.join(top_builddir, 'src/gpgme.h')
Packit Service 30b792
    library_dirs = [os.path.join(top_builddir,
Packit Service 30b792
                                 'src/.libs')]  # XXX uses libtool internals
Packit d7e8d0
    extra_macros.update(
Packit d7e8d0
        HAVE_CONFIG_H=1,
Packit d7e8d0
        HAVE_DATA_H=1,
Packit d7e8d0
        IN_TREE_BUILD=1,
Packit d7e8d0
    )
Packit d7e8d0
Packit Service 30b792
if hasattr(subprocess, 'DEVNULL'):
Packit d7e8d0
    devnull = subprocess.DEVNULL
Packit d7e8d0
else:
Packit Service 30b792
    devnull = open(os.devnull, 'w')
Packit d7e8d0
Packit d7e8d0
try:
Packit Service 30b792
    subprocess.check_call(gpgme_config + ['--version'], stdout=devnull)
Packit d7e8d0
except:
Packit Service 30b792
    sys.exit('Could not find gpgme-config.  ' +
Packit Service 30b792
             'Please install the libgpgme development package.')
Packit Service 30b792
Packit d7e8d0
Packit d7e8d0
def getconfig(what, config=gpgme_config):
Packit Service 30b792
    confdata = subprocess.Popen(
Packit Service 30b792
        config + ['--%s' % what], stdout=subprocess.PIPE).communicate()[0]
Packit d7e8d0
    return [x for x in confdata.decode('utf-8').split() if x != '']
Packit d7e8d0
Packit Service 30b792
Packit Service 30b792
version = version_raw = getconfig('version')[0]
Packit d7e8d0
if '-' in version:
Packit d7e8d0
    version = version.split('-')[0]
Packit d7e8d0
major, minor, patch = map(int, version.split('.'))
Packit d7e8d0
Packit d7e8d0
if not (major > 1 or (major == 1 and minor >= 7)):
Packit d7e8d0
    sys.exit('Need at least GPGME version 1.7, found {}.'.format(version_raw))
Packit d7e8d0
Packit d7e8d0
if not gpgme_h:
Packit Service 30b792
    gpgme_h = os.path.join(getconfig('prefix')[0], 'include', 'gpgme.h')
Packit d7e8d0
Packit d7e8d0
define_macros = []
Packit d7e8d0
libs = getconfig('libs')
Packit d7e8d0
Packit d7e8d0
# Define extra_macros for both the SWIG and C code
Packit d7e8d0
for k, v in extra_macros.items():
Packit Service 30b792
    extra_swig_opts.append('-D{0}={1}'.format(k, v))
Packit d7e8d0
    define_macros.append((k, str(v)))
Packit d7e8d0
Packit d7e8d0
for item in getconfig('cflags'):
Packit Service 30b792
    if item.startswith('-I'):
Packit d7e8d0
        include_dirs.append(item[2:])
Packit Service 30b792
    elif item.startswith('-D'):
Packit Service 30b792
        defitem = item[2:].split('=', 1)
Packit Service 30b792
        if len(defitem) == 2:
Packit d7e8d0
            define_macros.append((defitem[0], defitem[1]))
Packit d7e8d0
        else:
Packit d7e8d0
            define_macros.append((defitem[0], None))
Packit d7e8d0
Packit d7e8d0
# Adjust include and library locations in case of win32
Packit Service 30b792
uname_s = os.popen('uname -s').read()
Packit Service 30b792
if uname_s.startswith('MINGW32'):
Packit Service 30b792
    mnts = [
Packit Service 30b792
        x.split()[0:3:2] for x in os.popen('mount').read().split('\n') if x
Packit Service 30b792
    ]
Packit Service 30b792
    tmplist = sorted([(len(x[1]), x[1], x[0]) for x in mnts])
Packit Service 30b792
    tmplist.reverse()
Packit Service 30b792
    extra_dirs = []
Packit Service 30b792
    for item in include_dirs:
Packit Service 30b792
        for ln, mnt, tgt in tmplist:
Packit Service 30b792
            if item.startswith(mnt):
Packit Service 30b792
                item = os.path.normpath(item[ln:])
Packit Service 30b792
                while item[0] == os.path.sep:
Packit Service 30b792
                    item = item[1:]
Packit Service 30b792
                extra_dirs.append(os.path.join(tgt, item))
Packit Service 30b792
                break
Packit Service 30b792
    include_dirs += extra_dirs
Packit Service 30b792
    for item in [x[2:] for x in libs if x.startswith('-L')]:
Packit Service 30b792
        for ln, mnt, tgt in tmplist:
Packit Service 30b792
            if item.startswith(mnt):
Packit Service 30b792
                item = os.path.normpath(item[ln:])
Packit Service 30b792
                while item[0] == os.path.sep:
Packit Service 30b792
                    item = item[1:]
Packit Service 30b792
                library_dirs.append(os.path.join(tgt, item))
Packit Service 30b792
                break
Packit Service 30b792
Packit d7e8d0
Packit d7e8d0
def in_srcdir(name):
Packit Service 30b792
    return os.path.join(os.environ.get('srcdir', ''), name)
Packit Service 30b792
Packit Service 30b792
Packit d7e8d0
def up_to_date(source, target):
Packit Service 30b792
    return (os.path.exists(target) and
Packit Service 30b792
            os.path.getmtime(source) <= os.path.getmtime(target))
Packit Service 30b792
Packit d7e8d0
Packit d7e8d0
# We build an Extension using SWIG, which generates a Python module.
Packit d7e8d0
# By default, the 'build_py' step is run before 'build_ext', and
Packit d7e8d0
# therefore the generated Python module is not copied into the build
Packit d7e8d0
# directory.
Packit Service 30b792
# Bugs: https://bugs.python.org/issue1016626
Packit Service 30b792
#       https://bugs.python.org/issue2624
Packit d7e8d0
# Workaround:
Packit Service 30b792
# https://stackoverflow.com/questions/12491328/python-distutils-not-include-the-swig-generated-module
Packit Service 30b792
#
Packit Service 30b792
# To install to multiple Python installations or to alternate ones run the
Packit Service 30b792
# following three commands (yes, run the build one twice):
Packit Service 30b792
#
Packit Service 30b792
# /path/to/pythonX.Y setup.py build
Packit Service 30b792
# /path/to/pythonX.Y setup.py build
Packit Service 30b792
# /path/to/pythonX.Y setup.py install
Packit Service 30b792
#
Packit Service 30b792
# It is highly likely that this will need to be run as root or with sudo (or
Packit Service 30b792
# sudo -H).  It may or may not work with venv. and outside a virtualenv
Packit d7e8d0
Packit Service 30b792
class BuildExtFirstHack(build):
Packit d7e8d0
    def _read_header(self, header, cflags):
Packit Service 30b792
        tmp_include = self._in_build_base('include1.h')
Packit d7e8d0
        with open(tmp_include, 'w') as f:
Packit Service 30b792
            f.write('#include <%s>' % header)
Packit Service 30b792
        return subprocess.check_output(
Packit Service 30b792
            os.environ.get('CPP', 'cc -E').split() + cflags +
Packit Service 30b792
            [tmp_include]).decode('utf-8')
Packit d7e8d0
Packit d7e8d0
    def _write_if_unchanged(self, target, content):
Packit d7e8d0
        if os.path.exists(target):
Packit d7e8d0
            with open(target) as f:
Packit d7e8d0
                if f.read() == content:
Packit d7e8d0
                    return
Packit d7e8d0
Packit Service 30b792
        with open(target, 'w') as sink:
Packit d7e8d0
            sink.write(content)
Packit d7e8d0
Packit d7e8d0
    def _generate_gpgme_h(self, source_name, sink_name):
Packit Service 30b792
        print('Using gpgme.h from {}'.format(source_name))
Packit Service 30b792
        shutil.copy2(source_name, sink_name)
Packit d7e8d0
Packit d7e8d0
    def _generate_errors_i(self):
Packit d7e8d0
Packit d7e8d0
        try:
Packit Service 30b792
            subprocess.check_call(
Packit Service 30b792
                gpg_error_config + ['--version'], stdout=devnull)
Packit d7e8d0
        except:
Packit Service 30b792
            sys.exit('Could not find gpg-error-config.  ' +
Packit Service 30b792
                     'Please install the libgpg-error development package.')
Packit d7e8d0
Packit Service 30b792
        gpg_error_content = self._read_header(
Packit Service 30b792
            'gpg-error.h', getconfig('cflags', config=gpg_error_config))
Packit d7e8d0
Packit d7e8d0
        filter_re = re.compile(r'GPG_ERR_[^ ]* =')
Packit d7e8d0
        rewrite_re = re.compile(r' *(.*) = .*')
Packit d7e8d0
Packit d7e8d0
        errors_i_content = ''
Packit d7e8d0
        for line in gpg_error_content.splitlines():
Packit d7e8d0
            if not filter_re.search(line):
Packit d7e8d0
                continue
Packit Service 30b792
            errors_i_content += rewrite_re.sub(
Packit Service 30b792
                r'%constant long \1 = \1;' + '\n', line.strip())
Packit d7e8d0
Packit Service 30b792
        self._write_if_unchanged(
Packit Service 30b792
            self._in_build_base('errors.i'), errors_i_content)
Packit d7e8d0
Packit d7e8d0
    def _in_build_base(self, name):
Packit d7e8d0
        return os.path.join(self.build_base, name)
Packit d7e8d0
Packit d7e8d0
    def _generate(self):
Packit d7e8d0
        # Cleanup gpgme.h from deprecated functions and typedefs.
Packit d7e8d0
        if not os.path.exists(self.build_base):
Packit d7e8d0
            os.makedirs(self.build_base)
Packit d7e8d0
Packit Service 30b792
        self._generate_gpgme_h(gpgme_h, self._in_build_base('gpgme.h'))
Packit d7e8d0
        self._generate_errors_i()
Packit d7e8d0
Packit Service 30b792
        # Copy due to https://bugs.python.org/issue2624
Packit d7e8d0
        # Avoid creating in srcdir
Packit d7e8d0
        for source, target in ((in_srcdir(n), self._in_build_base(n))
Packit Service 30b792
                               for n in ('gpgme.i', 'helpers.c', 'private.h',
Packit Service 30b792
                                         'helpers.h')):
Packit d7e8d0
            if not up_to_date(source, target):
Packit d7e8d0
                shutil.copy2(source, target)
Packit d7e8d0
Packit d7e8d0
        # Append generated files via build_base
Packit Service 30b792
        if not os.path.exists(os.path.join(self.build_lib, 'gpg')):
Packit Service 30b792
            os.makedirs(os.path.join(self.build_lib, 'gpg'))
Packit Service 30b792
        shutil.copy2('version.py', os.path.join(self.build_lib, 'gpg'))
Packit d7e8d0
Packit d7e8d0
    def run(self):
Packit d7e8d0
        self._generate()
Packit d7e8d0
Packit Service 30b792
        swig_sources.extend((self._in_build_base('gpgme.i'),
Packit Service 30b792
                             self._in_build_base('helpers.c')))
Packit Service 30b792
        swig_opts.extend([
Packit Service 30b792
            '-I' + self.build_base, '-outdir',
Packit Service 30b792
            os.path.join(self.build_lib, 'gpg')
Packit Service 30b792
        ])
Packit d7e8d0
        include_dirs.insert(0, self.build_base)
Packit d7e8d0
Packit d7e8d0
        self.run_command('build_ext')
Packit d7e8d0
        build.run(self)
Packit d7e8d0
Packit Service 30b792
Packit d7e8d0
py3 = [] if sys.version_info.major < 3 else ['-py3']
Packit d7e8d0
swig_sources = []
Packit d7e8d0
swig_opts = ['-threads'] + py3 + extra_swig_opts
Packit Service 30b792
swige = Extension(
Packit Service 30b792
    'gpg._gpgme',
Packit Service 30b792
    sources=swig_sources,
Packit Service 30b792
    swig_opts=swig_opts,
Packit Service 30b792
    include_dirs=include_dirs,
Packit Service 30b792
    define_macros=define_macros,
Packit Service 30b792
    library_dirs=library_dirs,
Packit Service 30b792
    extra_link_args=libs)
Packit Service 30b792
Packit Service 30b792
setup(
Packit Service 30b792
    name='gpg',
Packit Service 30b792
    cmdclass={'build': BuildExtFirstHack},
Packit Service 30b792
    version='@VERSION@',
Packit Service 30b792
    # Note: description appears as Summary in egg-info file.
Packit Service 30b792
    description='Python bindings to the GPGME API of the GnuPG cryptography library.',
Packit Service 30b792
    # Note: long-description appears as Description in egg-info file.
Packit Service 30b792
    long_description='''Dynamically generated bindings to the C API of the GNU Privacy Guard.
Packit Service 30b792
Packit Service 30b792
The GPG Made Easy (GPGME) library provides a high-level API in C to all the
Packit Service 30b792
component software and libraries in the GnuPG Project, including GPG itself
Packit Service 30b792
(the GnuPG OpenPGP implementation), libgcrypt, libgpg-error, libassuan and
Packit Service 30b792
more.
Packit Service 30b792
Packit Service 30b792
The official CPython bindings to GPGME are generated during the compiling
Packit Service 30b792
process of GPGME itself and built for the specific C header and include files
Packit Service 30b792
produced when GPGME is compiled using SWIG.  This provides access to over two
Packit Service 30b792
thousand functions, methods and values via both the lower level dynamically
Packit Service 30b792
generated bindings and a more intuitively pythonic higher level layer.
Packit Service 30b792
Packit Service 30b792
While the lower level, dynamically generated bindings provide access to
Packit Service 30b792
everything which GPGME itself provides; the higher level layer is easier to use
Packit Service 30b792
by Python developers, provides access to the vast majority of functionality
Packit Service 30b792
developers would want from GnuPG and is extensively documented.
Packit Service 30b792
Packit Service 30b792
GPGME and these bindings is available here:
Packit Service 30b792
Packit Service 30b792
    https://gnupg.org/software/gpgme/index.html
Packit Service 30b792
''',
Packit Service 30b792
    author='The GnuPG hackers',
Packit Service 30b792
    author_email='gnupg-devel@gnupg.org',
Packit Service 30b792
    url='https://www.gnupg.org',
Packit Service 30b792
    ext_modules=[swige],
Packit Service 30b792
    packages=[
Packit Service 30b792
        'gpg', 'gpg.constants', 'gpg.constants.data', 'gpg.constants.keylist',
Packit Service 30b792
        'gpg.constants.sig', 'gpg.constants.tofu'
Packit Service 30b792
    ],
Packit Service 30b792
    license='LGPL2.1+ (the library), GPL2+ (tests and examples)',
Packit Service 30b792
    classifiers=[
Packit Service 30b792
        'Development Status :: 4 - Beta',
Packit Service 30b792
        'Intended Audience :: Developers',
Packit Service 30b792
        'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)',
Packit Service 30b792
        'Programming Language :: Python :: 2',
Packit Service 30b792
        'Programming Language :: Python :: 2.7',
Packit Service 30b792
        'Programming Language :: Python :: 3',
Packit Service 30b792
        'Programming Language :: Python :: 3.4',
Packit Service 30b792
        'Programming Language :: Python :: 3.5',
Packit Service 30b792
        'Programming Language :: Python :: 3.6',
Packit Service 30b792
        'Programming Language :: Python :: 3.7',
Packit Service 30b792
        'Operating System :: POSIX',
Packit Service 30b792
        'Operating System :: Microsoft :: Windows',
Packit Service 30b792
        'Topic :: Communications :: Email',
Packit Service 30b792
        'Topic :: Security :: Cryptography',
Packit Service 30b792
    ],
Packit d7e8d0
)