Browse Source

Complete overhaul of setup.py, README.md build and install instructions

- now works for linux, mac, (win to be tested)
- Removed a lot of unnecessary code and complexity
- Added logging
sync
heck 2 years ago
parent
commit
d409cfacb5
2 changed files with 211 additions and 229 deletions
  1. +36
    -6
      README.md
  2. +175
    -223
      setup.py

+ 36
- 6
README.md View File

@ -1,11 +1,41 @@
There's a setup.py in pEpPythonAdapter/
# pEpPythonAdapter
In Python we've setup tools, so it's:
## Build Insttructions
python3 setup.py build
python3 setup.py install
These build instructions should work on:
* Linux
* MacOS
* Windows
### Build
To build against system wide pEp installation (libs/includes)
```bash
python3 setup.py build_ext
```
To build against a pEp installation in your home dir (libs/includes):
```bash
python3 setup.py build_ext --local
```
That is a Python concept. You can find more about it here:
To build against a pEp installation in a custom installation root (libs/includes)
```bash
python3 setup.py build_ext --prefix=<path_to_your_install_root>
```
### Install
To install the extension module system wide, as root, run:
```bash
python3 setup.py install
```
https://docs.python.org/3/extending/building.html#building-c-and-c-extensions-with-distutils
To install the extension module into you home dir
```bash
python3 setup.py install --user
```
To install the extension module into a custom destination
```bash
python3 setup.py install --prefix=<custom_destination_root>
```

+ 175
- 223
setup.py View File

@ -1,284 +1,236 @@
# -*- coding: utf-8 -*-
# This file is under GNU Affero General Public License 3.0
# see LICENSE.txt
#
# For more debugging, export DISTUTILS_DEBUG=True
from __future__ import print_function
import sys
from sys import argv
import os
from os import environ
from os.path import dirname, exists, join
from os.path import join
import platform
from setuptools import setup, Extension
from glob import glob
import sysconfig
if sys.platform == 'winnt':
if sys.version_info[0] >= 3:
import winreg
else:
import _winreg as winreg
from setuptools.command.build_ext import build_ext
verboseLevel = 0
if sys.version_info[0] < 3:
FileNotFoundError = EnvironmentError
def find(fname, pathlist):
for path in pathlist:
cand_fname = join(path, fname)
if exists(cand_fname):
return path
raise FileNotFoundError(fname)
def append_once(lst, element):
if element not in lst:
lst.append(element)
def extend_once(lst, elements):
for element in elements:
if element not in lst:
lst.append(element)
def getPythonLibver():
g = sysconfig.get_config_vars()
sent = []
for template in (
'{cmd}{py_version_nodot}{abiflags}',
'{cmd}{py_version_nodot}',
'{cmd}{py_version_major}',
'{cmd}{py_version_major}{abiflags}',
'{cmd}'
):
val = template.format(
cmd = g['PYTHON'],
py_version_nodot = g['py_version_nodot'],
py_version_major = sys.version_info[0],
abiflags = g.get('ABIFLAGS', ''),
)
if val not in sent:
yield val
sent.append(val)
def pEpLog(*msg):
if verboseLevel > 0:
import inspect
msgstr = ''
separator = ' '
for m in msg:
msgstr += str(m)
msgstr += separator
func = inspect.currentframe().f_back.f_code
print(func.co_filename + " : " + func.co_name + " : " + msgstr)
class BuildExtCommand(build_ext):
# default_pyver = next( getPythonLibver() )
user_options = build_ext.user_options + [
# ('boost-python=', None, 'Boost Python version to use (e.g. \'python34\')'),
('local', None, 'Use local pEp install in HOME/USERPROFILE'),
('with-pEp-engine=', None, 'Path to pEp Engine source'),
('with-pEp-libadapter=', None, 'Path to pEp C++ Adapter Library source'),
('with-boost=', None, 'Path to Boost install prefix'),
('with-asn1c-share=', None, 'Path to installed ASN1C share directory'),
('local', None, 'Use local pEp install in HOME/USERPROFILE for libs/includes'),
('prefix=', None, 'Use local pEp install in prefix for libs/includes'),
]
def windowsGetInstallLocation():
def initialize_options(self):
pEpLog("called")
build_ext.initialize_options(self)
self.local = None != environ.get('PER_USER_DIRECTORY')
self.prefix = getattr(self, "prefix=", None)
def windowsGetInstallLocation(self):
pEpLog("called")
# Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro
# TODO: Try desktop adapter location first, then COM server
# FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place)
REG_PATH = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp"
reg_path = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp"
KeyName = 'FileName'
regKey = None
pEpLog("Registry Lookup:", reg_path, KeyName)
try:
regKey = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ)
regKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_READ)
# Keys: Description, FileName, FriendlyName, LoadBehavior
com_server, regtype = winreg.QueryValueEx(regKey, 'FileName')
com_server, regtype = winreg.QueryValueEx(regKey, KeyName)
winreg.CloseKey(regKey)
except WindowsError:
pEpLog("Unknown Error")
com_server = None
finally:
if winreg:
winreg.CloseKey(regKey)
# <install-base>\\bin\\COM_Server.exe
dirname = os.path.dirname
return dirname( dirname( com_server ) )
def initialize_options(self):
build_ext.initialize_options(self)
# self.boost_python = BuildExtCommand.default_pyver
self.local = None != environ.get('PER_USER_DIRECTORY')
self.with_pEp_engine = None
self.with_pEp_libadapter = None
self.with_boost = None
self.with_asn1c_share = None
ret = dirname(dirname(com_server))
pEpLog("Value:", ret)
return ret
def get_build_info_winnt(self):
home = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE')
sys_root = environ.get('SystemRoot')
profile_root = environ.get('AppData')
local_root = environ.get('LocalAppData')
inst_prefix = self.windowsGetInstallLocation()
sys_includes = [
join(inst_prefix, 'include'),
join(profile_root, 'pEp', 'include'),
join(local_root, 'pEp', 'include'),
join(sys_root, 'pEp', 'include'),
]
sys_libdirs = [
join(inst_prefix, 'bin'),
join(profile_root, 'pEp', 'bin'),
join(local_root, 'pEp', 'bin'),
join(sys_root, 'pEp', 'bin'),
]
libs = [
'pEpEngine',
'boost_python37-mt',
'boost_locale-mt'
]
return (home, sys_includes, sys_libdirs, libs)
def get_build_info_darwin(self):
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
sys_includes = [
'/opt/local/include',
'/usr/local/include',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include',
'/usr/include',
]
sys_libdirs = [
'/opt/local/lib',
'/usr/local/lib',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib',
'/usr/lib',
]
libs = [
'pEpEngine',
'boost_python37-mt',
'boost_locale-mt'
]
return (home, sys_includes, sys_libdirs, libs)
def get_build_info_linux(self):
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
sys_includes = [
'/usr/local/include',
'/usr/include',
]
sys_libdirs = [
'/usr/local/lib',
'/usr/lib',
'/usr/lib/{}-linux-gnu'.format(platform.machine())
]
libs = [
'pEpEngine',
'boost_python3',
'boost_locale'
]
return (home, sys_includes, sys_libdirs, libs)
def finalize_options(self):
pEpLog("called")
build_ext.finalize_options(self)
# normalize paths given by user (expand tilde etc.)
for with_option in ('pEp_engine', 'pEp_libadapter', 'boost', 'asn1c_share'):
w_opt = 'with_' + with_option
w_val = getattr(self, w_opt)
if w_val != None:
setattr(self, w_opt, os.path.normpath(w_val))
if sys.platform == 'darwin':
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
PEPLIBNAME = 'libpEpEngine.dylib'
LIBPEPA = 'libpEpAdapter.a'
BOOSTLIBNAME = 'libboost_{boost_python:s}-mt.dylib'
SYS_INCLUDES = [
'/opt/local/include', # we prefer MacPorts over Homebrew (but support both)
'/usr/local/include',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include',
join(environ["HOME"], 'include'),
'/usr/include',
]
SYS_SHARES = [
'/opt/local/share',
'/usr/local/share',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/share',
join(environ["HOME"], 'share'),
'/usr/share',
]
SYS_LIB_PREFIXES = [
'/opt/local/lib',
'/usr/local/lib',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib',
join(environ["HOME"], 'lib'),
'/usr/lib',
]
elif sys.platform == 'winnt':
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE')
SYS_ROOT = environ.get('SystemRoot')
PROFILE_ROOT = environ.get('AppData')
LOCAL_ROOT = environ.get('LocalAppData')
INST_PREFIX = windowsGetInstallLocation()
PEPLIBNAME = 'pEpEngine.dll'
LIBPEPA = 'libpEpAdapter.a'
BOOSTLIBNAME = 'boost_{boost_python:s}-mt.dll'
SYS_INCLUDES = [
join(INST_PREFIX, 'include'),
join(PROFILE_ROOT, 'pEp', 'include'),
join(LOCAL_ROOT, 'pEp', 'include'),
join(SYS_ROOT, 'pEp', 'include'),
]
SYS_SHARES = [
join(INST_PREFIX, 'share'),
join(PROFILE_ROOT, 'pEp', 'share'),
join(LOCAL_ROOT, 'pEp', 'share'),
join(SYS_ROOT, 'pEp', 'share'),
]
SYS_LIB_PREFIXES = [
join(INST_PREFIX, 'bin'),
join(PROFILE_ROOT, 'pEp', 'bin'),
join(LOCAL_ROOT, 'pEp', 'bin'),
join(SYS_ROOT, 'pEp', 'bin'),
]
pEpLog("verbose: ", self.verbose)
pEpLog("local: ", self.local)
pEpLog("prefix: ", self.prefix)
pEpLog("sys.platform: ", sys.platform)
global verboseLevel
verboseLevel = self.verbose
# get build information for platform
if sys.platform == 'winnt':
build_info = self.get_build_info_winnt()
elif sys.platform == 'darwin':
build_info = self.get_build_info_darwin()
elif sys.platform == 'linux':
build_info = self.get_build_info_linux()
else:
HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
PEPLIBNAME = 'pEpEngine.so'
LIBPEPA = 'libpEpAdapter.a'
BOOSTLIBNAME = 'boost_{boost_python:s}-mt.so'
SYS_INCLUDES = ['/usr/local/pEp/include', '/usr/local/include', '/usr/include']
SYS_SHARES = ['/usr/local/pEp/share', '/usr/local/share', '/usr/share']
SYS_LIB_PREFIXES = ['/usr/local/pEp/bin', '/usr/local/bin', '/usr/bin']
use_local_incl = (self.local or os.path.isfile(
join(HOME, 'include', 'pEp', 'pEpEngine.h')) )
use_local_lib = (self.local or os.path.isfile(
join(HOME, 'lib', PEPLIBNAME)) )
INCLUDES = [ join(HOME, 'include') ] if use_local_incl else []
INCLUDES.extend(SYS_INCLUDES)
SHARES = [ join(HOME, 'share') ] if use_local_incl else []
SHARES.extend(SYS_SHARES)
LIBS = [ join(HOME, 'lib') ] if use_local_lib else []
LIBS.extend(SYS_LIB_PREFIXES)
if not self.with_pEp_engine:
ENGINE_INC = find( join('pEp', 'pEpEngine.h'), INCLUDES )
ENGINE_LIB = find( PEPLIBNAME, LIBS )
else:
if exists( join(self.with_pEp_engine, 'include', 'pEp') ):
ENGINE_INC = find( join('pEp', 'pEpEngine.h'), (join(self.with_pEp_engine, 'include'),) )
ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'lib'),) )
else:
ENGINE_INC = find( 'pEpEngine.h', (join(self.with_pEp_engine, 'src'),) )
ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'src'),) )
if not self.with_pEp_libadapter:
LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), INCLUDES )
LIBPEPA_LIB = find( LIBPEPA, LIBS )
else:
if exists( join(self.with_pEp_libadapter, 'include', 'pEp') ):
LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), (join(self.with_pEp_libadapter, 'include'),) )
LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'lib'),) )
else:
LIBPEPA_INC = find( 'Adapter.hh', (join(self.with_pEp_libadapter, 'src'),) )
LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'src'),) )
if not self.with_boost:
BOOST_INC = find( join('boost', 'system', 'config.hpp'), INCLUDES )
BOOST_LIB = None
e_ = None
for py in getPythonLibver():
f = BOOSTLIBNAME.format(boost_python=py)
try:
BOOST_LIB = find( f, LIBS )
break
except Exception as e:
if self.verbose:
print("Not found: " + f)
e_ = e if e_ is None else e_
if BOOST_LIB is None:
raise e_
else:
raise NotImplementedError("Building from Boost source not implemented yet") # FIXME
# BOOST_INC = find( join('boost', 'system', 'config.hpp'), (self.with_boost,) )
# BOOST_LIB = find( BOOSTLIBNAME, (self.with_boost,) )
if not self.with_asn1c_share:
ASN1C_INC = find( join('asn1c', 'asn_system.h'), SHARES )
else:
ASN1C_INC = find( join('asn1c', 'asn_system.h'), (self.with_asn1c_share,) )
if self.verbose:
print('ENGINE_INC=%s' % ENGINE_INC)
print('ENGINE_LIB=%s' % ENGINE_LIB)
print('LIBPEPA_INC=%s' % LIBPEPA_INC)
print('LIBPEPA_LIB=%s' % LIBPEPA_LIB)
print('BOOST_INC=%s' % BOOST_INC)
print('BOOST_LIB=%s' % BOOST_LIB)
print('ASN1C_INC=%s' % ASN1C_INC)
pEpLog("Platform not supported:" + sys.platform)
exit()
(home, sys_includes, sys_libdirs, libs) = build_info
# Build the Includes -I and Library paths -L
# Start empty
includes = []
libdirs = []
# Append home-dir
if self.local:
pEpLog("local mode")
home_include=[ join(home, 'include') ]
home_libdirs=[ join(home, 'lib') ]
includes += home_include
libdirs += home_libdirs
# Append prefix-dir
if self.prefix:
pEpLog("using prefix=",self.prefix)
prefix_include=[ join(self.prefix, 'include') ]
prefix_libdirs=[ join(self.prefix, 'lib') ]
includes += prefix_include
libdirs += prefix_libdirs
# Append default system dirs
includes += sys_includes
libdirs += sys_libdirs
# Compile flags
compile_flags = ['-std=c++14']
if self.debug:
pEpLog("debug mode")
compile_flags += ['-O0', '-g', '-UNDEBUG']
# Apply the build information
global module_pEp
extend_once( module_pEp.include_dirs, [ENGINE_INC, LIBPEPA_INC, BOOST_INC, ASN1C_INC] )
extend_once( module_pEp.library_dirs, [ENGINE_LIB, LIBPEPA_LIB, BOOST_LIB] )
extend_once( module_pEp.libraries, ['pEpEngine', 'boost_python37-mt', 'boost_locale-mt'] )
module_pEp.include_dirs = includes
module_pEp.library_dirs = libdirs
module_pEp.libraries = libs
module_pEp.extra_compile_args = compile_flags
if self.debug:
module_pEp.extra_compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14']
else:
module_pEp.extra_compile_args = ['-std=c++14'] # FIXME
pEpLog("Include Dirs:", module_pEp.include_dirs)
pEpLog("Libs Dirs:", module_pEp.library_dirs)
pEpLog("Libraries:", module_pEp.libraries)
pEpLog("Compile flags:", module_pEp.extra_compile_args)
def run(self):
build_ext.run(self)
# module_pEp global is referenced in BuildExtCommand
module_pEp = Extension('pEp',
sources = glob('src/*.cc'),
libraries = ['pEpEngine'],
# extra_compile_args = compile_args,
# include_dirs = [ENGINE_INC, BOOST_INC, ASN1C_INC],
# library_dirs = [ENGINE_LIB, BOOST_LIB],
)
if sys.platform == 'winnt':
if sys.version_info[0] >= 3:
import winreg
else:
import _winreg as winreg
if sys.version_info[0] < 3:
FileNotFoundError = EnvironmentError
module_pEp = Extension(
'pEp',
sources = glob('src/*.cc'),
)
# "MAIN" Function
setup(
name='pEp',
version='2.0',
description='p≡p for Python',
author="Volker Birk",
author_email="vb@pep-project.org",
ext_modules=[module_pEp,],
maintainer="Heck",
maintainer_email="heck@pep.foundation",
ext_modules=[module_pEp],
cmdclass={
'build_ext': BuildExtCommand,
},


Loading…
Cancel
Save