1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
# Copyright (c) 2020 Leiden University Medical Center
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022
# Python Software Foundation; All Rights Reserved
# This file is part of python-isal which is distributed under the
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2.
import functools
import os
import platform
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from setuptools import Extension, find_packages, setup
from setuptools.command.build_ext import build_ext
def _get_version():
version = subprocess.check_output(['dpkg-parsechangelog', '-SVersion'],
text=True).split('-')[0]
with open('src/isal/_version.py', 'w') as fd:
fd.write('__version__ = "%s"' % version)
ISA_L_SOURCE = os.path.join("src", "isal", "isa-l")
SYSTEM_IS_BSD = (sys.platform.startswith("freebsd") or
sys.platform.startswith("netbsd"))
SYSTEM_IS_UNIX = (sys.platform.startswith("linux") or
sys.platform.startswith("darwin") or
sys.platform.startswith("gnu") or
SYSTEM_IS_BSD)
SYSTEM_IS_WINDOWS = sys.platform.startswith("win")
# Since pip builds in a temp directory by default, setting a fixed file in
# /tmp works during the entire session.
DEFAULT_CACHE_FILE = Path(tempfile.gettempdir()
).absolute() / ".isal_build_cache"
BUILD_CACHE = os.environ.get("PYTHON_ISAL_BUILD_CACHE")
BUILD_CACHE_FILE = Path(os.environ.get("PYTHON_ISAL_BUILD_CACHE_FILE",
DEFAULT_CACHE_FILE))
EXTENSIONS = [
Extension("isal.isal_zlib", ["src/isal/isal_zlibmodule.c"]),
Extension("isal.igzip_lib", ["src/isal/igzip_libmodule.c"]),
Extension("isal._isal", ["src/isal/_isalmodule.c"]),
]
class BuildIsalExt(build_ext):
def build_extension(self, ext):
# Add option to link dynamically for packaging systems such as conda.
# Always link dynamically on readthedocs to simplify install.
if (os.getenv("PYTHON_ISAL_LINK_DYNAMIC") is not None or
os.environ.get("READTHEDOCS") is not None):
# Check for isa-l include directories. This is useful when
# installing in a conda environment.
possible_prefixes = [sys.exec_prefix, sys.base_exec_prefix]
for prefix in possible_prefixes:
if Path(prefix, "include", "isa-l").exists():
ext.include_dirs = [os.path.join(prefix, "include")]
ext.library_dirs = [os.path.join(prefix, "lib")]
break # Only one include directory is needed.
# On windows include is in Library apparently
elif Path(prefix, "Library", "include", "isa-l").exists():
ext.include_dirs = [os.path.join(prefix, "Library",
"include")]
ext.library_dirs = [os.path.join(prefix, "Library", "lib")]
break
if SYSTEM_IS_UNIX:
ext.libraries = ["isal"] # libisal.so*
elif SYSTEM_IS_WINDOWS:
ext.libraries = ["isa-l"] # isa-l.dll
else:
raise NotImplementedError(
f"Unsupported platform: {sys.platform}")
else:
isa_l_build_dir = build_isa_l()
if SYSTEM_IS_UNIX:
ext.extra_objects = [
os.path.join(isa_l_build_dir, "bin", "isa-l.a")]
elif SYSTEM_IS_WINDOWS:
ext.extra_objects = [
os.path.join(isa_l_build_dir, "isa-l_static.lib")]
else:
raise NotImplementedError(
f"Unsupported platform: {sys.platform}")
ext.include_dirs = [isa_l_build_dir]
super().build_extension(ext)
# Use a cache to prevent isa-l from being build twice. According to the
# functools docs lru_cache with maxsize None is faster. The shortcut called
# 'cache' is only available from python 3.9 onwards.
# see: https://docs.python.org/3/library/functools.html#functools.cache
@functools.lru_cache(maxsize=None)
def build_isa_l():
# Check for cache
if BUILD_CACHE:
if BUILD_CACHE_FILE.exists():
cache_path = Path(BUILD_CACHE_FILE.read_text())
if (cache_path / "isa-l.h").exists():
return str(cache_path)
# Creating temporary directories
build_dir = tempfile.mktemp()
shutil.copytree(ISA_L_SOURCE, build_dir)
# Build environment is a copy of OS environment to allow user to influence
# it.
build_env = os.environ.copy()
if SYSTEM_IS_UNIX:
build_env["CFLAGS"] = build_env.get("CFLAGS", "") + " -fPIC"
if hasattr(os, "sched_getaffinity"):
cpu_count = len(os.sched_getaffinity(0))
else: # sched_getaffinity not available on all platforms
cpu_count = os.cpu_count() or 1 # os.cpu_count() can return None
run_args = dict(cwd=build_dir, env=build_env)
if SYSTEM_IS_UNIX:
if platform.machine() == "aarch64":
cflags_param = "CFLAGS_aarch64"
else:
cflags_param = "CFLAGS_"
make_cmd = "make"
if SYSTEM_IS_BSD:
make_cmd = "gmake"
subprocess.run([make_cmd, "-j", str(cpu_count), "-f", "Makefile.unx",
"isa-l.h", "bin/isa-l.a",
f"{cflags_param}={build_env.get('CFLAGS', '')}"],
**run_args)
elif SYSTEM_IS_WINDOWS:
subprocess.run(["nmake", "/f", "Makefile.nmake"], **run_args)
else:
raise NotImplementedError(f"Unsupported platform: {sys.platform}")
shutil.copytree(os.path.join(build_dir, "include"),
os.path.join(build_dir, "isa-l"))
if BUILD_CACHE:
BUILD_CACHE_FILE.write_text(build_dir)
return build_dir
setup(
name="isal",
version=_get_version(),
description="Faster zlib and gzip compatible compression and "
"decompression by providing python bindings for the ISA-L "
"library.",
author="Leiden University Medical Center",
author_email="r.h.p.vorderman@lumc.nl", # A placeholder for now
long_description=Path("README.rst").read_text(),
long_description_content_type="text/x-rst",
cmdclass={"build_ext": BuildIsalExt},
license="PSF-2.0",
keywords="isal isa-l compression deflate gzip igzip threads",
zip_safe=False,
packages=find_packages('src'),
package_dir={'': 'src'},
package_data={'isal': ['*.pyi', 'py.typed',
# Include isa-l LICENSE and other relevant files
# with the binary distribution.
'isa-l/LICENSE', 'isa-l/README.md',
'isa-l/Release_notes.txt']},
url="https://github.com/pycompression/python-isal",
classifiers=[
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Programming Language :: C",
"Development Status :: 5 - Production/Stable",
"Topic :: System :: Archiving :: Compression",
"License :: OSI Approved :: Python Software Foundation License",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
],
python_requires=">=3.8", # BadGzipFile imported
ext_modules=EXTENSIONS
)
|