| # 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 platform |
| import shutil |
| import sys |
| import numpy as np |
| |
| from pathlib import Path |
| from Cython.Build import cythonize |
| from setuptools import setup, Extension |
| from setuptools.command.build_ext import build_ext |
| |
| ROOT = Path(__file__).parent.resolve() |
| PKG = ROOT / "tsfile" |
| CPP_OUT = ROOT / ".." / "cpp" / "target" / "build" |
| CPP_LIB = CPP_OUT / "lib" |
| CPP_INC = CPP_OUT / "include" |
| |
| version = "2.2.1.dev" |
| |
| if not CPP_INC.exists(): |
| raise FileNotFoundError(f"missing C++ headers: {CPP_INC}") |
| if (PKG / "include").exists(): |
| shutil.rmtree(PKG / "include") |
| shutil.copytree(CPP_INC, PKG / "include") |
| if sys.platform.startswith("linux"): |
| candidates = sorted(CPP_LIB.glob("libtsfile.so*"), key=lambda p: len(p.name), reverse=True) |
| if not candidates: |
| raise FileNotFoundError("missing libtsfile.so* in build output") |
| src = candidates[0] |
| dst = PKG / src.name |
| shutil.copy2(src, dst) |
| link_name = PKG / "libtsfile.so" |
| shutil.copy2(src, link_name) |
| |
| elif sys.platform == "darwin": |
| candidates = sorted(CPP_LIB.glob("libtsfile.*.dylib")) or list(CPP_LIB.glob("libtsfile.dylib")) |
| if not candidates: |
| raise FileNotFoundError("missing libtsfile*.dylib in build output") |
| src = candidates[0] |
| dst = PKG / src.name |
| shutil.copy2(src, dst) |
| link_name = PKG / "libtsfile.dylib" |
| shutil.copy2(src, link_name) |
| elif sys.platform == "win32": |
| for base_name in ("libtsfile",): |
| dll_candidates = sorted(CPP_LIB.glob(f"{base_name}*.dll"), key=lambda p: len(p.name), reverse=True) |
| dll_a_candidates = sorted(CPP_LIB.glob(f"{base_name}*.dll.a"), key=lambda p: len(p.name), reverse=True) |
| |
| if not dll_candidates: |
| raise FileNotFoundError(f"missing {base_name}*.dll in build output") |
| if not dll_a_candidates: |
| raise FileNotFoundError(f"missing {base_name}*.dll.a in build output") |
| |
| dll_src = dll_candidates[0] |
| dll_a_src = dll_a_candidates[0] |
| |
| shutil.copy2(dll_src, PKG / f"{base_name}.dll") |
| shutil.copy2(dll_a_src, PKG / f"{base_name}.dll.a") |
| |
| # Copy MinGW runtime DLLs next to libtsfile.dll so Python can find them. |
| # Python 3.8+ does not search PATH for DLLs; they must be in the same |
| # directory as the .pyd extensions (registered via os.add_dll_directory). |
| for _mingw_dll in ("libstdc++-6.dll", "libgcc_s_seh-1.dll", "libwinpthread-1.dll"): |
| for _dir in os.environ.get("PATH", "").split(os.pathsep): |
| _src = Path(_dir) / _mingw_dll |
| if _src.is_file(): |
| shutil.copy2(_src, PKG / _mingw_dll) |
| print(f"setup.py: copied {_mingw_dll} from {_src}") |
| break |
| else: |
| print(f"setup.py: WARNING - {_mingw_dll} not found on PATH") |
| else: |
| raise RuntimeError(f"Unsupported platform: {sys.platform}") |
| |
| |
| class BuildExt(build_ext): |
| def run(self): |
| super().run() |
| |
| def finalize_options(self): |
| if sys.platform == "win32": |
| self.compiler = "mingw32" |
| super().finalize_options() |
| |
| |
| extra_compile_args = [] |
| extra_link_args = [] |
| runtime_library_dirs = [] |
| libraries = [] |
| library_dirs = [str(PKG)] |
| include_dirs = [str(PKG), np.get_include(), str(PKG / "include")] |
| |
| if sys.platform.startswith("linux"): |
| libraries = ["tsfile"] |
| extra_compile_args += ["-O3", "-std=c++11", "-fvisibility=hidden", "-fPIC"] |
| runtime_library_dirs = ["$ORIGIN"] |
| extra_link_args += ["-Wl,-rpath,$ORIGIN"] |
| elif sys.platform == "darwin": |
| libraries = ["tsfile"] |
| extra_compile_args += ["-O3", "-std=c++11", "-fvisibility=hidden", "-fPIC"] |
| extra_link_args += ["-Wl,-rpath,@loader_path", "-stdlib=libc++"] |
| elif sys.platform == "win32": |
| libraries = ["tsfile"] |
| extra_compile_args += ["-O2", "-std=c++11", "-DSIZEOF_VOID_P=8", "-D__USE_MINGW_ANSI_STDIO=1", "-DMS_WIN64", |
| "-D_WIN64"] |
| extra_link_args += [] |
| else: |
| raise RuntimeError(f"Unsupported platform: {sys.platform}") |
| |
| common = dict( |
| language="c++", |
| include_dirs=include_dirs, |
| library_dirs=library_dirs, |
| libraries=libraries, |
| extra_compile_args=extra_compile_args, |
| extra_link_args=extra_link_args, |
| runtime_library_dirs=runtime_library_dirs, |
| ) |
| |
| exts = [ |
| Extension("tsfile.tsfile_py_cpp", ["tsfile/tsfile_py_cpp.pyx"], **common), |
| Extension("tsfile.tsfile_reader", ["tsfile/tsfile_reader.pyx"], **common), |
| Extension("tsfile.tsfile_writer", ["tsfile/tsfile_writer.pyx"], **common), |
| ] |
| |
| setup( |
| name="tsfile", |
| version=version, |
| packages=["tsfile"], |
| package_dir={"": "."}, |
| include_package_data=True, |
| ext_modules=cythonize(exts, compiler_directives={"language_level": 3}), |
| cmdclass={"build_ext": BuildExt}, |
| ) |