Skip to content

Commit

Permalink
cufinufft: remove setup.py reliance on ext_modules
Browse files Browse the repository at this point in the history
Just copies the shared object directly into the python package
  • Loading branch information
blackwer committed Dec 12, 2023
1 parent b723d7f commit c4fd0ec
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 82 deletions.
37 changes: 4 additions & 33 deletions python/cufinufft/cufinufft/_cufinufft.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
"""
This file contains low level python bindings for the cufinufft CUDA libraries.
Seperate bindings are provided for single and double precision libraries,
Expand All @@ -7,15 +6,6 @@

import ctypes
import os
import warnings

# While imp is deprecated, it is currently the inspection solution
# that works for all versions of Python 2 and 3.
# One day if that changes, can be replaced
# with importlib.find_spec.
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
import imp

from ctypes import c_double
from ctypes import c_int
Expand All @@ -27,30 +17,11 @@
c_float_p = ctypes.POINTER(c_float)
c_double_p = ctypes.POINTER(c_double)

# TODO: See if there is a way to improve this so it is less hacky.
lib = None
# Try to load a local library directly.
try:
lib = ctypes.cdll.LoadLibrary('libcufinufft.so')
except OSError:
pass

# Should that not work, try to find the full path of a packaged lib.
# The packaged lib should have a py/platform decorated name,
# and be rpath'ed the true CUDA C cufinufft library through the
# Extension and wheel systems.
try:
if lib is None:
# Find the library.
fh = imp.find_module('cufinufft/cufinufftc')[0]
# Get the full path for the ctypes loader.
full_lib_path = os.path.realpath(fh.name)
fh.close() # Be nice and close the open file handle.

# Load the library,
# which rpaths the libraries we care about.
lib = ctypes.cdll.LoadLibrary(full_lib_path)

try:
lib = ctypes.cdll.LoadLibrary(os.path.join(os.path.dirname(__file__), 'libcufinufft.so'))
except:
lib = ctypes.cdll.LoadLibrary('libcufinufft.so')
except Exception:
raise ImportError('Failed to find a suitable cufinufft library')

Expand Down
1 change: 0 additions & 1 deletion python/cufinufft/cufinufft/_plan.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
"""
This module contains the high level python wrapper for
the cufinufft CUDA libraries.
Expand Down
56 changes: 8 additions & 48 deletions python/cufinufft/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import os
import ctypes
from pathlib import Path
import shutil

from tempfile import mkstemp

from setuptools import setup, Extension
from setuptools import setup

# Description
DESCRIPTION = "Non-uniform fast Fourier transforms on the GPU"
Expand All @@ -19,16 +18,14 @@
requirements = [item.strip() for item in fh.readlines()]

cufinufft_dir = os.environ.get('CUFINUFFT_DIR')

if cufinufft_dir == None or cufinufft_dir == '':
if not cufinufft_dir:
cufinufft_dir = Path(__file__).resolve().parents[2]

include_dir = os.path.join(cufinufft_dir, "include")
library_dir = os.path.join(cufinufft_dir, "build")
shared_obj = os.path.join(cufinufft_dir, 'build', 'libcufinufft.so')

# Sanity check that we can find the CUDA cufinufft libraries before we get too far.
# Sanity check that we can find and load the CUDA cufinufft libraries before we get too far.
try:
lib = ctypes.cdll.LoadLibrary(os.path.join(library_dir, 'libcufinufft.so'))
lib = ctypes.cdll.LoadLibrary(shared_obj)
except Exception as e:
print('CUDA shared libraries not found in library path.'
' Please refer to installation documentation at '
Expand All @@ -38,28 +35,7 @@
raise(e)
print('cufinufft CUDA shared libraries found, continuing...')

# For certain platforms (e.g. Ubuntu 20.04), we need to create a dummy source
# that calls one of the functions in the FINUFFT dynamic library. The reason
# is that these platforms override the default --no-as-needed flag for ld,
# which means that the linker will only link to those dynamic libraries for
# which there are unresolved symbols in the object files. Since we do not have
# a real source, the result is that no dynamic libraries are linked. To
# prevent this, we create a dummy source so that the library will link as
# expected.
fd, source_filename = mkstemp(suffix='.c', text=True)

with open(fd, 'w') as f:
f.write( \
"""
#include <cufinufft.h>
void PyInit_cufinufftc(void) {
cufinufft_opts opt;
cufinufft_default_opts(&opt);
}
""")

shutil.copy(shared_obj, os.path.join(os.getcwd(), 'cufinufft'))

# Python Package Setup
setup(
Expand All @@ -74,6 +50,7 @@
license="Apache 2",
packages=['cufinufft'],
package_dir={'': '.'},
package_data={'cufinufft': ['libcufinufft.so']},
install_requires=requirements,
# If you'd like to build or alter the docs you may additionally require these.
extras_require={
Expand All @@ -88,21 +65,4 @@
'Topic :: Scientific/Engineering :: Mathematics'],
python_requires='>=3.6',
zip_safe=False,
# This explicitly tells the wheel systems that we're platform specific.
# Addiitonally, will create a new cPython library with a decorated name
# that is rpath linked to CUDA library, also decorated (by auditwheel).
# Most importantly, pip will manage to install all this stuff in
# in places Python can find it (with a little help).
py_modules=['cufinufft.cufinufftc'],
ext_modules=[
Extension(name='cufinufft.cufinufftc',
sources=[source_filename],
libraries=['cufinufft'],
include_dirs=[include_dir],
library_dirs=[library_dir],
runtime_library_dirs=[library_dir],
)
]
)

os.unlink(source_filename)

0 comments on commit c4fd0ec

Please sign in to comment.