p≡p for Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
11 KiB

  1. # -*- coding: utf-8 -*-
  2. # This file is under GNU Affero General Public License 3.0
  3. # see LICENSE.txt
  4. from __future__ import print_function
  5. import sys
  6. from sys import argv
  7. import os
  8. from os import environ, uname
  9. from os.path import dirname, exists, join
  10. from setuptools import setup, Extension
  11. from glob import glob
  12. import sysconfig
  13. if sys.platform == 'winnt':
  14. if sys.version_info[0] >= 3:
  15. import winreg
  16. else:
  17. import _winreg as winreg
  18. from setuptools.command.build_ext import build_ext
  19. if sys.version_info[0] < 3:
  20. FileNotFoundError = EnvironmentError
  21. def find(fname, pathlist):
  22. for path in pathlist:
  23. cand_fname = join(path, fname)
  24. if exists(cand_fname):
  25. return path
  26. raise FileNotFoundError(fname)
  27. def append_once(lst, element):
  28. if element not in lst:
  29. lst.append(element)
  30. def extend_once(lst, elements):
  31. for element in elements:
  32. if element not in lst:
  33. lst.append(element)
  34. def getPythonLibver():
  35. g = sysconfig.get_config_vars()
  36. sent = []
  37. for template in (
  38. '{cmd}{py_version_nodot}{abiflags}',
  39. '{cmd}{py_version_nodot}',
  40. '{cmd}{py_version_major}',
  41. '{cmd}{py_version_major}{abiflags}',
  42. '{cmd}'
  43. ):
  44. val = template.format(
  45. cmd = g['PYTHON'],
  46. py_version_nodot = g['py_version_nodot'],
  47. py_version_major = sys.version_info[0],
  48. abiflags = g.get('ABIFLAGS', ''),
  49. )
  50. if val not in sent:
  51. yield val
  52. sent.append(val)
  53. class BuildExtCommand(build_ext):
  54. # default_pyver = next( getPythonLibver() )
  55. user_options = build_ext.user_options + [
  56. # ('boost-python=', None, 'Boost Python version to use (e.g. \'python34\')'),
  57. ('local', None, 'Use local pEp install in HOME/USERPROFILE'),
  58. ('with-pEp-engine=', None, 'Path to pEp Engine source'),
  59. ('with-pEp-libadapter=', None, 'Path to pEp C++ Adapter Library source'),
  60. ('with-boost=', None, 'Path to Boost install prefix'),
  61. ('with-asn1c-share=', None, 'Path to installed ASN1C share directory'),
  62. ]
  63. def windowsGetInstallLocation():
  64. # Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro
  65. # TODO: Try desktop adapter location first, then COM server
  66. # FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place)
  67. REG_PATH = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp"
  68. regKey = None
  69. try:
  70. regKey = winreg.OpenKey(
  71. winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ)
  72. # Keys: Description, FileName, FriendlyName, LoadBehavior
  73. com_server, regtype = winreg.QueryValueEx(regKey, 'FileName')
  74. winreg.CloseKey(regKey)
  75. except WindowsError:
  76. com_server = None
  77. finally:
  78. if winreg:
  79. winreg.CloseKey(regKey)
  80. # <install-base>\\bin\\COM_Server.exe
  81. dirname = os.path.dirname
  82. return dirname( dirname( com_server ) )
  83. def initialize_options(self):
  84. build_ext.initialize_options(self)
  85. # self.boost_python = BuildExtCommand.default_pyver
  86. self.local = None != environ.get('PER_USER_DIRECTORY')
  87. self.with_pEp_engine = None
  88. self.with_pEp_libadapter = None
  89. self.with_boost = None
  90. self.with_asn1c_share = None
  91. def finalize_options(self):
  92. build_ext.finalize_options(self)
  93. # normalize paths given by user (expand tilde etc.)
  94. for with_option in ('pEp_engine', 'pEp_libadapter', 'boost', 'asn1c_share'):
  95. w_opt = 'with_' + with_option
  96. w_val = getattr(self, w_opt)
  97. if w_val != None:
  98. setattr(self, w_opt, os.path.normpath(w_val))
  99. if sys.platform == 'darwin':
  100. HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
  101. PEPLIBNAME = 'libpEpEngine.dylib'
  102. LIBPEPA = 'libpEpAdapter.a'
  103. BOOSTLIBNAME = 'libboost_{boost_python:s}-mt.dylib'
  104. SYS_INCLUDES = [
  105. '/opt/local/include', # we prefer MacPorts over Homebrew (but support both)
  106. '/usr/local/include',
  107. '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include',
  108. join(environ["HOME"], 'include'),
  109. '/usr/include',
  110. ]
  111. SYS_SHARES = [
  112. '/opt/local/share',
  113. '/usr/local/share',
  114. '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/share',
  115. join(environ["HOME"], 'share'),
  116. '/usr/share',
  117. ]
  118. SYS_LIB_PREFIXES = [
  119. '/opt/local/lib',
  120. '/usr/local/lib',
  121. '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib',
  122. join(environ["HOME"], 'lib'),
  123. '/usr/lib',
  124. ]
  125. elif sys.platform == 'winnt':
  126. HOME = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE')
  127. SYS_ROOT = environ.get('SystemRoot')
  128. PROFILE_ROOT = environ.get('AppData')
  129. LOCAL_ROOT = environ.get('LocalAppData')
  130. INST_PREFIX = windowsGetInstallLocation()
  131. PEPLIBNAME = 'pEpEngine.dll'
  132. LIBPEPA = 'libpEpAdapter.a'
  133. BOOSTLIBNAME = 'boost_{boost_python:s}-mt.dll'
  134. SYS_INCLUDES = [
  135. join(INST_PREFIX, 'include'),
  136. join(PROFILE_ROOT, 'pEp', 'include'),
  137. join(LOCAL_ROOT, 'pEp', 'include'),
  138. join(SYS_ROOT, 'pEp', 'include'),
  139. ]
  140. SYS_SHARES = [
  141. join(INST_PREFIX, 'share'),
  142. join(PROFILE_ROOT, 'pEp', 'share'),
  143. join(LOCAL_ROOT, 'pEp', 'share'),
  144. join(SYS_ROOT, 'pEp', 'share'),
  145. ]
  146. SYS_LIB_PREFIXES = [
  147. join(INST_PREFIX, 'bin'),
  148. join(PROFILE_ROOT, 'pEp', 'bin'),
  149. join(LOCAL_ROOT, 'pEp', 'bin'),
  150. join(SYS_ROOT, 'pEp', 'bin'),
  151. ]
  152. else:
  153. HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
  154. PEPLIBNAME = 'libpEpEngine.so'
  155. LIBPEPA = 'libpEpAdapter.a'
  156. BOOSTLIBNAME = 'libboost_python37.so'
  157. SYS_INCLUDES = ['/usr/local/pEp/include', '/usr/local/include', '/usr/include']
  158. SYS_SHARES = ['/usr/local/pEp/share', '/usr/local/share', '/usr/share']
  159. SYS_LIB_PREFIXES = ['/usr/local/pEp/bin', '/usr/local/bin', '/usr/bin', '/usr/lib/x86_64-linux-gnu/', '/usr/lib/i386-linux-gnu/']
  160. use_local_incl = (self.local or os.path.isfile(
  161. join(HOME, 'include', 'pEp', 'pEpEngine.h')) )
  162. use_local_lib = (self.local or os.path.isfile(
  163. join(HOME, 'lib', PEPLIBNAME)) )
  164. INCLUDES = [ join(HOME, 'include') ] if use_local_incl else []
  165. INCLUDES.extend(SYS_INCLUDES)
  166. SHARES = [ join(HOME, 'share') ] if use_local_incl else []
  167. SHARES.extend(SYS_SHARES)
  168. LIBS = [ join(HOME, 'lib') ] if use_local_lib else []
  169. LIBS.extend(SYS_LIB_PREFIXES)
  170. if not self.with_pEp_engine:
  171. ENGINE_INC = find( join('pEp', 'pEpEngine.h'), INCLUDES )
  172. ENGINE_LIB = find( PEPLIBNAME, LIBS )
  173. else:
  174. if exists( join(self.with_pEp_engine, 'include', 'pEp') ):
  175. ENGINE_INC = find( join('pEp', 'pEpEngine.h'), (join(self.with_pEp_engine, 'include'),) )
  176. ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'lib'),) )
  177. else:
  178. ENGINE_INC = find( 'pEpEngine.h', (join(self.with_pEp_engine, 'src'),) )
  179. ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'src'),) )
  180. if not self.with_pEp_libadapter:
  181. LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), INCLUDES )
  182. LIBPEPA_LIB = find( LIBPEPA, LIBS )
  183. else:
  184. if exists( join(self.with_pEp_libadapter, 'include', 'pEp') ):
  185. LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), (join(self.with_pEp_libadapter, 'include'),) )
  186. LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'lib'),) )
  187. else:
  188. LIBPEPA_INC = find( 'Adapter.hh', (join(self.with_pEp_libadapter, 'src'),) )
  189. LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'src'),) )
  190. if not self.with_boost:
  191. BOOST_INC = find( join('boost', 'system', 'config.hpp'), INCLUDES )
  192. BOOST_LIB = None
  193. e_ = None
  194. for py in getPythonLibver():
  195. f = BOOSTLIBNAME.format(boost_python=py)
  196. try:
  197. BOOST_LIB = find( f, LIBS )
  198. break
  199. except Exception as e:
  200. if self.verbose:
  201. print("Not found: " + f)
  202. e_ = e if e_ is None else e_
  203. if BOOST_LIB is None:
  204. raise e_
  205. else:
  206. raise NotImplementedError("Building from Boost source not implemented yet") # FIXME
  207. # BOOST_INC = find( join('boost', 'system', 'config.hpp'), (self.with_boost,) )
  208. # BOOST_LIB = find( BOOSTLIBNAME, (self.with_boost,) )
  209. if not self.with_asn1c_share:
  210. ASN1C_INC = find( join('asn1c', 'asn_system.h'), SHARES )
  211. else:
  212. ASN1C_INC = find( join('asn1c', 'asn_system.h'), (self.with_asn1c_share,) )
  213. if self.verbose:
  214. print('ENGINE_INC=%s' % ENGINE_INC)
  215. print('ENGINE_LIB=%s' % ENGINE_LIB)
  216. print('LIBPEPA_INC=%s' % LIBPEPA_INC)
  217. print('LIBPEPA_LIB=%s' % LIBPEPA_LIB)
  218. print('BOOST_INC=%s' % BOOST_INC)
  219. print('BOOST_LIB=%s' % BOOST_LIB)
  220. print('ASN1C_INC=%s' % ASN1C_INC)
  221. global module_pEp
  222. extend_once( module_pEp.include_dirs, [ENGINE_INC, LIBPEPA_INC, BOOST_INC, ASN1C_INC] )
  223. extend_once( module_pEp.library_dirs, [ENGINE_LIB, LIBPEPA_LIB, BOOST_LIB] )
  224. extend_once( module_pEp.libraries, ['pEpEngine', 'boost_python3', 'boost_locale'] )
  225. if self.debug:
  226. module_pEp.extra_compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14']
  227. else:
  228. module_pEp.extra_compile_args = ['-std=c++14'] # FIXME
  229. def run(self):
  230. build_ext.run(self)
  231. # module_pEp global is referenced in BuildExtCommand
  232. module_pEp = Extension('pEp',
  233. sources = glob('src/*.cc'),
  234. libraries = ['pEpEngine'],
  235. # extra_compile_args = compile_args,
  236. # include_dirs = [ENGINE_INC, BOOST_INC, ASN1C_INC],
  237. # library_dirs = [ENGINE_LIB, BOOST_LIB],
  238. )
  239. setup(
  240. name='pEp',
  241. version='2.0',
  242. description='p≡p for Python',
  243. author="Volker Birk",
  244. author_email="vb@pep-project.org",
  245. ext_modules=[module_pEp,],
  246. cmdclass={
  247. 'build_ext': BuildExtCommand,
  248. },
  249. )