#!/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 os
import subprocess
import sys
from pathlib import Path
from setuptools import Extension, setup
# https://github.com/jbweston/miniver
def get_version(pkg_path):
"""
Load version.py module without importing the whole package.
Template code from miniver.
"""
from importlib.util import module_from_spec, spec_from_file_location
spec = spec_from_file_location("version", os.path.join(pkg_path, "_version.py"))
module = module_from_spec(spec)
spec.loader.exec_module(module)
return module.__version__
version = get_version("src/nanoarrow")
# Run bootstrap.py to run cmake generating a fresh bundle based on this
# checkout or copy from ../dist if the caller doesn't have cmake available.
# Note that bootstrap.py won't exist if building from sdist.
this_dir = os.path.dirname(__file__)
bootstrap_py = os.path.join(this_dir, "bootstrap.py")
if os.path.exists(bootstrap_py):
subprocess.run([sys.executable, bootstrap_py])
# Set some extra flags for compiling with coverage support
extra_compile_args = []
extra_link_args = []
extra_define_macros = []
device_include_dirs = []
device_library_dirs = []
device_libraries = []
device_define_macros = []
if os.getenv("NANOARROW_PYTHON_COVERAGE") == "1":
extra_compile_args.append("--coverage")
extra_link_args.append("--coverage")
extra_define_macros.append(("CYTHON_TRACE", 1))
if os.getenv("NANOARROW_DEBUG_EXTENSION") == "1":
extra_compile_args.extend(["-g", "-O0"])
cuda_toolkit_root = os.getenv("NANOARROW_PYTHON_CUDA_HOME")
if cuda_toolkit_root:
cuda_lib = "cuda.lib" if os.name == "nt" else "libcuda.so"
include_dir = Path(cuda_toolkit_root) / "include"
possible_libs = [
Path(cuda_toolkit_root) / "lib" / cuda_lib,
Path(cuda_toolkit_root) / "lib64" / cuda_lib,
Path(cuda_toolkit_root) / "lib" / "x64" / cuda_lib,
Path("/usr/lib/wsl/lib") / cuda_lib,
]
if not include_dir.is_dir():
raise ValueError(f"CUDA include directory does not exist: '{include_dir}'")
device_include_dirs.append(str(include_dir))
device_libraries.append("cuda")
extra_define_macros.append(("NANOARROW_DEVICE_WITH_CUDA", 1))
# Library might be already in a system library directory such that no -L flag
# is needed
lib_dirs = [d for d in possible_libs if d.exists()]
if lib_dirs:
device_library_dirs.append(str(lib_dirs[0].parent))
# This mechanism to build a static c library against which extensions
# can be linked is not well documented but is a better solution than
# simply including these files as sources to the extensions that need
# them. A more robust solution would be to use Meson or CMake to build
# the Python extensions since they can both build a shared nanoarrow
# and link it. This mechanism is the build_clib command available in
# setuptools (and previously from distutils).
common_libraries = [
[
"nanoarrow_python_shared",
{
"sources": [
"vendor/nanoarrow.c",
"vendor/nanoarrow_device.c",
"vendor/nanoarrow_ipc.c",
"vendor/flatcc.c",
],
"include_dirs": ["vendor"] + device_include_dirs,
"libraries": device_libraries,
"library_dirs": device_library_dirs,
"macros": extra_define_macros + device_define_macros,
},
]
]
def nanoarrow_extension(name, *, link_device=False):
return Extension(
name=name,
include_dirs=["vendor", "src/nanoarrow"],
language="c",
sources=["src/" + name.replace(".", "/") + ".pyx"],
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
define_macros=extra_define_macros + device_define_macros,
libraries=["nanoarrow_python_shared"] + device_libraries if link_device else [],
)
setup(
ext_modules=[
nanoarrow_extension("nanoarrow._types"),
nanoarrow_extension("nanoarrow._utils"),
nanoarrow_extension("nanoarrow._device", link_device=True),
nanoarrow_extension("nanoarrow._array", link_device=True),
nanoarrow_extension("nanoarrow._array_stream"),
nanoarrow_extension("nanoarrow._buffer"),
nanoarrow_extension("nanoarrow._ipc_lib"),
nanoarrow_extension("nanoarrow._schema"),
],
version=version,
libraries=common_libraries,
)