Skip to content

Commit

Permalink
MSVC complex values (GraphBLAS#68)
Browse files Browse the repository at this point in the history
* MSVC complex values

* Give build.py a more unique name
  • Loading branch information
alugowski authored Feb 13, 2023
1 parent 97fc4f9 commit 67043d1
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 42 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include setup.py
include build_graphblas_cffi.py
include README.md
include LICENSE
include suitesparse_graphblas/*.pxd
Expand Down
70 changes: 70 additions & 0 deletions build_graphblas_cffi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import os
import sys
from pathlib import Path

from cffi import FFI
from setuptools import Extension

is_win = sys.platform.startswith("win")
ss_g = Path(__file__).parent / "suitesparse_graphblas"

ffibuilder = FFI()

include_dirs = [os.path.join(sys.prefix, "include")]
library_dirs = [os.path.join(sys.prefix, "lib")]
if is_win:
include_dirs.append(os.path.join(sys.prefix, "Library", "include"))
library_dirs.append(os.path.join(sys.prefix, "Library", "lib"))

ffibuilder.set_source(
"suitesparse_graphblas._graphblas",
(ss_g / "source.c").read_text(),
libraries=["graphblas"],
include_dirs=include_dirs,
library_dirs=library_dirs,
)

ffibuilder.cdef((ss_g / "suitesparse_graphblas.h").read_text())


def get_extension(apply_msvc_patch: bool = None, extra_compile_args=()):
"""
Get a setuptools.Extension version of this CFFI builder.
In other words, enables `setup(ext_modules=[get_extension()])`
instead of `setup(cffi_modules=["build_graphblas_cffi.py:ffibuilder"])`.
The main reason for this is to allow a patch for complex values when compiling on MSVC.
MSVC famously lacks support for standard C complex types like `double _Complex` and
`float _Complex`. Instead, MSVC has its own `_Dcomplex` and `_Fcomplex` types.
Cffi's machinery cannot be made to work with these types, so we instead
emit the regular standard C code and patch it manually.
:param apply_msvc_patch: whether to apply the MSVC patch.
If None then auto-detect based on platform.
:param extra_compile_args: forwarded to Extension constructor.
"""
code_path = ss_g / "_graphblas.c"
ffibuilder.emit_c_code(str(code_path))

if apply_msvc_patch is None:
apply_msvc_patch = is_win

if apply_msvc_patch:
msvc_code = code_path.read_text()
msvc_code = msvc_code.replace("float _Complex", "_Fcomplex")
msvc_code = msvc_code.replace("double _Complex", "_Dcomplex")
code_path.write_text(msvc_code)

return Extension(
"suitesparse_graphblas._graphblas",
[os.path.join("suitesparse_graphblas", "_graphblas.c")],
libraries=["graphblas"],
include_dirs=include_dirs,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
)


if __name__ == "__main__":
ffibuilder.compile(verbose=True)
15 changes: 14 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import numpy as np
from setuptools import Extension, setup

# Add current directory to the Python path because it's not present when running `pip install .`
sys.path.append(os.path.dirname(__file__))
import build_graphblas_cffi # noqa: E402 # isort:skip

try:
from Cython.Build import cythonize
from Cython.Compiler.Options import get_directive_defaults
Expand All @@ -15,6 +19,13 @@

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

# /d2FH4- flag needed only for early Python 3.8 builds on Windows.
# See https://cibuildwheel.readthedocs.io/en/stable/faq/
# (Search for flag on page. Full link is long and causes the linter to fail the tests.)
#
# The /std:c11 flag is because the MSVC default is C89.
extra_compile_args = ["/d2FH4-", "/std:c11"] if sys.platform == "win32" else []

if use_cython:
suffix = ".pyx"
directive_defaults = get_directive_defaults()
Expand All @@ -40,13 +51,15 @@
[name],
include_dirs=include_dirs,
define_macros=define_macros,
extra_compile_args=extra_compile_args,
)
for name in glob(f"suitesparse_graphblas/**/*{suffix}", recursive=True)
]
if use_cython:
ext_modules = cythonize(ext_modules, include_path=include_dirs)

ext_modules.append(build_graphblas_cffi.get_extension(extra_compile_args=extra_compile_args))

setup(
ext_modules=ext_modules,
cffi_modules=["suitesparse_graphblas/build.py:ffibuilder"],
)
41 changes: 0 additions & 41 deletions suitesparse_graphblas/build.py

This file was deleted.

0 comments on commit 67043d1

Please sign in to comment.