blob: 759abab33f2368632844fe874c7c34a0abbd84ad [file] [log] [blame]
# 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},
)