Skip to content

MSVC complex values #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.