|
| 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) |
0 commit comments