Skip to content

Commit

Permalink
pybind: Rework rbd/setup.py for PyPI
Browse files Browse the repository at this point in the history
Signed-off-by: Anirudha Bose <ani07nov@gmail.com>
  • Loading branch information
onyb committed Aug 10, 2016
1 parent 0d41383 commit 8082b2d
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 42 deletions.
1 change: 1 addition & 0 deletions src/pybind/rbd/MANIFEST.in
@@ -0,0 +1 @@
include rbd.pyx
227 changes: 185 additions & 42 deletions src/pybind/rbd/setup.py
@@ -1,55 +1,198 @@
# Largely taken from
# https://blog.kevin-brown.com/programming/2014/09/24/combining-autotools-and-setuptools.html
import os, sys, os.path
from __future__ import print_function

from setuptools.command.egg_info import egg_info
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
import os
import pkgutil
import shutil
import subprocess
import sys
import tempfile
import textwrap
from distutils.ccompiler import new_compiler
from distutils.errors import CompileError, LinkError
from distutils.sysconfig import customize_compiler

def get_version():
try:
for line in open(os.path.join(os.path.dirname(__file__), "..", "ceph_ver.h")):
if "CEPH_GIT_NICE_VER" in line:
return line.split()[2][1:-1]
if not pkgutil.find_loader('setuptools'):
from distutils.core import setup
from distutils.extension import Extension
else:
from setuptools import setup
from setuptools.extension import Extension

# PEP 440 versioning of the RBD package on PyPI
# Bump this version, after every changeset

__version__ = '2.0.0'


def get_python_flags():
cflags = {'I': [], 'extras': []}
ldflags = {'l': [], 'L': [], 'extras': []}

if os.environ.get('VIRTUAL_ENV', None):
python = "python"
else:
python = 'python' + str(sys.version_info.major) + '.' + str(sys.version_info.minor)

python_config = python + '-config'

for cflag in subprocess.check_output(
[python_config, "--cflags"]
).strip().decode('utf-8').split():
if cflag.startswith('-I'):
cflags['I'].append(cflag.replace('-I', ''))
else:
return "0"
except IOError:
return "0"

class EggInfoCommand(egg_info):
def finalize_options(self):
egg_info.finalize_options(self)
if "build" in self.distribution.command_obj:
build_command = self.distribution.command_obj["build"]
self.egg_base = build_command.build_base
self.egg_info = os.path.join(self.egg_base, os.path.basename(self.egg_info))
cflags['extras'].append(cflag)

for ldflag in subprocess.check_output(
[python_config, "--ldflags"]
).strip().decode('utf-8').split():
if ldflag.startswith('-l'):
ldflags['l'].append(ldflag.replace('-l', ''))
if ldflag.startswith('-L'):
ldflags['L'].append(ldflag.replace('-L', ''))
else:
ldflags['extras'].append(ldflag)

return {
'cflags': cflags,
'ldflags': ldflags
}


def check_sanity():
"""
Test if development headers and library for rbd is available by compiling a dummy C program.
"""
CEPH_SRC_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'..',
'..'
)

tmp_dir = tempfile.mkdtemp(dir=os.environ.get('TMPDIR', os.path.dirname(__file__)))
tmp_file = os.path.join(tmp_dir, 'rbd_dummy.c')

with open(tmp_file, 'w') as fp:
dummy_prog = textwrap.dedent("""
#include <stddef.h>
#include <rbd/librbd.h>
int main(void) {
rados_t cluster;
rados_create(&cluster, NULL);
return 0;
}
""")
fp.write(dummy_prog)

compiler = new_compiler()
customize_compiler(compiler)

if {'MAKEFLAGS', 'MFLAGS', 'MAKELEVEL'}.issubset(set(os.environ.keys())):
# The setup.py has been invoked by a top-level Ceph make.
# Set the appropriate CFLAGS and LDFLAGS

compiler.set_include_dirs([os.path.join(CEPH_SRC_DIR, 'include')])
compiler.set_library_dirs([os.environ.get('CEPH_LIBDIR')])

try:
compiler.define_macro('_FILE_OFFSET_BITS', '64')

link_objects = compiler.compile(
sources=[tmp_file],
output_dir=tmp_dir
)

compiler.link_executable(
objects=link_objects,
output_progname=os.path.join(tmp_dir, 'rbd_dummy'),
libraries=['rbd', 'rados'],
output_dir=tmp_dir,
)

except CompileError:
print('\nCompile Error: RBD development headers not found', file=sys.stderr)
return False
except LinkError:
print('\nLink Error: RBD library not found', file=sys.stderr)
return False
else:
return True
finally:
shutil.rmtree(tmp_dir)


if not check_sanity():
sys.exit(1)

cmdclass = {}
try:
from Cython.Build import cythonize
from Cython.Distutils import build_ext

cmdclass = {'build_ext': build_ext}
except ImportError:
print("WARNING: Cython is not installed.")

if not os.path.isfile('rbd.c'):
print('ERROR: Cannot find Cythonized file rbd.c', file=sys.stderr)
sys.exit(1)
else:
def cythonize(x, **kwargs):
return x

source = "rbd.c"
else:
source = "rbd.pyx"

# Disable cythonification if we're not really building anything
if (len(sys.argv) >= 2 and
any(i in sys.argv[1:] for i in ('--help', 'clean', 'egg_info', '--version')
)):
any(i in sys.argv[1:] for i in ('--help', 'clean', 'egg_info', '--version')
)):
def cythonize(x, **kwargs):
return x

flags = get_python_flags()

setup(
name = 'rbd',
version = get_version(),
description = "Python libraries for the Ceph librbd library",
long_description = (
"This package contains Python libraries for interacting with Ceph's "
"RBD block device library."),
ext_modules = cythonize([
Extension("rbd",
["rbd.pyx"],
libraries=["rbd"],
name='rbd',
version=__version__,
description="Python bindings for the RBD library",
long_description=(
"This package contains Python bindings for interacting with the "
"RADOS Block Device (RBD) library. rbd is a utility for manipulating "
"rados block device images, used by the Linux rbd driver and the rbd "
"storage driver for QEMU/KVM. RBD images are simple block devices that "
"are striped over objects and stored in a RADOS object store. The size "
"of the objects the image is striped over must be a power of two."
),
url='https://github.com/ceph/ceph/tree/master/src/pybind/rbd',
license='LGPLv2+',
platforms='Linux',
ext_modules=cythonize(
[
Extension(
"rbd",
[source],
include_dirs=flags['cflags']['I'],
library_dirs=flags['ldflags']['L'],
libraries=['rbd', 'rados'] + flags['ldflags']['l'],
extra_compile_args=flags['cflags']['extras'] + flags['ldflags']['extras'],
)
], build_dir=os.environ.get("CYTHON_BUILD_DIR", None), include_path=[
os.path.join(os.path.dirname(__file__), "..", "rados")]
],
build_dir=os.environ.get("CYTHON_BUILD_DIR", None),
include_path=[
os.path.join(os.path.dirname(__file__), "..", "rados")
]
),
cmdclass={
"egg_info": EggInfoCommand,
"build_ext": build_ext,
},
classifiers=[
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)',
'Operating System :: POSIX :: Linux',
'Programming Language :: Cython',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5'
],
cmdclass=cmdclass,
)

0 comments on commit 8082b2d

Please sign in to comment.