Skip to content

Commit

Permalink
always precompile xcffib’s ffi (even in ABI mode)
Browse files Browse the repository at this point in the history
  • Loading branch information
georgeharker committed Dec 6, 2024
1 parent 5ead5a3 commit 386aa5a
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dist-newstyle
_*.c
_*.so
_*.o
_xcffib.py
*.swp
*.swo
*.pyc
Expand Down
26 changes: 18 additions & 8 deletions module/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,23 @@


# Attempt api mode if installed
api_mode = True
cffi_mode = "(unknown)"
try:
# Note in ABI mode lib will be missing
from _xcffib import ffi, lib
api_mode = True
assert lib.__CFFI_MODE == lib.__CFFI_MODE_API
cffi_mode = "API"
except ImportError:
api_mode = False

# Fall back to non api mode
if not api_mode:
from .ffi_build import ffi # noqa

try:
# Note in ABI mode lib will be missing
from _xcffib import ffi
except ImportError:
# Fall back to importing and parsing cffi defs
from .ffi_build import ffi

# Fall back to non api mode, inline at load time
# this would only happen if the precompiled _xcffib was missing
if cffi_mode != "API":
if platform.system() == "Darwin":
soname = "libxcb.dylib"
elif platform.system() == "Windows":
Expand All @@ -45,6 +51,10 @@
if soname is None:
soname = "libxcb.so"
lib = ffi.dlopen(soname) # noqa
if lib.__CFFI_MODE == lib.__CFFI_MODE_ABI:
cffi_mode = "ABI"
elif lib.__CFFI_MODE == lib.__CFFI_MODE_ABI_PRECOMPILED:
cffi_mode = "ABI(precompiled)"

__xcb_proto_version__ = 'placeholder'
__version__ = 'placeholder'
Expand Down
86 changes: 67 additions & 19 deletions module/ffi_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
from warnings import warn

from cffi import FFI

Expand Down Expand Up @@ -237,29 +238,76 @@
xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
"""

CDEF += """
CDEF += r"""
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
"""

__CFFI_MODE_API = 0
__CFFI_MODE_ABI = 1
__CFFI_MODE_ABI_PRECOMPILED = 2
CDEF += f"""
#define __CFFI_MODE_API {__CFFI_MODE_API}
#define __CFFI_MODE_ABI {__CFFI_MODE_ABI}
#define __CFFI_MODE_ABI_PRECOMPILED {__CFFI_MODE_ABI_PRECOMPILED}
"""


def ffi_build(build_source=True):
"""
This will be called from setup() to return an FFI
which it will compile - work out here which type is
possible and return it.
"""
# Note local ffi needed here as multiple
# source calls is illegal and cdefs differ
try:
ffi = FFI()
ffi.cdef(CDEF + f"""
#define __CFFI_MODE {__CFFI_MODE_API}
""")

ffi.set_source_pkgconfig(
'_xcffib',
['xcb'],
"""
#include "xcb/xcb.h"
#include "xcb/xproto.h"
#include "xcb/xcbext.h"
#include "xcb/render.h"
""" + f"""
#define __CFFI_MODE_API {__CFFI_MODE_API}
#define __CFFI_MODE_ABI {__CFFI_MODE_ABI}
#define __CFFI_MODE_ABI_PRECOMPILED {__CFFI_MODE_ABI_PRECOMPILED}
#define __CFFI_MODE {__CFFI_MODE_API}
"""
)

ffi.compile(verbose=True)
return ffi
except Exception:
warn("Falling back to precompiled python mode")
ffi = FFI()
ffi.cdef(CDEF + f"""
#define __CFFI_MODE {__CFFI_MODE_ABI_PRECOMPILED}
""")

ffi.set_source(
'_xcffib',
None)

ffi = FFI()
ffi.cdef(CDEF)

if ('XCFFIB_API_MODE' in os.environ and
int(os.environ['XCFFIB_API_MODE']) == 1):
ffi.set_source_pkgconfig(
'_xcffib',
['xcb'],
"""
#include "xcb/xcb.h"
#include "xcb/xproto.h"
#include "xcb/xcbext.h"
#include "xcb/render.h"
"""
)

if __name__ == "__main__":
ffi.compile(verbose=True)
return ffi


ffi = FFI()
ffi.cdef(CDEF + f"""
#define __CFFI_MODE {__CFFI_MODE_ABI}
""")


if __name__ == "__main__":
ffi = ffi_build()
ffi.compile(verbose=True)
7 changes: 1 addition & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ def finalize_options(self):
version = "1.5.0"
dependencies = ["cffi>=1.1.0; python_implementation != 'PyPy'"]

api_mode = False
if ('XCFFIB_API_MODE' in os.environ and
int(os.environ['XCFFIB_API_MODE']) == 1):
api_mode = True

setup(
name="xcffib",
version=version,
Expand All @@ -78,5 +73,5 @@ def finalize_options(self):
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries'
],
cffi_modules=["xcffib/ffi_build.py:ffi"] if api_mode else [],
cffi_modules=["xcffib/ffi_build.py:ffi_build"]
)

0 comments on commit 386aa5a

Please sign in to comment.