from setuptools import setup, Distribution from setuptools.command.install import install from setuptools.command.build_ext import build_ext from setuptools.extension import Extension import sys import subprocess import os import glob import shutil import re from ctypes import cdll _NAME = 'cryptoauthlib' _DESCRIPTION = 'Python Wrapper Library for Microchip Security Products' _AUTHOR = 'Microchip Technology Inc' _AUTHOR_EMAIL = 'support@microchip.com' _LICENSE = 'Other' _VERSION = "" _URL = 'https://github.com/MicrochipTech/cryptoauthlib' _DOWNLOAD_URL = '%s/archive/%s.tar.gz' % (_URL, _VERSION) _CLASSIFIERS = [ 'Development Status :: 4 - Beta', 'License :: Other/Proprietary License', 'Intended Audience :: Developers', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Operating System :: OS Independent', ] _PROJECT_URLS = { 'Documentation': '%s/wiki/python' % _URL, 'Source': _URL, 'Tracker': '%s/issues' % _URL, } # Include the compiled library in the resulting distribution _PACKAGE_DATA = {} if sys.platform is 'win32': _PACKAGE_DATA['libcryptoauth'] = ['cryptoauth.dll'] #elif sys.platform is 'darwin': else: _PACKAGE_DATA['libcryptoauth'] = ['libcryptoauth.so'] # See if this is being built from an sdist structure if os.path.exists('lib') and os.path.exists('third_party'): _sdist_build = True else: _sdist_build = False # See if the library is already installed try: lib = cdll.LoadLibrary('libcryptoauth.so') # Test to ensure it has the required features to support the # python wrapper. It may change later to a version check assert 0 != lib.ATCAIfacecfg_size _EXTENSIONS = None except: _EXTENSIONS = [Extension('cryptoauthlib', sources=[])] # Try to load the version try: _VERSION = open('VERSION', 'r').read().strip() except FileNotFoundError: with open('../lib/atca_version.h', 'r') as f: m = re.search(r'ATCA_LIBRARY_VERSION_DATE\s+\"([0-9]+)\"', f.read(), re.M) _VERSION = m.groups()[0] def copy_udev_rules(target): if _sdist_build: rules = 'lib/hal/90-cryptohid.rules' else: rules = '../lib/hal/90-cryptohid.rules' if not os.path.exists(target): raise FileNotFoundError if not os.path.exists(target + os.path.sep + os.path.basename(rules)): shutil.copy(rules, target) def install_udev_rules(): if sys.platform.startswith('linux'): try: copy_udev_rules('/etc/udev/rules.d') except PermissionError: print('Unable to write udev rules. Rerun install as sudo or install rules manually') except: print('Unable to install udev rules. See readme to manually install') def load_readme(): with open('README.md', 'r') as f: read_me = f.read() if not _sdist_build: with open('../README.md', 'r') as f: notes = f.read() read_me += notes[notes.find('Release notes'):notes.find('Host Device Support')] with open('README.md', 'w') as f: f.write(read_me) return read_me class CryptoAuthCommandBuildExt(build_ext): def build_extension(self, ext): # Suppress cmake output devnull = open(os.devnull, 'r+b') nousb = bool(os.environ.get('CRYPTOAUTHLIB_NOUSB', False)) # Check if CMAKE is installed try: subprocess.check_call(['cmake', '--version'], stdin=devnull, stdout=devnull, stderr=devnull, shell=False) except OSError as e: print("CMAKE must be installed on the system for this module to build the required extension e.g. 'apt-get install cmake' or 'yum install cmake'") raise e extdir = os.path.abspath( os.path.dirname(self.get_ext_fullpath(ext.name)) + os.path.sep + _NAME) setupdir = os.path.dirname(os.path.abspath(__file__)) + os.path.sep cmakelist_path = os.path.abspath(setupdir + 'lib' if _sdist_build else '../lib') if not sys.platform.startswith('linux'): cfg = 'Debug' if self.debug else 'Release' build_args = ['--config', cfg] else: build_args = [] cmake_args = ['-DATCA_HAL_CUSTOM=ON'] if not nousb: cmake_args += ['-DATCA_HAL_KIT_HID=ON'] if 'win32' == sys.platform: cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_%s=' % cfg.upper() + extdir, '-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_%s=' % cfg.upper() + extdir] if sys.maxsize > 2**32: cmake_args += ['-A', 'x64'] else: cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir] if sys.platform.startswith('linux'): cmake_args += ['-DATCA_HAL_I2C=ON'] cmake_args += ['-DATCACERT_DEF_SRC={}atca_utils_sizes.c'.format(setupdir.replace('\\','/') if _sdist_build else '../test/')] if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) # Configure the library try: subprocess.check_output(['cmake', cmakelist_path] + cmake_args, cwd=os.path.abspath(self.build_temp), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: msg = e.output.decode('utf-8') if 'usb' in msg: msg += '\n\n USB libraries or headers were not located. If USB support is\n' \ ' not required it can be disabled by setting the environment\n' \ ' variable CRYPTOAUTHLIB_NOUSB to true before trying to install\n' \ ' this package: \n\n' \ ' $ export CRYPTOAUTHLIB_NOUSB=True\n\n' \ ' Run setup.py clean before trying install again or use the pip \n' \ ' option --no-cache-dir\n' raise RuntimeError(msg) # Build the library try: subprocess.check_output(['cmake', '--build', '.'] + build_args, cwd=os.path.abspath(self.build_temp), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: if sys.version_info[0] <= 2: raise RuntimeError(e.output) # Python 2 doesn't handle unicode exceptions else: raise RuntimeError(e.output.decode('utf-8')) class CryptoAuthCommandInstall(install): def run(self): self.do_egg_install() install_udev_rules() class BinaryDistribution(Distribution): def has_ext_modules(self): return (_EXTENSIONS is not None) # Setuptools has some weird behavior when the install command class is extended # but only affects bdist_* invocations which only applies to macos and windows # and the extension is only required for linux _COMMANDS = { 'build_ext': CryptoAuthCommandBuildExt } #if sys.platform.startswith('linux'): # _COMMANDS['install'] = CryptoAuthCommandInstall if __name__ == '__main__': setup( name=_NAME, packages=[_NAME], version=_VERSION, description=_DESCRIPTION, long_description=load_readme(), long_description_content_type='text/markdown', url=_URL, author=_AUTHOR, author_email=_AUTHOR_EMAIL, download_url=_DOWNLOAD_URL, keywords='Microchip ATECC508A ATECC608A ECDSA ECDH', project_urls=_PROJECT_URLS, license=_LICENSE, classifiers=_CLASSIFIERS, package_data=_PACKAGE_DATA, include_package_data=True, distclass=BinaryDistribution, cmdclass=_COMMANDS, setup_requires=['setuptools>=38.6.0', 'wheel'], install_requires=['enum34;python_version<"3.4"'], ext_modules=_EXTENSIONS, python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', zip_safe=False )