From f614c479cefad25e974f3f029279dfdaeb3eeab3 Mon Sep 17 00:00:00 2001 From: Leonard Pollak Date: Mon, 11 Oct 2021 18:37:59 +0200 Subject: [PATCH] Improve on the build process of this module Adds a builder class for building mbedtls and nng. Add custom build option to build nng/mbedtls (hardcoded: 'yes') Uses setup.cfg to specify the repo url and revision --- build_pynng.py | 10 ++- setup.cfg | 9 +- setup.py | 232 +++++++++++++++++++++++-------------------------- 3 files changed, 127 insertions(+), 124 deletions(-) diff --git a/build_pynng.py b/build_pynng.py index 3215129..4772596 100644 --- a/build_pynng.py +++ b/build_pynng.py @@ -10,6 +10,7 @@ ffibuilder = FFI() if sys.platform == 'win32': + incdirs = ['nng/include'] objects = ['./nng/build/Release/nng.lib'] mbedtls_dir = './mbedtls/build/library/Release' @@ -21,7 +22,14 @@ # system libraries determined to be necessary through trial and error libraries = ['Ws2_32', 'Advapi32'] +# comment out this block if you want to build this with you own libraries +# e.g.: python setup.py build_ext -I -L -l +#elif True: +# incdirs = None +# libraries = ['pthread' 'mbedtls' 'nng'] +# objects = None else: + incdirs = ['nng/include'] objects = ['./nng/build/libnng.a', "./mbedtls/prefix/lib/libmbedtls.a", "./mbedtls/prefix/lib/libmbedx509.a", "./mbedtls/prefix/lib/libmbedcrypto.a"] libraries = ['pthread'] @@ -57,7 +65,7 @@ libraries=libraries, # library_dirs=['nng/build/Debug',], # (more arguments like setup.py's Extension class: - include_dirs=['nng/include'], + include_dirs=incdirs, extra_objects=objects, ) diff --git a/setup.cfg b/setup.cfg index c5aac7a..f6d7e29 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,10 @@ +[build_nng] +repo=https://github.com/nanomsg/nng +rev=4f5e11c391c4a8f1b2731aee5ad47bc0c925042a + +[build_mbedtls] +repo=https://github.com/ARMmbed/mbedtls.git +rev=04a049bda1ceca48060b57bc4bcf5203ce591421 + [build_ext] inplace = 1 - diff --git a/setup.py b/setup.py index 20cd02d..c9d7764 100644 --- a/setup.py +++ b/setup.py @@ -3,162 +3,144 @@ import shutil import sys -import setuptools.command.build_py -import setuptools.command.build_ext +from setuptools import Command, setup +from setuptools.command.build_ext import build_ext +from distutils.command.build import build as dbuild # have to exec; can't import the package before it's built. exec(open("pynng/_version.py", encoding="utf-8").read()) -THIS_DIR = os.path.abspath(os.path.dirname(__file__)) -NNG_REPO = 'https://github.com/nanomsg/nng' -NNG_REV = '4f5e11c391c4a8f1b2731aee5ad47bc0c925042a' -MBEDTLS_REPO = 'https://github.com/ARMmbed/mbedtls.git' -MBEDTLS_REV = '04a049bda1ceca48060b57bc4bcf5203ce591421' +class BuilderBase(Command): + """Base Class for building vendored dependencies""" + user_options = [ + ('repo=', None, 'GitHub repository URL.'), + ('rev=', None, 'GitHub repository revision.'), + ] -WINDOWS = sys.platform == 'win32' + windows = sys.platform == 'win32' + flags = ['-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true'] + is_64bit = sys.maxsize > 2**32 + if windows: + if is_64bit: + flags += ['-A', 'x64'] + else: + flags += ['-A', 'win32'] -def _rmdir(dirname): - # we can't use shutil.rmtree because it won't delete readonly files. - if WINDOWS: - cmd = ['rmdir', '/q', '/s', dirname] - else: - cmd = ['rm', '-rf', dirname] - return check_call(cmd) + if shutil.which('ninja'): + # the ninja build generator is a trillion times faster. + flags += ['-G', 'Ninja'] + cmake_cmd = ['cmake'] + flags -def build_mbedtls(cmake_args): - """ - Clone mbedtls and build it with cmake. + def initialize_options(self): + """Set default values for options.""" + self.repo = '' + self.rev = '' - """ - do = check_call - if not os.path.exists('mbedtls'): - do('git clone --recursive {}'.format(MBEDTLS_REPO), shell=True) - # for local hacking, just copy a directory (network connection is slow) - # do('cp -r ../mbedtls mbedtls', shell=True) - do('git checkout {}'.format(MBEDTLS_REV), shell=True, cwd='mbedtls') - cwd = 'mbedtls/build' - os.mkdir(cwd) - cmake_cmd = ['cmake'] + cmake_args - cmake_cmd += [ - '-DENABLE_PROGRAMS=OFF', - '-DCMAKE_BUILD_TYPE=Release', - '-DCMAKE_INSTALL_PREFIX=../prefix', - '..' - ] - print('building mbedtls with:', cmake_cmd) - do(cmake_cmd, cwd=cwd) - do( - 'cmake --build . --config Release --target install', - shell=True, - cwd=cwd, - ) + def finalize_options(self): + """Post-process options.""" + pass + def run(self): + """Clone nng and build it with cmake, with TLS enabled.""" + if not os.path.exists(self.git_dir): + check_call('git clone {}'.format(self.repo), shell=True) + check_call('git checkout {}'.format(self.rev), shell=True, cwd=self.git_dir) + if not os.path.exists(self.build_dir): + os.mkdir(self.build_dir) -def build_nng(cmake_args): - """ - Clone nng and build it with cmake, with TLS enabled. + self.cmake_cmd += self.cmake_extra_args + self.cmake_cmd.append('..') + print(f'building {self.git_dir} with:', self.cmake_cmd) + check_call(self.cmake_cmd, cwd=self.build_dir) - """ - do = check_call - if not os.path.exists('nng'): - do('git clone {}'.format(NNG_REPO), shell=True) - # for local hacking, just copy a directory (network connection is slow) - # do('cp -r ../nng-clean nng', shell=True) - do('git checkout {}'.format(NNG_REV), shell=True, cwd='nng') - os.mkdir('nng/build') - cmake_cmd = ['cmake'] + cmake_args - cmake_cmd += [ + self.finalize_build() + + +class BuildNng(BuilderBase): + + description = 'build the nng library' + git_dir = 'nng' + build_dir = 'nng/build' + this_dir = os.path.abspath(os.path.dirname(__file__)) + cmake_extra_args = [ '-DNNG_ENABLE_TLS=ON', '-DNNG_TESTS=OFF', '-DNNG_TOOLS=OFF', '-DCMAKE_BUILD_TYPE=Release', - '-DMBEDTLS_ROOT_DIR={}/mbedtls/prefix/'.format(THIS_DIR), - '..', + '-DMBEDTLS_ROOT_DIR={}/mbedtls/prefix/'.format(this_dir), ] - print('building mbedtls with:', cmake_cmd) - do(cmake_cmd, cwd='nng/build') - do( - 'cmake --build . --config Release', - shell=True, - cwd='nng/build', - ) + def finalize_build(self): + check_call( + 'cmake --build . --config Release', + shell=True, + cwd=self.build_dir, + ) -def build_libs(): - """ - Builds the nng and mbedtls libs. - """ - # The user has to have the correct Visual Studio version on the path or the - # build will fail, possibly in exciting and mysterious ways. - major, minor, *_ = sys.version_info - - flags = ['-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true'] - is_64bit = sys.maxsize > 2**32 - if WINDOWS: - if is_64bit: - flags += ['-A', 'x64'] - else: - flags += ['-A', 'win32'] - - if shutil.which('ninja'): - # the ninja build generator is a million times faster. - flags += ['-G', 'Ninja'] - build_mbedtls(flags) - build_nng(flags) +class BuildMbedTls(BuilderBase): + description = 'build the mbedtls library' + git_dir = 'mbedtls' + build_dir = 'mbedtls/build' + cmake_extra_args = [ + '-DENABLE_PROGRAMS=OFF', + '-DCMAKE_BUILD_TYPE=Release', + '-DCMAKE_INSTALL_PREFIX=../prefix', + ] -def build_nng_lib(): - # cannot import build_pynng at the top level becuase cffi may not be - # installed yet (since it is a dependency, and this script installs - # dependencies). Bootstrapping! - import build_pynng - objs = build_pynng.objects - if objs and all(os.path.exists(p) for p in objs): - # the object file we were planning on building already exists; we'll - # just use it! - return + def finalize_build(self): + check_call( + 'cmake --build . --config Release --target install', + shell=True, + cwd=self.build_dir, + ) - build_libs() +#class BuildBuild(dbuild): +class BuildBuild(build_ext): + """ + Custom build command + """ + #dbuild.user_options += [ + # ('build-deps', None, 'build nng and mbedtls before building the module') + #] + build_ext.user_options += [ + ('build-deps', None, 'build nng and mbedtls before building the module') + ] -# TODO: this is basically a hack to get something to run before running cffi -# extnsion builder. subclassing something else would be better! -class BuildPyCommand(setuptools.command.build_py.build_py): - """Build nng library before anything else.""" + def initialize_options(self): + """ + Set default values for options + Each user option must be listed here with their default value. + """ + #dbuild.initialize_options(self) + build_ext.initialize_options(self) + self.build_deps = 'yes' def run(self): - build_nng_lib() - super(BuildPyCommand, self).run() + """ + Running... + """ + if self.build_deps: + self.run_command('build_mbedtls') + self.run_command('build_nng') - -class BuildExtCommand(setuptools.command.build_ext.build_ext): - """Build nng library before anything else.""" - - def run(self): - build_nng_lib() - super(BuildExtCommand, self).run() + #dbuild.run(self) # proceed with "normal" build steps + build_ext.run(self) # proceed with "normal" build steps with open('README.md', 'r', encoding='utf-8') as f: long_description = f.read() -tests_require = [ - 'pytest', - 'pytest-asyncio', - 'pytest-trio', - 'pytest-curio', - 'trio', - 'curio' -] - -setuptools.setup( +setup( cmdclass={ - 'build_py': BuildPyCommand, - 'build_ext': BuildExtCommand, + 'build_mbedtls': BuildMbedTls, + 'build_nng': BuildNng, + 'build_ext': BuildBuild, }, name='pynng', version=__version__, @@ -189,7 +171,13 @@ def run(self): setup_requires=['cffi', 'pytest-runner'], install_requires=['cffi', 'sniffio'], cffi_modules=['build_pynng.py:ffibuilder'], - tests_require=tests_require, + tests_require=[ + 'pytest', + 'pytest-asyncio', + 'pytest-trio', + 'pytest-curio', + 'trio', + 'curio' + ], test_suite='tests', - )