Skip to content

Commit

Permalink
Improve on the build process of this module
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Leonard Pollak committed Oct 28, 2021
1 parent bed289f commit f614c47
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 124 deletions.
10 changes: 9 additions & 1 deletion build_pynng.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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<inc_path> -L<lib_path> -l<lib>
#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']
Expand Down Expand Up @@ -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,
)

Expand Down
9 changes: 8 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -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

232 changes: 110 additions & 122 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__,
Expand Down Expand Up @@ -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',

)

0 comments on commit f614c47

Please sign in to comment.