mirror of
				https://github.com/Legrandin/pycryptodome.git
				synced 2025-10-31 13:41:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			418 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			418 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #! /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.core import Extension, Command
 | |
| from distutils.command.build_ext import build_ext
 | |
| 
 | |
| import os, sys
 | |
| 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"))
 | |
| 
 | |
| # Functions for finding libraries and files, copied from Python's setup.py.
 | |
| 
 | |
| def find_file(filename, std_dirs, paths):
 | |
|     """Searches for the directory where a given file is located,
 | |
|     and returns a possibly-empty list of additional directories, or None
 | |
|     if the file couldn't be found at all.
 | |
| 
 | |
|     'filename' is the name of a file, such as readline.h or libcrypto.a.
 | |
|     'std_dirs' is the list of standard system directories; if the
 | |
|         file is found in one of them, no additional directives are needed.
 | |
|     'paths' is a list of additional locations to check; if the file is
 | |
|         found in one of them, the resulting list will contain the directory.
 | |
|     """
 | |
| 
 | |
|     # Check the standard locations
 | |
|     for dir in std_dirs:
 | |
|         f = os.path.join(dir, filename)
 | |
|         if os.path.exists(f): return []
 | |
| 
 | |
|     # Check the additional directories
 | |
|     for dir in paths:
 | |
|         f = os.path.join(dir, filename)
 | |
|         if os.path.exists(f):
 | |
|             return [dir]
 | |
| 
 | |
|     # Not found anywhere
 | |
|     return None
 | |
| 
 | |
| def find_library_file(compiler, libname, std_dirs, paths):
 | |
|     filename = compiler.library_filename(libname, lib_type='shared')
 | |
|     result = find_file(filename, std_dirs, paths)
 | |
|     if result is not None: return result
 | |
| 
 | |
|     filename = compiler.library_filename(libname, lib_type='static')
 | |
|     result = find_file(filename, std_dirs, paths)
 | |
|     return result
 | |
| 
 | |
| 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'):
 | |
|             # Tell GCC to compile using the C99 standard.
 | |
|             self.__add_compiler_option("-std=c99")
 | |
| 
 | |
|             # Make assert() statements always work
 | |
|             self.__remove_compiler_option("-DNDEBUG")
 | |
| 
 | |
|             # Choose our own optimization options
 | |
|             for opt in ["-O", "-O0", "-O1", "-O2", "-O3", "-Os"]:
 | |
|                 self.__remove_compiler_option(opt)
 | |
|             if self.debug:
 | |
|                 # Basic optimization is still needed when debugging to compile
 | |
|                 # the libtomcrypt code.
 | |
|                 self.__add_compiler_option("-O")
 | |
|             else:
 | |
|                 # Speed up execution by tweaking compiler options.  This
 | |
|                 # especially helps the DES modules.
 | |
|                 self.__add_compiler_option("-O3")
 | |
|                 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)
 | |
|                 self.__remove_compiler_option("-pg")
 | |
|             if USE_GCOV:
 | |
|                 self.__add_compiler_option("-fprofile-arcs")
 | |
|                 self.__add_compiler_option("-ftest-coverage")
 | |
|                 self.compiler.libraries += ['gcov']
 | |
| 
 | |
|         # Call the superclass's build_extensions method
 | |
|         build_ext.build_extensions(self)
 | |
| 
 | |
|     def detect_modules (self):
 | |
|         # Add special include directory for MSVC (because MSVC is special)
 | |
|         if self.compiler.compiler_type == 'msvc':
 | |
|             self.compiler.include_dirs.insert(0, "src/inc-msvc/")
 | |
| 
 | |
|         # Detect libgmp or libmpir and don't build _fastmath if both are missing.
 | |
|         lib_dirs = self.compiler.library_dirs + ['/lib', '/usr/lib', '/usr/local/lib']
 | |
|         if not (self.compiler.find_library_file(lib_dirs, 'gmp') or
 | |
|             self.compiler.find_library_file(lib_dirs, 'mpir')):
 | |
|             PrintErr ("warning: GMP or MPIR library not found; Not building "+
 | |
|                 "Crypto.PublicKey._fastmath.")
 | |
|             self.__remove_extensions(["Crypto.PublicKey._fastmath"])
 | |
| 		# Change library to libmpir if libgmp is missing
 | |
|         elif not (self.compiler.find_library_file(lib_dirs, 'gmp')):
 | |
|             self.__change_extension_lib(["Crypto.PublicKey._fastmath"],
 | |
|                 ['mpir'])
 | |
|             # And if this is Windows, we need to add a linker option
 | |
|             # to make a static libmpir link well into a dynamic _fastmath
 | |
|             if sys.platform == 'win32':
 | |
|                 self.__add_extension_link_option(["Crypto.PublicKey._fastmath"],
 | |
|                     ["/NODEFAULTLIB:LIBCMT"])
 | |
| 
 | |
|     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)
 | |
| 
 | |
| 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"
 | |
| 
 | |
|     user_options = [
 | |
|         ('skip-slow-tests', None,
 | |
|             'Skip slow tests')
 | |
|     ]
 | |
| 
 | |
|     def initialize_options(self):
 | |
|         self.build_dir = None
 | |
|         self.skip_slow_tests = 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 SelfTest
 | |
|         self.announce("running self-tests")
 | |
|         old_path = sys.path[:]
 | |
|         try:
 | |
|             sys.path.insert(0, self.build_dir)
 | |
|             from Crypto import SelfTest
 | |
|             SelfTest.run(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")
 | |
| 
 | |
| kw = {'name':"pycrypto",
 | |
|       'version':"2.3",  # 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_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.Protocol", "Crypto.PublicKey"],
 | |
|       'package_dir' : { "Crypto": "lib/Crypto" },
 | |
|       'ext_modules': plat_ext + [
 | |
|             # _fastmath (uses GNU mp library)
 | |
|             Extension("Crypto.PublicKey._fastmath",
 | |
|                       include_dirs=['src/','/usr/include/'],
 | |
|                       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.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.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']),
 | |
| 
 | |
|             # 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 :: 4 - Beta',
 | |
|           'License :: Public Domain',
 | |
|           'Intended Audience :: Developers',
 | |
|           'Operating System :: Unix',
 | |
|           'Operating System :: Microsoft :: Windows',
 | |
|           'Operating System :: MacOS :: MacOS X',
 | |
|           'Topic :: Security :: Cryptography',
 | |
|           ]
 | |
|     if 'download_url' in core.setup_keywords:
 | |
|         kw['download_url'] = ('http://www.pycrypto.org/files/'
 | |
|                               '%s-%s.tar.gz' % (kw['name'], kw['version']) )
 | |
| 
 | |
| 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)
 | 
