diff --git a/Makefile b/Makefile index 2e4e031..335a863 100644 --- a/Makefile +++ b/Makefile @@ -82,12 +82,7 @@ servedocs: docs ## compile the docs watching for changes watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . dist: clean ## builds source and wheel package - python setup.py sdist - - ./make/osx/build_wheels.sh - - ./make/manylinux1/build_wheels.sh - + python setup.py sdist bdist_wheel ls -l dist release: ## package and upload a release diff --git a/wolfssl/__init__.py b/wolfssl/__init__.py index 95ec4dd..b4f42f0 100644 --- a/wolfssl/__init__.py +++ b/wolfssl/__init__.py @@ -38,8 +38,10 @@ try: from wolfssl._ffi import ffi as _ffi from wolfssl._ffi import lib as _lib -except ImportError: - pass +except ImportError as e: + from wolfssl.utils import _FFIPlaceholder + _ffi = _FFIPlaceholder(e) + _lib = _FFIPlaceholder(e) from wolfssl.utils import t2b @@ -169,7 +171,7 @@ def __init__(self, protocol, server_side=None): self.verify_mode = CERT_NONE def __del__(self): - if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL: + if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL: _lib.wolfSSL_CTX_free(self.native_object) @property @@ -474,7 +476,7 @@ def __del__(self): self._release_native_object() def _release_native_object(self): - if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL: + if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL: _lib.wolfSSL_free(self.native_object) self.native_object = _ffi.NULL diff --git a/wolfssl/_build_ffi.py b/wolfssl/_build_ffi.py index 43a0fdd..9dfba28 100644 --- a/wolfssl/_build_ffi.py +++ b/wolfssl/_build_ffi.py @@ -35,9 +35,6 @@ from ctypes import cdll from collections import namedtuple -libwolfssl_path = "" - - def local_path(path): """ Return path relative to the root of this project """ @@ -223,8 +220,13 @@ def build_wolfssl(ref, debug=False): def make_optional_func_list(libwolfssl_path, funcs): + defined = [] sys.stderr.write("\nlibwolfssl Path: %s\n" % libwolfssl_path) - if libwolfssl_path.endswith(".so"): + if not libwolfssl_path or not os.path.exists(libwolfssl_path): + sys.stderr.write("WARNING: libwolfssl not found, skipping optional " + "function detection\n") + return [] + if libwolfssl_path.endswith(".so") or libwolfssl_path.endswith(".dylib"): libwolfssl = cdll.LoadLibrary(libwolfssl_path) defined = [] for func in funcs: @@ -244,16 +246,13 @@ def make_optional_func_list(libwolfssl_path, funcs): return defined -def get_libwolfssl(): - libwolfssl_path = os.path.join(wolfssl_lib_path(), "libwolfssl.a") - if not os.path.exists(libwolfssl_path): - libwolfssl_path = os.path.join(wolfssl_lib_path(), "libwolfssl.so") - if not os.path.exists(libwolfssl_path): - return 0 - else: - return 1 - else: - return 1 +def get_libwolfssl_path(): + lib_dir = wolfssl_lib_path() + for ext in (".so", ".dylib", ".a"): + path = os.path.join(lib_dir, "libwolfssl" + ext) + if os.path.exists(path): + return path + return None def generate_libwolfssl(): @@ -282,6 +281,7 @@ def generate_libwolfssl(): raise RuntimeError("wolfSSL needs to be compiled with " "--enable-opensslextra") featureDetection = 1 + libwolfssl_path = get_libwolfssl_path() sys.stderr.write("\nDEBUG: Found , attempting native " "feature detection\n") @@ -290,9 +290,10 @@ def generate_libwolfssl(): featureDetection = 0 sys.stderr.write("\nDEBUG: Skipping native feature detection, build not " "using USE_LOCAL_WOLFSSL\n") - if get_libwolfssl() == 0: + libwolfssl_path = get_libwolfssl_path() + if libwolfssl_path is None: generate_libwolfssl() - get_libwolfssl() + libwolfssl_path = get_libwolfssl_path() # default values OLDTLS_ENABLED = 0 @@ -328,13 +329,23 @@ def generate_libwolfssl(): ffi = FFI() -ffi.set_source( - "wolfssl._ffi", - ffi_source, - include_dirs=[wolfssl_inc_path()], - library_dirs=[wolfssl_lib_path()], - libraries=["wolfssl"], -) +if libwolfssl_path and libwolfssl_path.endswith(".a"): + # Static linking: pass the .a file directly via extra_objects + ffi.set_source( + "wolfssl._ffi", + ffi_source, + include_dirs=[wolfssl_inc_path()], + extra_objects=[libwolfssl_path], + ) +else: + # Dynamic linking: use library_dirs + libraries + ffi.set_source( + "wolfssl._ffi", + ffi_source, + include_dirs=[wolfssl_inc_path()], + library_dirs=[wolfssl_lib_path()], + libraries=["wolfssl"], + ) cdef = """ /* diff --git a/wolfssl/_methods.py b/wolfssl/_methods.py index 7c672ae..a72b538 100644 --- a/wolfssl/_methods.py +++ b/wolfssl/_methods.py @@ -25,8 +25,10 @@ try: from wolfssl._ffi import lib as _lib from wolfssl._ffi import ffi as _ffi -except ImportError: - pass +except ImportError as e: + from wolfssl.utils import _FFIPlaceholder + _ffi = _FFIPlaceholder(e) + _lib = _FFIPlaceholder(e) PROTOCOL_SSLv23 = 1 @@ -111,5 +113,5 @@ def __init__(self, protocol, server_side): raise MemoryError("Cannot allocate method object") def __del__(self): - if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL: + if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL: _native_free(self.native_object, _DYNAMIC_TYPE_METHOD) diff --git a/wolfssl/utils.py b/wolfssl/utils.py index 19757ed..e4cece8 100644 --- a/wolfssl/utils.py +++ b/wolfssl/utils.py @@ -30,6 +30,19 @@ _BINARY_TYPE = bytes if _PY3 else str +class _FFIPlaceholder: + def __init__(self, cause=None): + object.__setattr__(self, '_cause', cause) + + def __getattr__(self, name): + raise ImportError( + "wolfssl._ffi is not available. The CFFI bindings have not been " + "compiled. If you installed wolfssl via pip, the build may have " + "failed silently. Try reinstalling with: " + "pip install --no-binary wolfssl wolfssl" + ) from self._cause + + def t2b(string): """ Converts text to binary.