Skip to content

Commit 67043d1

Browse files
authored
MSVC complex values (#68)
* MSVC complex values * Give build.py a more unique name
1 parent 97fc4f9 commit 67043d1

File tree

4 files changed

+85
-42
lines changed

4 files changed

+85
-42
lines changed

MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
include setup.py
2+
include build_graphblas_cffi.py
23
include README.md
34
include LICENSE
45
include suitesparse_graphblas/*.pxd

build_graphblas_cffi.py

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import os
2+
import sys
3+
from pathlib import Path
4+
5+
from cffi import FFI
6+
from setuptools import Extension
7+
8+
is_win = sys.platform.startswith("win")
9+
ss_g = Path(__file__).parent / "suitesparse_graphblas"
10+
11+
ffibuilder = FFI()
12+
13+
include_dirs = [os.path.join(sys.prefix, "include")]
14+
library_dirs = [os.path.join(sys.prefix, "lib")]
15+
if is_win:
16+
include_dirs.append(os.path.join(sys.prefix, "Library", "include"))
17+
library_dirs.append(os.path.join(sys.prefix, "Library", "lib"))
18+
19+
ffibuilder.set_source(
20+
"suitesparse_graphblas._graphblas",
21+
(ss_g / "source.c").read_text(),
22+
libraries=["graphblas"],
23+
include_dirs=include_dirs,
24+
library_dirs=library_dirs,
25+
)
26+
27+
ffibuilder.cdef((ss_g / "suitesparse_graphblas.h").read_text())
28+
29+
30+
def get_extension(apply_msvc_patch: bool = None, extra_compile_args=()):
31+
"""
32+
Get a setuptools.Extension version of this CFFI builder.
33+
34+
In other words, enables `setup(ext_modules=[get_extension()])`
35+
instead of `setup(cffi_modules=["build_graphblas_cffi.py:ffibuilder"])`.
36+
37+
The main reason for this is to allow a patch for complex values when compiling on MSVC.
38+
MSVC famously lacks support for standard C complex types like `double _Complex` and
39+
`float _Complex`. Instead, MSVC has its own `_Dcomplex` and `_Fcomplex` types.
40+
Cffi's machinery cannot be made to work with these types, so we instead
41+
emit the regular standard C code and patch it manually.
42+
43+
:param apply_msvc_patch: whether to apply the MSVC patch.
44+
If None then auto-detect based on platform.
45+
:param extra_compile_args: forwarded to Extension constructor.
46+
"""
47+
code_path = ss_g / "_graphblas.c"
48+
ffibuilder.emit_c_code(str(code_path))
49+
50+
if apply_msvc_patch is None:
51+
apply_msvc_patch = is_win
52+
53+
if apply_msvc_patch:
54+
msvc_code = code_path.read_text()
55+
msvc_code = msvc_code.replace("float _Complex", "_Fcomplex")
56+
msvc_code = msvc_code.replace("double _Complex", "_Dcomplex")
57+
code_path.write_text(msvc_code)
58+
59+
return Extension(
60+
"suitesparse_graphblas._graphblas",
61+
[os.path.join("suitesparse_graphblas", "_graphblas.c")],
62+
libraries=["graphblas"],
63+
include_dirs=include_dirs,
64+
library_dirs=library_dirs,
65+
extra_compile_args=extra_compile_args,
66+
)
67+
68+
69+
if __name__ == "__main__":
70+
ffibuilder.compile(verbose=True)

setup.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
import numpy as np
66
from setuptools import Extension, setup
77

8+
# Add current directory to the Python path because it's not present when running `pip install .`
9+
sys.path.append(os.path.dirname(__file__))
10+
import build_graphblas_cffi # noqa: E402 # isort:skip
11+
812
try:
913
from Cython.Build import cythonize
1014
from Cython.Compiler.Options import get_directive_defaults
@@ -15,6 +19,13 @@
1519

1620
define_macros = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
1721

22+
# /d2FH4- flag needed only for early Python 3.8 builds on Windows.
23+
# See https://cibuildwheel.readthedocs.io/en/stable/faq/
24+
# (Search for flag on page. Full link is long and causes the linter to fail the tests.)
25+
#
26+
# The /std:c11 flag is because the MSVC default is C89.
27+
extra_compile_args = ["/d2FH4-", "/std:c11"] if sys.platform == "win32" else []
28+
1829
if use_cython:
1930
suffix = ".pyx"
2031
directive_defaults = get_directive_defaults()
@@ -40,13 +51,15 @@
4051
[name],
4152
include_dirs=include_dirs,
4253
define_macros=define_macros,
54+
extra_compile_args=extra_compile_args,
4355
)
4456
for name in glob(f"suitesparse_graphblas/**/*{suffix}", recursive=True)
4557
]
4658
if use_cython:
4759
ext_modules = cythonize(ext_modules, include_path=include_dirs)
4860

61+
ext_modules.append(build_graphblas_cffi.get_extension(extra_compile_args=extra_compile_args))
62+
4963
setup(
5064
ext_modules=ext_modules,
51-
cffi_modules=["suitesparse_graphblas/build.py:ffibuilder"],
5265
)

suitesparse_graphblas/build.py

-41
This file was deleted.

0 commit comments

Comments
 (0)