setup.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. #! /usr/bin/env python
  2. #
  3. # setup.py : Distutils setup script
  4. #
  5. # Part of the Python Cryptography Toolkit
  6. #
  7. # ===================================================================
  8. # Portions Copyright (c) 2001, 2002, 2003 Python Software Foundation;
  9. # All Rights Reserved
  10. #
  11. # This file contains code from the Python 2.2 setup.py module (the
  12. # "Original Code"), with modifications made after it was incorporated
  13. # into PyCrypto (the "Modifications").
  14. #
  15. # To the best of our knowledge, the Python Software Foundation is the
  16. # copyright holder of the Original Code, and has licensed it under the
  17. # Python 2.2 license. See the file LEGAL/copy/LICENSE.python-2.2 for
  18. # details.
  19. #
  20. # The Modifications to this file are dedicated to the public domain.
  21. # To the extent that dedication to the public domain is not available,
  22. # everyone is granted a worldwide, perpetual, royalty-free,
  23. # non-exclusive license to exercise all rights associated with the
  24. # contents of this file for any purpose whatsoever. No rights are
  25. # reserved.
  26. #
  27. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  28. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  29. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  30. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  31. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  32. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  33. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  34. # SOFTWARE.
  35. # ===================================================================
  36. __revision__ = "$Id$"
  37. from distutils import core
  38. from distutils.ccompiler import new_compiler
  39. from distutils.core import Extension, Command
  40. from distutils.command.build import build
  41. from distutils.command.build_ext import build_ext
  42. import os, sys, re
  43. import struct
  44. if sys.version[0:1] == '1':
  45. raise RuntimeError ("The Python Cryptography Toolkit requires "
  46. "Python 2.x or 3.x to build.")
  47. if sys.platform == 'win32':
  48. HTONS_LIBS = ['ws2_32']
  49. plat_ext = [
  50. Extension("Crypto.Random.OSRNG.winrandom",
  51. libraries = HTONS_LIBS + ['advapi32'],
  52. include_dirs=['src/'],
  53. sources=["src/winrand.c"])
  54. ]
  55. else:
  56. HTONS_LIBS = []
  57. plat_ext = []
  58. # For test development: Set this to 1 to build with gcov support.
  59. # Use "gcov -p -o build/temp.*/src build/temp.*/src/*.gcda" to build the
  60. # .gcov files
  61. USE_GCOV = 0
  62. try:
  63. # Python 3
  64. from distutils.command.build_py import build_py_2to3 as build_py
  65. except ImportError:
  66. # Python 2
  67. from distutils.command.build_py import build_py
  68. # List of pure Python modules that will be excluded from the binary packages.
  69. # The list consists of (package, module_name) tuples
  70. if sys.version_info[0] == 2:
  71. EXCLUDE_PY = []
  72. else:
  73. EXCLUDE_PY = [
  74. # We don't want Py3k to choke on the 2.x compat code
  75. ('Crypto.Util', 'py21compat'),
  76. ]
  77. if sys.platform != "win32": # Avoid nt.py, as 2to3 can't fix it w/o winrandom
  78. EXCLUDE_PY += [('Crypto.Random.OSRNG','nt')]
  79. # Work around the print / print() issue with Python 2.x and 3.x. We only need
  80. # to print at one point of the code, which makes this easy
  81. def PrintErr(*args, **kwd):
  82. fout = kwd.get("file", sys.stderr)
  83. w = fout.write
  84. if args:
  85. w(str(args[0]))
  86. sep = kwd.get("sep", " ")
  87. for a in args[1:]:
  88. w(sep)
  89. w(str(a))
  90. w(kwd.get("end", "\n"))
  91. def endianness_macro():
  92. s = struct.pack("@I", 0x33221100)
  93. if s == "\x00\x11\x22\x33".encode(): # little endian
  94. return ('PCT_LITTLE_ENDIAN', 1)
  95. elif s == "\x33\x22\x11\x00".encode(): # big endian
  96. return ('PCT_BIG_ENDIAN', 1)
  97. raise AssertionError("Machine is neither little-endian nor big-endian")
  98. class PCTBuildExt (build_ext):
  99. def build_extensions(self):
  100. # Detect which modules should be compiled
  101. self.detect_modules()
  102. # Tweak compiler options
  103. if self.compiler.compiler_type in ('unix', 'cygwin', 'mingw32'):
  104. # Tell GCC to compile using the C99 standard.
  105. self.__add_compiler_option("-std=c99")
  106. # ... but don't tell that to the aCC compiler on HP-UX
  107. if self.compiler.compiler_so[0] == 'cc' and sys.platform.startswith('hp-ux'):
  108. self.__remove_compiler_option("-std=c99")
  109. # Make assert() statements always work
  110. self.__remove_compiler_option("-DNDEBUG")
  111. # Choose our own optimization options
  112. for opt in ["-O", "-O0", "-O1", "-O2", "-O3", "-Os"]:
  113. self.__remove_compiler_option(opt)
  114. if self.debug:
  115. # Basic optimization is still needed when debugging to compile
  116. # the libtomcrypt code.
  117. self.__add_compiler_option("-O")
  118. else:
  119. # Speed up execution by tweaking compiler options. This
  120. # especially helps the DES modules.
  121. self.__add_compiler_option("-O3")
  122. self.__add_compiler_option("-fomit-frame-pointer")
  123. # Don't include debug symbols unless debugging
  124. self.__remove_compiler_option("-g")
  125. # Don't include profiling information (incompatible with
  126. # -fomit-frame-pointer)
  127. self.__remove_compiler_option("-pg")
  128. if USE_GCOV:
  129. self.__add_compiler_option("-fprofile-arcs")
  130. self.__add_compiler_option("-ftest-coverage")
  131. self.compiler.libraries += ['gcov']
  132. # Call the superclass's build_extensions method
  133. build_ext.build_extensions(self)
  134. def detect_modules (self):
  135. # Read the config.h file (usually generated by autoconf)
  136. if self.compiler.compiler_type == 'msvc':
  137. # Add special include directory for MSVC (because MSVC is special)
  138. self.compiler.include_dirs.insert(0, "src/inc-msvc/")
  139. ac = self.__read_autoconf("src/inc-msvc/config.h")
  140. else:
  141. ac = self.__read_autoconf("src/config.h")
  142. # Detect libgmp or libmpir and don't build _fastmath if both are missing.
  143. if ac.get("HAVE_LIBGMP"):
  144. # Default; no changes needed
  145. pass
  146. elif ac.get("HAVE_LIBMPIR"):
  147. # Change library to libmpir if libgmp is missing
  148. self.__change_extension_lib(["Crypto.PublicKey._fastmath"],
  149. ['mpir'])
  150. # And if this is MSVC, we need to add a linker option
  151. # to make a static libmpir link well into a dynamic _fastmath
  152. if self.compiler.compiler_type == 'msvc':
  153. self.__add_extension_link_option(["Crypto.PublicKey._fastmath"],
  154. ["/NODEFAULTLIB:LIBCMT"])
  155. else:
  156. # No MP library; use _slowmath.
  157. PrintErr ("warning: GMP or MPIR library not found; Not building "+
  158. "Crypto.PublicKey._fastmath.")
  159. self.__remove_extensions(["Crypto.PublicKey._fastmath"])
  160. def __add_extension_link_option(self, names, options):
  161. """Add linker options for the specified extension(s)"""
  162. i = 0
  163. while i < len(self.extensions):
  164. if self.extensions[i].name in names:
  165. self.extensions[i].extra_link_args = options
  166. i += 1
  167. def __change_extension_lib(self, names, libs):
  168. """Change the libraries to be used for the specified extension(s)"""
  169. i = 0
  170. while i < len(self.extensions):
  171. if self.extensions[i].name in names:
  172. self.extensions[i].libraries = libs
  173. i += 1
  174. def __remove_extensions(self, names):
  175. """Remove the specified extension(s) from the list of extensions
  176. to build"""
  177. i = 0
  178. while i < len(self.extensions):
  179. if self.extensions[i].name in names:
  180. del self.extensions[i]
  181. continue
  182. i += 1
  183. def __remove_compiler_option(self, option):
  184. """Remove the specified compiler option.
  185. Return true if the option was found. Return false otherwise.
  186. """
  187. found = 0
  188. for attrname in ('compiler', 'compiler_so'):
  189. compiler = getattr(self.compiler, attrname, None)
  190. if compiler is not None:
  191. while option in compiler:
  192. compiler.remove(option)
  193. found += 1
  194. return found
  195. def __add_compiler_option(self, option):
  196. for attrname in ('compiler', 'compiler_so'):
  197. compiler = getattr(self.compiler, attrname, None)
  198. if compiler is not None:
  199. compiler.append(option)
  200. def __read_autoconf(self, filename):
  201. rx_define = re.compile(r"""^#define (\S+) (?:(\d+)|(".*"))$""")
  202. result = {}
  203. f = open(filename, "r")
  204. try:
  205. config_lines = f.read().replace("\r\n", "\n").split("\n")
  206. for line in config_lines:
  207. m = rx_define.search(line)
  208. if not m: continue
  209. sym = m.group(1)
  210. n = m.group(2)
  211. s = m.group(3)
  212. if n:
  213. result[sym] = int(n)
  214. elif s:
  215. result[sym] = eval(s) # XXX - hack to unescape C-style string
  216. else:
  217. continue
  218. finally:
  219. f.close()
  220. return result
  221. def run(self):
  222. for cmd_name in self.get_sub_commands():
  223. self.run_command(cmd_name)
  224. build_ext.run(self)
  225. def has_configure(self):
  226. compiler = new_compiler(compiler=self.compiler)
  227. return compiler.compiler_type != 'msvc'
  228. sub_commands = [ ('build_configure', has_configure) ] + build_ext.sub_commands
  229. class PCTBuildConfigure(Command):
  230. description = "Generate config.h using ./configure (autoconf)"
  231. def initialize_options(self):
  232. pass
  233. def finalize_options(self):
  234. pass
  235. def run(self):
  236. if not os.path.exists("config.status"):
  237. if os.system("chmod 0755 configure") != 0:
  238. raise RuntimeError("chmod error")
  239. cmd = "sh configure" # we use "sh" here so that it'll work on mingw32 with standard python.org binaries
  240. if self.verbose < 1:
  241. cmd += " -q"
  242. if os.system(cmd) != 0:
  243. raise RuntimeError("autoconf error")
  244. class PCTBuildPy(build_py):
  245. def find_package_modules(self, package, package_dir, *args, **kwargs):
  246. modules = build_py.find_package_modules(self, package, package_dir,
  247. *args, **kwargs)
  248. # Exclude certain modules
  249. retval = []
  250. for item in modules:
  251. pkg, module = item[:2]
  252. if (pkg, module) in EXCLUDE_PY:
  253. continue
  254. retval.append(item)
  255. return retval
  256. class TestCommand(Command):
  257. description = "Run self-test"
  258. # Long option name, short option name, description
  259. user_options = [
  260. ('skip-slow-tests', None,
  261. 'Skip slow tests'),
  262. ('module=', 'm', 'Test a single module (e.g. Cipher, PublicKey)')
  263. ]
  264. def initialize_options(self):
  265. self.build_dir = None
  266. self.skip_slow_tests = None
  267. self.module = None
  268. def finalize_options(self):
  269. self.set_undefined_options('install', ('build_lib', 'build_dir'))
  270. self.config = {'slow_tests': not self.skip_slow_tests}
  271. def run(self):
  272. # Run SelfTest
  273. self.announce("running self-tests")
  274. old_path = sys.path[:]
  275. try:
  276. sys.path.insert(0, self.build_dir)
  277. from Crypto import SelfTest
  278. moduleObj = None
  279. if self.module:
  280. if self.module.count('.')==0:
  281. # Test a whole a sub-package
  282. full_module = "Crypto.SelfTest." + self.module
  283. module_name = self.module
  284. else:
  285. # Test only a module
  286. # Assume only one dot is present
  287. comps = self.module.split('.')
  288. module_name = "test_" + comps[1]
  289. full_module = "Crypto.SelfTest." + comps[0] + "." + module_name
  290. # Import sub-package or module
  291. moduleObj = __import__( full_module, globals(), locals(), module_name )
  292. SelfTest.run(module=moduleObj, verbosity=self.verbose, stream=sys.stdout, config=self.config)
  293. finally:
  294. # Restore sys.path
  295. sys.path[:] = old_path
  296. # Run slower self-tests
  297. self.announce("running extended self-tests")
  298. kw = {'name':"pycrypto",
  299. 'version':"2.6.1", # See also: lib/Crypto/__init__.py
  300. 'description':"Cryptographic modules for Python.",
  301. 'author':"Dwayne C. Litzenberger",
  302. 'author_email':"dlitz@dlitz.net",
  303. 'url':"http://www.pycrypto.org/",
  304. 'cmdclass' : {'build_configure': PCTBuildConfigure, 'build_ext': PCTBuildExt, 'build_py': PCTBuildPy, 'test': TestCommand },
  305. 'packages' : ["Crypto", "Crypto.Hash", "Crypto.Cipher", "Crypto.Util",
  306. "Crypto.Random",
  307. "Crypto.Random.Fortuna",
  308. "Crypto.Random.OSRNG",
  309. "Crypto.SelfTest",
  310. "Crypto.SelfTest.Cipher",
  311. "Crypto.SelfTest.Hash",
  312. "Crypto.SelfTest.Protocol",
  313. "Crypto.SelfTest.PublicKey",
  314. "Crypto.SelfTest.Random",
  315. "Crypto.SelfTest.Random.Fortuna",
  316. "Crypto.SelfTest.Random.OSRNG",
  317. "Crypto.SelfTest.Util",
  318. "Crypto.SelfTest.Signature",
  319. "Crypto.Protocol",
  320. "Crypto.PublicKey",
  321. "Crypto.Signature"],
  322. 'package_dir' : { "Crypto": "lib/Crypto" },
  323. 'ext_modules': plat_ext + [
  324. # _fastmath (uses GNU mp library)
  325. Extension("Crypto.PublicKey._fastmath",
  326. include_dirs=['src/','/usr/include/'],
  327. libraries=['gmp'],
  328. sources=["src/_fastmath.c"]),
  329. # Hash functions
  330. Extension("Crypto.Hash._MD2",
  331. include_dirs=['src/'],
  332. sources=["src/MD2.c"]),
  333. Extension("Crypto.Hash._MD4",
  334. include_dirs=['src/'],
  335. sources=["src/MD4.c"]),
  336. Extension("Crypto.Hash._SHA256",
  337. include_dirs=['src/'],
  338. sources=["src/SHA256.c"]),
  339. Extension("Crypto.Hash._SHA224",
  340. include_dirs=['src/'],
  341. sources=["src/SHA224.c"]),
  342. Extension("Crypto.Hash._SHA384",
  343. include_dirs=['src/'],
  344. sources=["src/SHA384.c"]),
  345. Extension("Crypto.Hash._SHA512",
  346. include_dirs=['src/'],
  347. sources=["src/SHA512.c"]),
  348. Extension("Crypto.Hash._RIPEMD160",
  349. include_dirs=['src/'],
  350. sources=["src/RIPEMD160.c"],
  351. define_macros=[endianness_macro()]),
  352. # Block encryption algorithms
  353. Extension("Crypto.Cipher._AES",
  354. include_dirs=['src/'],
  355. sources=["src/AES.c"]),
  356. Extension("Crypto.Cipher._ARC2",
  357. include_dirs=['src/'],
  358. sources=["src/ARC2.c"]),
  359. Extension("Crypto.Cipher._Blowfish",
  360. include_dirs=['src/'],
  361. sources=["src/Blowfish.c"]),
  362. Extension("Crypto.Cipher._CAST",
  363. include_dirs=['src/'],
  364. sources=["src/CAST.c"]),
  365. Extension("Crypto.Cipher._DES",
  366. include_dirs=['src/', 'src/libtom/'],
  367. sources=["src/DES.c"]),
  368. Extension("Crypto.Cipher._DES3",
  369. include_dirs=['src/', 'src/libtom/'],
  370. sources=["src/DES3.c"]),
  371. # Stream ciphers
  372. Extension("Crypto.Cipher._ARC4",
  373. include_dirs=['src/'],
  374. sources=["src/ARC4.c"]),
  375. Extension("Crypto.Cipher._XOR",
  376. include_dirs=['src/'],
  377. sources=["src/XOR.c"]),
  378. # Utility modules
  379. Extension("Crypto.Util.strxor",
  380. include_dirs=['src/'],
  381. sources=['src/strxor.c']),
  382. # Counter modules
  383. Extension("Crypto.Util._counter",
  384. include_dirs=['src/'],
  385. sources=['src/_counter.c']),
  386. ]
  387. }
  388. # If we're running Python 2.3, add extra information
  389. if hasattr(core, 'setup_keywords'):
  390. if 'classifiers' in core.setup_keywords:
  391. kw['classifiers'] = [
  392. 'Development Status :: 5 - Production/Stable',
  393. 'License :: Public Domain',
  394. 'Intended Audience :: Developers',
  395. 'Operating System :: Unix',
  396. 'Operating System :: Microsoft :: Windows',
  397. 'Operating System :: MacOS :: MacOS X',
  398. 'Topic :: Security :: Cryptography',
  399. 'Programming Language :: Python :: 2',
  400. 'Programming Language :: Python :: 3',
  401. ]
  402. core.setup(**kw)
  403. def touch(path):
  404. import os, time
  405. now = time.time()
  406. try:
  407. # assume it's there
  408. os.utime(path, (now, now))
  409. except os.error:
  410. PrintErr("Failed to update timestamp of "+path)
  411. # PY3K: Workaround for winrandom.pyd not existing during the first pass.
  412. # It needs to be there for 2to3 to fix the import in nt.py
  413. if (sys.platform == 'win32' and sys.version_info[0] == 3 and
  414. 'build' in sys.argv[1:]):
  415. PrintErr("\nSecond pass to allow 2to3 to fix nt.py. No cause for alarm.\n")
  416. touch("./lib/Crypto/Random/OSRNG/nt.py")
  417. core.setup(**kw)