summaryrefslogtreecommitdiff
path: root/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py527
1 files changed, 527 insertions, 0 deletions
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..5269e9d
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,527 @@
+#! /usr/bin/env python
+#
+# setup.py : Distutils setup script
+#
+# Part of the Python Cryptography Toolkit
+#
+# ===================================================================
+# Portions Copyright (c) 2001, 2002, 2003 Python Software Foundation;
+# All Rights Reserved
+#
+# This file contains code from the Python 2.2 setup.py module (the
+# "Original Code"), with modifications made after it was incorporated
+# into PyCrypto (the "Modifications").
+#
+# To the best of our knowledge, the Python Software Foundation is the
+# copyright holder of the Original Code, and has licensed it under the
+# Python 2.2 license. See the file LEGAL/copy/LICENSE.python-2.2 for
+# details.
+#
+# The Modifications to this file are dedicated to the public domain.
+# To the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever. No rights are
+# reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+__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.sysconfig
+import os, sys, re
+import struct
+
+if sys.version[0:1] == '1':
+ raise RuntimeError ("The Python Cryptography Toolkit requires "
+ "Python 2.x or 3.x to build.")
+
+if sys.platform == 'win32':
+ HTONS_LIBS = ['ws2_32']
+ plat_ext = [
+ Extension("Crypto.Random.OSRNG.winrandom",
+ libraries = HTONS_LIBS + ['advapi32'],
+ include_dirs=['src/'],
+ sources=["src/winrand.c"])
+ ]
+else:
+ HTONS_LIBS = []
+ 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 = 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
+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".encode(): # little endian
+ return ('PCT_LITTLE_ENDIAN', 1)
+ elif s == "\x33\x22\x11\x00".encode(): # big endian
+ return ('PCT_BIG_ENDIAN', 1)
+ raise AssertionError("Machine is neither little-endian nor big-endian")
+
+class PCTBuildExt (build_ext):
+ def build_extensions(self):
+ # Detect which modules should be compiled
+ self.detect_modules()
+
+ # Tweak compiler options
+ if self.compiler.compiler_type in ('unix', 'cygwin', 'mingw32'):
+ # Make assert() statements always work
+ self.__remove_compiler_option("-DNDEBUG")
+
+ if USE_GCOV: # TODO - move this to configure.ac
+ self.__add_compiler_option("-fprofile-arcs")
+ self.__add_compiler_option("-ftest-coverage")
+ self.compiler.libraries += ['gcov']
+
+ # Python 2.1 and 2.2 don't respect the LDFLAGS environment variable. Hack it.
+ if sys.version_info < (2, 3, 'final', 0):
+ if os.environ.get('LDFLAGS'): # Set from ./buildenv (ultimately provided by autoconf)
+ for opt in os.environ['LDFLAGS'].split(" "):
+ opt = opt.strip()
+ if not opt: continue
+ self.compiler.linker_so.append(opt)
+
+ # Call the superclass's build_extensions method
+ build_ext.build_extensions(self)
+
+ def detect_modules (self):
+ # 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/")
+ 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"])
+
+ # Detect if we have AES-NI instrincs available
+ if not ac.get("HAVE_WMMINTRIN_H"):
+ # AES-NI instrincs not available
+ self.__remove_extensions(["Crypto.Cipher._AESNI"])
+ elif not (ac.get("HAVE_POSIX_MEMALIGN") or ac.get("HAVE_ALIGNED_ALLOC")
+ or ac.get("HAVE__ALIGNED_MALLOC")):
+ # no function to allocate aligned memory is available
+ self.__remove_extensions(["Crypto.Cipher._AESNI"])
+ elif ac.get("HAVE_MAES"):
+ # -maes has to be passed to the compiler to use the AES-NI instrincs
+ self.__add_extension_compile_option(["Crypto.Cipher._AESNI"],
+ ["-maes"])
+
+ def __add_extension_compile_option(self, names, options):
+ """Add compiler options for the specified extension(s)"""
+ for extension in self.extensions:
+ if extension.name in names:
+ extension.extra_compile_args = options
+
+ 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(s) from the list of extensions
+ to build"""
+ i = 0
+ while i < len(self.extensions):
+ if self.extensions[i].name in names:
+ del self.extensions[i]
+ continue
+ i += 1
+
+ def __remove_compiler_option(self, option):
+ """Remove the specified compiler option.
+
+ Return true if the option was found. Return false otherwise.
+ """
+ found = 0
+ for attrname in ('compiler', 'compiler_so'):
+ compiler = getattr(self.compiler, attrname, None)
+ if compiler is not None:
+ while option in compiler:
+ compiler.remove(option)
+ found += 1
+ return found
+
+ def __add_compiler_option(self, option):
+ for attrname in ('compiler', 'compiler_so'):
+ compiler = getattr(self.compiler, attrname, None)
+ 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
+
+ def run(self):
+ # Run the commands that this one depends on (i.e. build_configure)
+ for cmd_name in self.get_sub_commands():
+ self.run_command(cmd_name)
+
+ class unmodified: pass # sentinel value
+ orig_cc = unmodified
+ try:
+ # Set environment variables generated by the configure script
+ if os.path.exists("buildenv"):
+ try:
+ f = open("buildenv", "r")
+ for line in f.readlines():
+ if line.startswith("#") or not line.strip():
+ continue
+ k, v = line.split("=", 1)
+ k, v = k.strip(), v.strip()
+ os.environ[k] = v
+ finally:
+ f.close()
+
+ # Python 2.1 and 2.2 don't respect the CC environment variable by default. Monkey-patch it.
+ if sys.version_info < (2, 3, 'final', 0) and os.environ.get('CC'):
+ distutils.sysconfig.get_config_vars() # populates distutils.sysconfig._config_vars
+ orig_cc = distutils.sysconfig._config_vars['CC']
+ distutils.sysconfig._config_vars['CC'] = os.environ['CC']
+
+ # Build the extension modules
+ build_ext.run(self)
+
+ finally:
+ if orig_cc is not unmodified:
+ # Undo monkey-patch
+ distutils.sysconfig._config_vars['CC'] = orig_cc
+
+
+ def has_configure(self):
+ compiler = new_compiler(compiler=self.compiler)
+ return compiler.compiler_type != 'msvc'
+
+ sub_commands = [ ('build_configure', has_configure) ] + build_ext.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 hasattr(os, "chmod"):
+ import stat
+ os.chmod("configure", stat.S_IRUSR | stat.S_IWUSR |
+ stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP |
+ stat.S_IROTH | stat.S_IXOTH)
+ 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)
+
+ # Exclude certain modules
+ retval = []
+ for item in modules:
+ pkg, module = item[:2]
+ if (pkg, module) in EXCLUDE_PY:
+ continue
+ retval.append(item)
+ return retval
+
+
+class TestCommand(Command):
+
+ description = "Run self-test"
+
+ # Long option name, short option name, description
+ user_options = [
+ ('skip-slow-tests', None,
+ 'Skip slow tests'),
+ ('module=', 'm', 'Test a single module (e.g. Cipher, PublicKey)')
+ ]
+
+ def initialize_options(self):
+ self.build_dir = None
+ self.skip_slow_tests = None
+ self.module = None
+
+ def finalize_options(self):
+ self.set_undefined_options('install', ('build_lib', 'build_dir'))
+ self.config = {'slow_tests': not self.skip_slow_tests}
+
+ def run(self):
+ # Run sub commands
+ for cmd_name in self.get_sub_commands():
+ self.run_command(cmd_name)
+
+ # Run SelfTest
+ self.announce("running self-tests")
+ old_path = sys.path[:]
+ try:
+ sys.path.insert(0, self.build_dir)
+ from Crypto import SelfTest
+ moduleObj = None
+ if self.module:
+ if self.module.count('.')==0:
+ # Test a whole a sub-package
+ full_module = "Crypto.SelfTest." + self.module
+ module_name = self.module
+ else:
+ # Test only a module
+ # Assume only one dot is present
+ comps = self.module.split('.')
+ module_name = "test_" + comps[1]
+ full_module = "Crypto.SelfTest." + comps[0] + "." + module_name
+ # Import sub-package or module
+ moduleObj = __import__( full_module, globals(), locals(), module_name )
+ SelfTest.run(module=moduleObj, verbosity=self.verbose, stream=sys.stdout, config=self.config)
+ finally:
+ # Restore sys.path
+ sys.path[:] = old_path
+
+ # Run slower self-tests
+ self.announce("running extended self-tests")
+
+ sub_commands = [ ('build', None) ]
+
+kw = {'name':"pycrypto",
+ 'version':"2.7a1", # See also: lib/Crypto/__init__.py
+ 'description':"Cryptographic modules for Python.",
+ 'author':"Dwayne C. Litzenberger",
+ 'author_email':"dlitz@dlitz.net",
+ 'url':"http://www.pycrypto.org/",
+
+ 'cmdclass' : {'build_configure': PCTBuildConfigure, 'build_ext': PCTBuildExt, 'build_py': PCTBuildPy, 'test': TestCommand },
+ 'packages' : ["Crypto", "Crypto.Hash", "Crypto.Cipher", "Crypto.Util",
+ "Crypto.Random",
+ "Crypto.Random.Fortuna",
+ "Crypto.Random.OSRNG",
+ "Crypto.SelfTest",
+ "Crypto.SelfTest.Cipher",
+ "Crypto.SelfTest.Hash",
+ "Crypto.SelfTest.Protocol",
+ "Crypto.SelfTest.PublicKey",
+ "Crypto.SelfTest.Random",
+ "Crypto.SelfTest.Random.Fortuna",
+ "Crypto.SelfTest.Random.OSRNG",
+ "Crypto.SelfTest.Util",
+ "Crypto.SelfTest.Signature",
+ "Crypto.SelfTest.IO",
+ "Crypto.Protocol",
+ "Crypto.PublicKey",
+ "Crypto.Signature",
+ "Crypto.IO"],
+ 'package_dir' : { "Crypto": "lib/Crypto" },
+ 'ext_modules': plat_ext + [
+ # _fastmath (uses GNU mp library)
+ Extension("Crypto.PublicKey._fastmath",
+ include_dirs=['src/'],
+ libraries=['gmp'],
+ sources=["src/_fastmath.c"]),
+
+ # Hash functions
+ Extension("Crypto.Hash.MD2",
+ include_dirs=['src/'],
+ sources=["src/MD2.c"]),
+ Extension("Crypto.Hash.MD4",
+ include_dirs=['src/'],
+ sources=["src/MD4.c"]),
+ Extension("Crypto.Hash.SHA256",
+ include_dirs=['src/'],
+ sources=["src/SHA256.c"]),
+ Extension("Crypto.Hash.SHA224",
+ include_dirs=['src/'],
+ sources=["src/SHA224.c"]),
+ Extension("Crypto.Hash.SHA384",
+ include_dirs=['src/'],
+ sources=["src/SHA384.c"]),
+ Extension("Crypto.Hash.SHA512",
+ include_dirs=['src/'],
+ sources=["src/SHA512.c"]),
+ Extension("Crypto.Hash.RIPEMD160",
+ include_dirs=['src/'],
+ sources=["src/RIPEMD160.c"],
+ define_macros=[endianness_macro()]),
+
+ # Block encryption algorithms
+ Extension("Crypto.Cipher._AES",
+ include_dirs=['src/'],
+ sources=["src/AES.c"]),
+ Extension("Crypto.Cipher._AESNI",
+ include_dirs=['src/'],
+ sources=["src/AESNI.c"]),
+ Extension("Crypto.Cipher._ARC2",
+ include_dirs=['src/'],
+ sources=["src/ARC2.c"]),
+ Extension("Crypto.Cipher._Blowfish",
+ include_dirs=['src/'],
+ sources=["src/Blowfish.c"]),
+ Extension("Crypto.Cipher._CAST",
+ include_dirs=['src/'],
+ sources=["src/CAST.c"]),
+ Extension("Crypto.Cipher._DES",
+ include_dirs=['src/', 'src/libtom/'],
+ sources=["src/DES.c"]),
+ Extension("Crypto.Cipher._DES3",
+ include_dirs=['src/', 'src/libtom/'],
+ sources=["src/DES3.c"]),
+
+ # Stream ciphers
+ Extension("Crypto.Cipher._ARC4",
+ include_dirs=['src/'],
+ sources=["src/ARC4.c"]),
+ Extension("Crypto.Cipher._XOR",
+ include_dirs=['src/'],
+ sources=["src/XOR.c"]),
+
+ # Utility modules
+ Extension("Crypto.Util.strxor",
+ include_dirs=['src/'],
+ sources=['src/strxor.c']),
+ Extension("Crypto.Util.cpuid",
+ include_dirs=['src/'],
+ sources=['src/cpuid.c']),
+ Extension("Crypto.Util.galois",
+ include_dirs=['src/'],
+ sources=['src/galois.c']),
+
+ # Counter modules
+ Extension("Crypto.Util._counter",
+ include_dirs=['src/'],
+ sources=['src/_counter.c']),
+ ]
+}
+
+# If we're running Python 2.3, add extra information
+if hasattr(core, 'setup_keywords'):
+ if 'classifiers' in core.setup_keywords:
+ kw['classifiers'] = [
+ 'Development Status :: 5 - Production/Stable',
+ 'License :: Public Domain',
+ 'Intended Audience :: Developers',
+ 'Operating System :: Unix',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Topic :: Security :: Cryptography',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 3',
+ ]
+
+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)