diff options
author | Legrandin <gooksankoo@hoiptorrow.mailexpire.com> | 2011-10-18 23:20:26 +0200 |
---|---|---|
committer | Legrandin <gooksankoo@hoiptorrow.mailexpire.com> | 2011-10-18 23:20:26 +0200 |
commit | c22fa18c0dedb43a8b19dcb9b29512ba59e1764b (patch) | |
tree | e7864a848ed2c37d4a2c0d65bcae0f0cbdc6ea27 /setup.py | |
parent | 897b75983c31a9e2630af92161e6206c2480685e (diff) | |
parent | b9658a26003ebfcfce1804a2363a29354799b47e (diff) | |
download | pycrypto-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.py | 205 |
1 files changed, 153 insertions, 52 deletions
@@ -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) |