| #!/usr/bin/env python |
| |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| import glob |
| import os.path as osp |
| import re |
| import shutil |
| from Cython.Distutils import build_ext as _build_ext |
| import Cython |
| |
| import sys |
| |
| import pkg_resources |
| from setuptools import setup, Extension |
| |
| import os |
| |
| from os.path import join as pjoin |
| |
| from distutils.command.clean import clean as _clean |
| from distutils import sysconfig |
| |
| # Check if we're running 64-bit Python |
| is_64_bit = sys.maxsize > 2**32 |
| |
| # Check if this is a debug build of Python. |
| # if hasattr(sys, 'gettotalrefcount'): |
| # build_type = 'Debug' |
| # else: |
| # build_type = 'Release' |
| |
| build_type = 'Debug' |
| |
| if Cython.__version__ < '0.19.1': |
| raise Exception('Please upgrade to Cython 0.19.1 or newer') |
| |
| MAJOR = 0 |
| MINOR = 1 |
| MICRO = 0 |
| VERSION = '%d.%d.%ddev' % (MAJOR, MINOR, MICRO) |
| |
| |
| class clean(_clean): |
| |
| def run(self): |
| _clean.run(self) |
| for x in []: |
| try: |
| os.remove(x) |
| except OSError: |
| pass |
| |
| |
| class build_ext(_build_ext): |
| |
| def build_extensions(self): |
| numpy_incl = pkg_resources.resource_filename('numpy', 'core/include') |
| |
| self.extensions = [ext for ext in self.extensions |
| if ext.name != '__dummy__'] |
| |
| for ext in self.extensions: |
| if (hasattr(ext, 'include_dirs') and |
| numpy_incl not in ext.include_dirs): |
| ext.include_dirs.append(numpy_incl) |
| _build_ext.build_extensions(self) |
| |
| def run(self): |
| self._run_cmake() |
| _build_ext.run(self) |
| |
| # adapted from cmake_build_ext in dynd-python |
| # github.com/libdynd/dynd-python |
| |
| description = "Build the C-extensions for arrow" |
| user_options = ([('extra-cmake-args=', None, |
| 'extra arguments for CMake')] + |
| _build_ext.user_options) |
| |
| def initialize_options(self): |
| _build_ext.initialize_options(self) |
| self.extra_cmake_args = '' |
| |
| def _run_cmake(self): |
| # The directory containing this setup.py |
| source = osp.dirname(osp.abspath(__file__)) |
| |
| # The staging directory for the module being built |
| build_temp = pjoin(os.getcwd(), self.build_temp) |
| build_lib = os.path.join(os.getcwd(), self.build_lib) |
| |
| # Change to the build directory |
| saved_cwd = os.getcwd() |
| if not os.path.isdir(self.build_temp): |
| self.mkpath(self.build_temp) |
| os.chdir(self.build_temp) |
| |
| # Detect if we built elsewhere |
| if os.path.isfile('CMakeCache.txt'): |
| cachefile = open('CMakeCache.txt', 'r') |
| cachedir = re.search('CMAKE_CACHEFILE_DIR:INTERNAL=(.*)', |
| cachefile.read()).group(1) |
| cachefile.close() |
| if (cachedir != build_temp): |
| return |
| |
| pyexe_option = '-DPYTHON_EXECUTABLE=%s' % sys.executable |
| static_lib_option = '' |
| build_tests_option = '' |
| |
| if sys.platform != 'win32': |
| cmake_command = ['cmake', self.extra_cmake_args, pyexe_option, |
| build_tests_option, |
| static_lib_option, source] |
| |
| self.spawn(cmake_command) |
| args = ['make', 'VERBOSE=1'] |
| if 'PYARROW_PARALLEL' in os.environ: |
| args.append('-j{0}'.format(os.environ['PYARROW_PARALLEL'])) |
| self.spawn(args) |
| else: |
| import shlex |
| cmake_generator = 'Visual Studio 14 2015' |
| if is_64_bit: |
| cmake_generator += ' Win64' |
| # Generate the build files |
| extra_cmake_args = shlex.split(self.extra_cmake_args) |
| cmake_command = (['cmake'] + extra_cmake_args + |
| [source, pyexe_option, |
| static_lib_option, |
| build_tests_option, |
| '-G', cmake_generator]) |
| if "-G" in self.extra_cmake_args: |
| cmake_command = cmake_command[:-2] |
| |
| self.spawn(cmake_command) |
| # Do the build |
| self.spawn(['cmake', '--build', '.', '--config', build_type]) |
| |
| if self.inplace: |
| # a bit hacky |
| build_lib = saved_cwd |
| |
| # Move the built libpyarrow library to the place expected by the Python |
| # build |
| if sys.platform != 'win32': |
| name, = glob.glob('libpyarrow.*') |
| try: |
| os.makedirs(pjoin(build_lib, 'pyarrow')) |
| except OSError: |
| pass |
| shutil.move(name, pjoin(build_lib, 'pyarrow', name)) |
| else: |
| shutil.move(pjoin(build_type, 'pyarrow.dll'), |
| pjoin(build_lib, 'pyarrow', 'pyarrow.dll')) |
| |
| # Move the built C-extension to the place expected by the Python build |
| self._found_names = [] |
| for name in self.get_cmake_cython_names(): |
| built_path = self.get_ext_built(name) |
| if not os.path.exists(built_path): |
| print(built_path) |
| raise RuntimeError('libpyarrow C-extension failed to build:', |
| os.path.abspath(built_path)) |
| |
| ext_path = pjoin(build_lib, self._get_cmake_ext_path(name)) |
| if os.path.exists(ext_path): |
| os.remove(ext_path) |
| self.mkpath(os.path.dirname(ext_path)) |
| print('Moving built libpyarrow C-extension', built_path, |
| 'to build path', ext_path) |
| shutil.move(self.get_ext_built(name), ext_path) |
| self._found_names.append(name) |
| |
| os.chdir(saved_cwd) |
| |
| def _get_inplace_dir(self): |
| pass |
| |
| def _get_cmake_ext_path(self, name): |
| # Get the package directory from build_py |
| build_py = self.get_finalized_command('build_py') |
| package_dir = build_py.get_package_dir('pyarrow') |
| # This is the name of the arrow C-extension |
| suffix = sysconfig.get_config_var('EXT_SUFFIX') |
| if suffix is None: |
| suffix = sysconfig.get_config_var('SO') |
| filename = name + suffix |
| return pjoin(package_dir, filename) |
| |
| def get_ext_built(self, name): |
| if sys.platform == 'win32': |
| head, tail = os.path.split(name) |
| suffix = sysconfig.get_config_var('SO') |
| return pjoin(head, build_type, tail + suffix) |
| else: |
| suffix = sysconfig.get_config_var('SO') |
| return name + suffix |
| |
| def get_cmake_cython_names(self): |
| return ['array', |
| 'config', |
| 'error', |
| 'io', |
| 'parquet', |
| 'scalar', |
| 'schema', |
| 'table'] |
| |
| def get_names(self): |
| return self._found_names |
| |
| def get_outputs(self): |
| # Just the C extensions |
| # regular_exts = _build_ext.get_outputs(self) |
| return [self._get_cmake_ext_path(name) |
| for name in self.get_names()] |
| |
| |
| DESC = """\ |
| Python library for Apache Arrow""" |
| |
| setup( |
| name="pyarrow", |
| packages=['pyarrow', 'pyarrow.tests'], |
| version=VERSION, |
| zip_safe=False, |
| package_data={'pyarrow': ['*.pxd', '*.pyx']}, |
| # Dummy extension to trigger build_ext |
| ext_modules=[Extension('__dummy__', sources=[])], |
| |
| cmdclass={ |
| 'clean': clean, |
| 'build_ext': build_ext |
| }, |
| install_requires=['cython >= 0.23', 'numpy >= 1.9'], |
| description=DESC, |
| license='Apache License, Version 2.0', |
| maintainer="Apache Arrow Developers", |
| maintainer_email="dev@arrow.apache.org", |
| test_suite="pyarrow.tests" |
| ) |