create PLU decomposition
[liba.git] / setup.py
blobef93a6c4ce54698111448d4539a9286b70a1067b
1 #!/usr/bin/env python
2 try:
3 from setuptools.command.build_ext import build_ext
4 from setuptools import setup, Extension
5 except ImportError:
6 from distutils.command.build_ext import build_ext
7 from distutils.extension import Extension
8 from distutils.core import setup
9 try:
10 USE_CYTHON = 1
11 from Cython.Build import cythonize
12 except ImportError:
13 USE_CYTHON = 0
14 from subprocess import Popen
15 from argparse import ArgumentParser
16 from sys import byteorder
17 from re import findall
18 import os, sys, ctypes
19 import ctypes.util
22 def find_executable(*executable):
23 if sys.platform == "win32":
24 exe = []
25 for e in executable:
26 exe.append(e + ".exe")
27 executable = exe
28 path = os.environ.get("PATH", "")
29 for p in path.split(os.pathsep):
30 for e in executable:
31 f = os.path.join(p, e)
32 if os.path.isfile(f):
33 return f
34 return None
37 def strtobool(s):
38 if s.lower() in ("1", "y", "yes", "true"):
39 return 1
40 return 0
43 os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
44 if len(sys.argv) < 2:
45 sys.argv += ["--quiet", "build_ext", "--inplace"]
46 if USE_CYTHON == 0:
47 CYTHON = find_executable("cython3", "cython")
48 LIBA_OPENMP = os.environ.get("LIBA_OPENMP")
49 if LIBA_OPENMP:
50 LIBA_OPENMP = strtobool(LIBA_OPENMP)
51 LIBA_FLOAT = os.environ.get("LIBA_FLOAT")
52 if LIBA_FLOAT:
53 LIBA_FLOAT = int(LIBA_FLOAT)
54 else:
55 LIBA_FLOAT = 8
58 def check_math(text=""):
59 if sys.platform == "win32":
60 path_libm = ctypes.util.find_library("ucrtbase")
61 if not path_libm:
62 path_libm = ctypes.util.find_msvcrt()
63 else:
64 path_libm = ctypes.util.find_library("m")
65 try:
66 libm = ctypes.CDLL(path_libm)
67 except Exception:
68 return text
69 for func in (
70 "asinh",
71 "acosh",
72 "atanh",
73 "expm1",
74 "log1p",
75 "atan2",
76 "hypot",
77 "csqrt",
78 "cpow",
79 "cexp",
80 "clog",
81 "csin",
82 "ccos",
83 "ctan",
84 "csinh",
85 "ccosh",
86 "ctanh",
87 "casin",
88 "cacos",
89 "catan",
90 "casinh",
91 "cacosh",
92 "catanh",
94 name = "A_HAVE_" + func.upper()
95 if LIBA_FLOAT == 0x10:
96 func += "l"
97 if LIBA_FLOAT == 0x04:
98 func += "f"
99 try:
100 libm[func]
101 except Exception:
102 continue
103 text += "#define %s 1\n" % (name)
104 return text
107 def configure(config):
108 with open("setup.cfg", "r") as f:
109 version = findall(r"version = (\S+)", f.read())[0]
110 major, minor, patch = findall(r"(\d+).(\d+).(\d+)", version)[0]
111 order = {"little": 1234, "big": 4321}.get(byteorder)
112 vsize = ctypes.sizeof(ctypes.c_void_p(0))
113 text = """/* autogenerated by setup.py */
114 #define A_VERSION "{}"
115 #define A_VERSION_MAJOR {}
116 #define A_VERSION_MINOR {}
117 #define A_VERSION_PATCH {}
118 #if !defined A_SIZE_POINTER
119 #define A_SIZE_POINTER {}
120 #endif /* A_SIZE_POINTER */
121 #if !defined A_BYTE_ORDER
122 #define A_BYTE_ORDER {}
123 #endif /* A_BYTE_ORDER */
124 {}""".format(
125 version, major, minor, patch, vsize, order, check_math()
127 with open(config, "wb") as f:
128 f.write(text.encode("UTF-8"))
131 parser = ArgumentParser(add_help=False)
132 parser.add_argument("-b", "--build-base", default="build")
133 parser.add_argument("-O", "--link-objects")
134 args = parser.parse_known_args(sys.argv[1:])
135 base = args[0].build_base
137 sources, objects = [], []
138 config_h = os.path.join(base, "a.setup.h")
139 a_have_h = os.path.relpath(config_h, "include/a")
140 define_macros = [("A_HAVE_H", '"' + a_have_h + '"'), ("A_EXPORTS", None)]
141 if LIBA_FLOAT != 8:
142 define_macros += [("A_SIZE_FLOAT", LIBA_FLOAT)]
143 if USE_CYTHON and os.path.exists("python/src/liba.pyx"):
144 sources += ["python/src/liba.pyx"]
145 elif CYTHON or os.path.exists("python/src/liba.c"):
146 sources += ["python/src/liba.c"]
147 if not os.path.exists(base):
148 os.makedirs(base)
149 configure(config_h)
151 for dirpath, dirnames, filenames in os.walk("src"):
152 if args[0].link_objects:
153 break
154 for filename in filenames:
155 source = os.path.join(dirpath, filename)
156 if os.path.splitext(source)[-1] == ".c":
157 sources.append(source)
159 ext_modules = [
160 Extension(
161 name="liba",
162 language="c",
163 sources=sorted(sources),
164 include_dirs=["include"],
165 define_macros=define_macros,
168 if USE_CYTHON:
169 ext_modules = cythonize(ext_modules, quiet=True)
170 elif CYTHON:
171 Popen([CYTHON, "--fast-fail", "python/src/liba.pyx"]).wait()
174 class Build(build_ext): # type: ignore
175 def build_extensions(self):
176 if self.compiler.compiler_type == "msvc":
177 for e in self.extensions:
178 if LIBA_OPENMP:
179 e.extra_compile_args += ["/openmp"]
180 if not self.compiler.compiler_type == "msvc":
181 for e in self.extensions:
182 if LIBA_OPENMP:
183 e.extra_compile_args += ["-fopenmp"]
184 e.extra_link_args += ["-fopenmp"]
185 if self.compiler.compiler_type == "mingw32":
186 self.compiler.define_macro("__USE_MINGW_ANSI_STDIO", 1)
187 for e in self.extensions:
188 if e.language == "c++":
189 e.extra_link_args += ["-static-libstdc++"]
190 e.extra_link_args += ["-static-libgcc"]
191 e.extra_link_args += [
192 "-Wl,-Bstatic,--whole-archive",
193 "-lwinpthread",
194 "-Wl,--no-whole-archive",
196 build_ext.build_extensions(self)
199 setup(
200 ext_modules=ext_modules, # type: ignore
201 cmdclass={"build_ext": Build},