summaryrefslogtreecommitdiff
path: root/setup.py
diff options
context:
space:
mode:
authorLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-10-18 23:20:26 +0200
committerLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-10-18 23:20:26 +0200
commitc22fa18c0dedb43a8b19dcb9b29512ba59e1764b (patch)
treee7864a848ed2c37d4a2c0d65bcae0f0cbdc6ea27 /setup.py
parent897b75983c31a9e2630af92161e6206c2480685e (diff)
parentb9658a26003ebfcfce1804a2363a29354799b47e (diff)
downloadpycrypto-c22fa18c0dedb43a8b19dcb9b29512ba59e1764b.tar.gz
Merged from upstream (py3k support) and modified so that all unit tests pass.
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py205
1 files changed, 153 insertions, 52 deletions
diff --git a/setup.py b/setup.py
index eaaf2cc..cf258fa 100644
--- a/setup.py
+++ b/setup.py
@@ -37,16 +37,16 @@
__revision__ = "$Id$"
from distutils import core
+from distutils.ccompiler import new_compiler
from distutils.core import Extension, Command
+from distutils.command.build import build
from distutils.command.build_ext import build_ext
-import distutils
-import tempfile
-import os, sys
+import os, sys, re
import struct
if sys.version[0:1] == '1':
- raise RuntimeError, ("The Python Cryptography Toolkit requires "
- "Python 2.x to build.")
+ raise RuntimeError ("The Python Cryptography Toolkit requires "
+ "Python 2.x or 3.x to build.")
if sys.platform == 'win32':
HTONS_LIBS = ['ws2_32']
@@ -61,51 +61,49 @@ else:
plat_ext = []
# For test development: Set this to 1 to build with gcov support.
-# Use "gcov -p -o build/temp.*/src build/temp.*/src/*.gcda" to build the .gcov files
+# Use "gcov -p -o build/temp.*/src build/temp.*/src/*.gcda" to build the
+# .gcov files
USE_GCOV = 0
+
+try:
+ # Python 3
+ from distutils.command.build_py import build_py_2to3 as build_py
+except ImportError:
+ # Python 2
+ from distutils.command.build_py import build_py
+
# List of pure Python modules that will be excluded from the binary packages.
# The list consists of (package, module_name) tuples
-from distutils.command.build_py import build_py
-EXCLUDE_PY = []
-# ('Crypto.Hash', 'RIPEMD160'), # Included for your amusement, but the C version is much faster.
-#]
-
-def libgmp_exists():
- '''Verify that the compiler and the linker can reach libgmp'''
-
- fname = tempfile.mktemp(".c")
- oname = tempfile.mktemp(".out")
- f = open(fname, 'w')
- f.write("""
- #include <gmp.h>
-
- int main(void)
- {
- mpz_init((void*)0);
- return 0;
- }
- """)
- f.close()
-
- result = 1
- try:
- compiler = distutils.ccompiler.new_compiler()
- distutils.sysconfig.customize_compiler(compiler)
- objects = compiler.compile([fname])
- compiler.link_executable(objects, oname, libraries=('gmp',) )
- except Exception:
- result = 0
- for f in objects+[fname, oname]:
- try: os.remove(f)
- except Exception: pass
- return result
+if sys.version_info[0] == 2:
+ EXCLUDE_PY = []
+else:
+ EXCLUDE_PY = [
+ # We don't want Py3k to choke on the 2.x compat code
+ ('Crypto.Util', 'py21compat'),
+ ]
+ if sys.platform != "win32": # Avoid nt.py, as 2to3 can't fix it w/o winrandom
+ EXCLUDE_PY += [('Crypto.Random.OSRNG','nt')]
+
+# Work around the print / print() issue with Python 2.x and 3.x. We only need
+# to print at one point of the code, which makes this easy
+
+def PrintErr(*args, **kwd):
+ fout = kwd.get("file", sys.stderr)
+ w = fout.write
+ if args:
+ w(str(args[0]))
+ sep = kwd.get("sep", " ")
+ for a in args[1:]:
+ w(sep)
+ w(str(a))
+ w(kwd.get("end", "\n"))
def endianness_macro():
s = struct.pack("@I", 0x33221100)
- if s == "\x00\x11\x22\x33": # little endian
+ if s == "\x00\x11\x22\x33".encode(): # little endian
return ('PCT_LITTLE_ENDIAN', 1)
- elif s == "\x33\x22\x11\x00": # big endian
+ elif s == "\x33\x22\x11\x00".encode(): # big endian
return ('PCT_BIG_ENDIAN', 1)
raise AssertionError("Machine is neither little-endian nor big-endian")
@@ -136,7 +134,8 @@ class PCTBuildExt (build_ext):
self.__add_compiler_option("-fomit-frame-pointer")
# Don't include debug symbols unless debugging
self.__remove_compiler_option("-g")
- # Don't include profiling information (incompatible with -fomit-frame-pointer)
+ # Don't include profiling information (incompatible with
+ # -fomit-frame-pointer)
self.__remove_compiler_option("-pg")
if USE_GCOV:
self.__add_compiler_option("-fprofile-arcs")
@@ -147,17 +146,52 @@ class PCTBuildExt (build_ext):
build_ext.build_extensions(self)
def detect_modules (self):
- # Add special include directory for MSVC (because MSVC is special)
+ # Read the config.h file (usually generated by autoconf)
if self.compiler.compiler_type == 'msvc':
+ # Add special include directory for MSVC (because MSVC is special)
self.compiler.include_dirs.insert(0, "src/inc-msvc/")
-
- # Detect libgmp and don't build _fastmath if it is missing.
- if not libgmp_exists():
- print >>sys.stderr, "warning: GMP library not found; Not building Crypto.PublicKey._fastmath."
+ ac = self.__read_autoconf("src/inc-msvc/config.h")
+ else:
+ ac = self.__read_autoconf("src/config.h")
+
+ # Detect libgmp or libmpir and don't build _fastmath if both are missing.
+ if ac.get("HAVE_LIBGMP"):
+ # Default; no changes needed
+ pass
+ elif ac.get("HAVE_LIBMPIR"):
+ # Change library to libmpir if libgmp is missing
+ self.__change_extension_lib(["Crypto.PublicKey._fastmath"],
+ ['mpir'])
+ # And if this is MSVC, we need to add a linker option
+ # to make a static libmpir link well into a dynamic _fastmath
+ if self.compiler.compiler_type == 'msvc':
+ self.__add_extension_link_option(["Crypto.PublicKey._fastmath"],
+ ["/NODEFAULTLIB:LIBCMT"])
+ else:
+ # No MP library; use _slowmath.
+ PrintErr ("warning: GMP or MPIR library not found; Not building "+
+ "Crypto.PublicKey._fastmath.")
self.__remove_extensions(["Crypto.PublicKey._fastmath"])
+ def __add_extension_link_option(self, names, options):
+ """Add linker options for the specified extension(s)"""
+ i = 0
+ while i < len(self.extensions):
+ if self.extensions[i].name in names:
+ self.extensions[i].extra_link_args = options
+ i += 1
+
+ def __change_extension_lib(self, names, libs):
+ """Change the libraries to be used for the specified extension(s)"""
+ i = 0
+ while i < len(self.extensions):
+ if self.extensions[i].name in names:
+ self.extensions[i].libraries = libs
+ i += 1
+
def __remove_extensions(self, names):
- """Remove the specified extension from the list of extensions to build"""
+ """Remove the specified extension(s) from the list of extensions
+ to build"""
i = 0
while i < len(self.extensions):
if self.extensions[i].name in names:
@@ -185,9 +219,59 @@ class PCTBuildExt (build_ext):
if compiler is not None:
compiler.append(option)
+ def __read_autoconf(self, filename):
+ rx_define = re.compile(r"""^#define (\S+) (?:(\d+)|(".*"))$""")
+
+ result = {}
+ f = open(filename, "r")
+ try:
+ config_lines = f.read().replace("\r\n", "\n").split("\n")
+ for line in config_lines:
+ m = rx_define.search(line)
+ if not m: continue
+ sym = m.group(1)
+ n = m.group(2)
+ s = m.group(3)
+ if n:
+ result[sym] = int(n)
+ elif s:
+ result[sym] = eval(s) # XXX - hack to unescape C-style string
+ else:
+ continue
+ finally:
+ f.close()
+ return result
+
+class PCTBuild(build):
+ def has_configure(self):
+ compiler = new_compiler(compiler=self.compiler)
+ return compiler.compiler_type != 'msvc'
+
+ sub_commands = [ ('build_configure', has_configure) ] + build.sub_commands
+
+class PCTBuildConfigure(Command):
+ description = "Generate config.h using ./configure (autoconf)"
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ if not os.path.exists("config.status"):
+ if os.system("chmod 0755 configure") != 0:
+ raise RuntimeError("chmod error")
+ cmd = "sh configure" # we use "sh" here so that it'll work on mingw32 with standard python.org binaries
+ if self.verbose < 1:
+ cmd += " -q"
+ if os.system(cmd) != 0:
+ raise RuntimeError("autoconf error")
+
class PCTBuildPy(build_py):
def find_package_modules(self, package, package_dir, *args, **kwargs):
- modules = build_py.find_package_modules(self, package, package_dir, *args, **kwargs)
+ modules = build_py.find_package_modules(self, package, package_dir,
+ *args, **kwargs)
# Exclude certain modules
retval = []
@@ -198,6 +282,7 @@ class PCTBuildPy(build_py):
retval.append(item)
return retval
+
class TestCommand(Command):
description = "Run self-test"
@@ -254,7 +339,7 @@ kw = {'name':"pycrypto",
'author_email':"dlitz@dlitz.net",
'url':"http://www.pycrypto.org/",
- 'cmdclass' : {'build_ext':PCTBuildExt, 'build_py': PCTBuildPy, 'test': TestCommand },
+ 'cmdclass' : {'build': PCTBuild, 'build_configure': PCTBuildConfigure, 'build_ext':PCTBuildExt, 'build_py': PCTBuildPy, 'test': TestCommand },
'packages' : ["Crypto", "Crypto.Hash", "Crypto.Cipher", "Crypto.Util",
"Crypto.Random",
"Crypto.Random.Fortuna",
@@ -276,7 +361,7 @@ kw = {'name':"pycrypto",
'ext_modules': plat_ext + [
# _fastmath (uses GNU mp library)
Extension("Crypto.PublicKey._fastmath",
- include_dirs=['src/'],
+ include_dirs=['src/','/usr/include/'],
libraries=['gmp'],
sources=["src/_fastmath.c"]),
@@ -362,3 +447,19 @@ if hasattr(core, 'setup_keywords'):
core.setup(**kw)
+def touch(path):
+ import os, time
+ now = time.time()
+ try:
+ # assume it's there
+ os.utime(path, (now, now))
+ except os.error:
+ PrintErr("Failed to update timestamp of "+path)
+
+# PY3K: Workaround for winrandom.pyd not existing during the first pass.
+# It needs to be there for 2to3 to fix the import in nt.py
+if (sys.platform == 'win32' and sys.version_info[0] == 3 and
+ 'build' in sys.argv[1:]):
+ PrintErr("\nSecond pass to allow 2to3 to fix nt.py. No cause for alarm.\n")
+ touch("./lib/Crypto/Random/OSRNG/nt.py")
+ core.setup(**kw)