Skip to content

Commit

Permalink
Improved building for Python stable ABI / limited API.
Browse files Browse the repository at this point in the history
setup.py:
    Renamed PYMUPDF_SETUP_Py_LIMITED_API to all-caps
    PYMUPDF_SETUP_PY_LIMITED_API; accept only '0 or '1' instead of an actual
    value; pass True (not '0x03080000') to pipcl if '1'.

    Use pipcl.current_py_limited_api() to get Py_LIMITED_API value suitable for
    current Python version.

.github/workflows/build_wheels.yml:
    Use PYMUPDF_SETUP_PY_LIMITED_API.
scripts/gh_release.py
    Use PYMUPDF_SETUP_PY_LIMITED_API.
  • Loading branch information
julian-smith-artifex-com committed Oct 3, 2024
1 parent bce515c commit 7a286f7
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 40 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ on:
# default: '-'
# We can't currently have more than 10 inputs

PYMUPDF_SETUP_Py_LIMITED_API:
PYMUPDF_SETUP_PY_LIMITED_API:
description: 'If not "", is used to build single wheel for each OS.'
type: string
default: ''
Expand Down Expand Up @@ -147,7 +147,7 @@ jobs:

inputs_wheels_cps: ${{inputs.wheels_cps}}

PYMUPDF_SETUP_Py_LIMITED_API: ${{inputs.PYMUPDF_SETUP_Py_LIMITED_API}}
PYMUPDF_SETUP_PY_LIMITED_API: ${{inputs.PYMUPDF_SETUP_PY_LIMITED_API}}

run:
python scripts/gh_release.py
Expand Down
14 changes: 7 additions & 7 deletions scripts/gh_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def get_bool(name, default=0):
inputs_PYMUPDF_SETUP_MUPDF_BUILD = os.environ.get('inputs_PYMUPDF_SETUP_MUPDF_BUILD')
inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE = os.environ.get('inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE')

PYMUPDF_SETUP_Py_LIMITED_API = os.environ.get('PYMUPDF_SETUP_Py_LIMITED_API')
PYMUPDF_SETUP_PY_LIMITED_API = os.environ.get('PYMUPDF_SETUP_PY_LIMITED_API')

log( f'{inputs_flavours=}')
log( f'{inputs_sdist=}')
Expand All @@ -215,7 +215,7 @@ def get_bool(name, default=0):
log( f'{inputs_wheels_cps=}')
log( f'{inputs_PYMUPDF_SETUP_MUPDF_BUILD=}')
log( f'{inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE=}')
log( f'{PYMUPDF_SETUP_Py_LIMITED_API=}')
log( f'{PYMUPDF_SETUP_PY_LIMITED_API=}')

# Build Pyodide wheel if specified.
#
Expand Down Expand Up @@ -384,14 +384,14 @@ def set_cibuild_test():
# We include MuPDF build-time files.
flavour_d = True

if PYMUPDF_SETUP_Py_LIMITED_API:
if PYMUPDF_SETUP_PY_LIMITED_API:
# Build one wheel with oldest python, then fake build with other python
# versions so we test everything.
log(f'{PYMUPDF_SETUP_Py_LIMITED_API=}')
env_pass('PYMUPDF_SETUP_Py_LIMITED_API')
# This isn't actually necessary - PYMUPDF_SETUP_Py_LIMITED_API is
log(f'{PYMUPDF_SETUP_PY_LIMITED_API=}')
env_pass('PYMUPDF_SETUP_PY_LIMITED_API')
# This isn't actually necessary - PYMUPDF_SETUP_PY_LIMITED_API is
# already in the environment - but we set it anyway for clarity.
env_set('PYMUPDF_SETUP_Py_LIMITED_API', PYMUPDF_SETUP_Py_LIMITED_API, pass_=1)
env_set('PYMUPDF_SETUP_PY_LIMITED_API', PYMUPDF_SETUP_PY_LIMITED_API, pass_=1)
CIBW_BUILD_old = env_extra.get('CIBW_BUILD')
assert CIBW_BUILD_old is not None
env_set('CIBW_BUILD', 'cp38*')
Expand Down
56 changes: 25 additions & 31 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,8 @@
PYMUPDF_SETUP_MUPDF_REBUILD
If 0 we do not (re)build mupdf.
PYMUPDF_SETUP_Py_LIMITED_API
None, 'default' or the value of `Py_LIMITED_API` macro when building
MuPDF and PyMuPDF Python client code. If 'defaut', we use hard-coded
default.
This will hopefully allow the same build of PyMuPDF to be used with
multiple Python versions.
PYMUPDF_SETUP_PY_LIMITED_API
If '1', we build for current Python's stable ABI.
PYMUPDF_SETUP_URL_WHEEL
If set, we use an existing wheel instead of building a new wheel.
Expand Down Expand Up @@ -240,9 +235,10 @@ def log( text):
# Name of file that identifies that we are in a PyMuPDF sdist.
g_pymupdfb_sdist_marker = 'pymupdfb_sdist'

Py_LIMITED_API = os.environ.get('PYMUPDF_SETUP_Py_LIMITED_API')
if Py_LIMITED_API == 'default':
Py_LIMITED_API = '0x03080000'
PYMUPDF_SETUP_PY_LIMITED_API = os.environ.get('PYMUPDF_SETUP_PY_LIMITED_API')
assert PYMUPDF_SETUP_PY_LIMITED_API in (None, '0', '1'), \
f'Should be "0", "1" or undefined: {PYMUPDF_SETUP_PY_LIMITED_API=}.'
g_py_limited_api = (PYMUPDF_SETUP_PY_LIMITED_API == '1')

PYMUPDF_SETUP_URL_WHEEL = os.environ.get('PYMUPDF_SETUP_URL_WHEEL')
log(f'{PYMUPDF_SETUP_URL_WHEEL=}')
Expand Down Expand Up @@ -570,7 +566,7 @@ def build():
mupdf_local,
build_type,
overwrite_config,
Py_LIMITED_API,
g_py_limited_api,
PYMUPDF_SETUP_MUPDF_REFCHECK_IF,
PYMUPDF_SETUP_MUPDF_TRACE_IF,
)
Expand All @@ -584,7 +580,7 @@ def build():
mupdf_local,
build_type,
overwrite_config,
Py_LIMITED_API,
g_py_limited_api,
PYMUPDF_SETUP_MUPDF_REFCHECK_IF,
PYMUPDF_SETUP_MUPDF_TRACE_IF,
)
Expand All @@ -597,7 +593,7 @@ def build():
mupdf_local,
mupdf_build_dir,
build_type,
Py_LIMITED_API,
g_py_limited_api,
)
else:
log(f'Not building extension.')
Expand Down Expand Up @@ -711,7 +707,7 @@ def build_mupdf_windows(
mupdf_local,
build_type,
overwrite_config,
Py_LIMITED_API,
g_py_limited_api,
PYMUPDF_SETUP_MUPDF_REFCHECK_IF,
PYMUPDF_SETUP_MUPDF_TRACE_IF,
):
Expand All @@ -736,8 +732,8 @@ def build_mupdf_windows(
wp = pipcl.wdev.WindowsPython()
tesseract = '' if os.environ.get('PYMUPDF_SETUP_MUPDF_TESSERACT') == '0' else 'tesseract-'
windows_build_tail = f'build\\shared-{tesseract}{build_type}'
if Py_LIMITED_API:
windows_build_tail += f'-Py_LIMITED_API={Py_LIMITED_API}'
if g_py_limited_api:
windows_build_tail += f'-Py_LIMITED_API={pipcl.current_py_limited_api()}'
windows_build_tail += f'-x{wp.cpu.bits}-py{wp.version}'
windows_build_dir = f'{mupdf_local}\\{windows_build_tail}'
#log( f'Building mupdf.')
Expand Down Expand Up @@ -805,7 +801,7 @@ def build_mupdf_unix(
mupdf_local,
build_type,
overwrite_config,
Py_LIMITED_API,
g_py_limited_api,
PYMUPDF_SETUP_MUPDF_REFCHECK_IF,
PYMUPDF_SETUP_MUPDF_TRACE_IF,
):
Expand Down Expand Up @@ -880,9 +876,9 @@ def build_mupdf_unix(
):
log(f'Appending `bsymbolic-` to MuPDF build path.')
build_prefix += 'bsymbolic-'
log(f'{Py_LIMITED_API=}')
if Py_LIMITED_API:
build_prefix += f'Py_LIMITED_API={Py_LIMITED_API}-'
log(f'{g_py_limited_api=}')
if g_py_limited_api:
build_prefix += f'Py_LIMITED_API={pipcl.current_py_limited_api()}-'
unix_build_dir = f'{mupdf_local}/build/{build_prefix}{build_type}'
# We need MuPDF's Python bindings, so we build MuPDF with
# `mupdf/scripts/mupdfwrap.py` instead of running `make`.
Expand Down Expand Up @@ -937,15 +933,15 @@ def _fs_update(text, path):
f.write( text)


def _build_extension( mupdf_local, mupdf_build_dir, build_type, Py_LIMITED_API):
def _build_extension( mupdf_local, mupdf_build_dir, build_type, g_py_limited_api):
'''
Builds Python extension module `_extra`.
Returns leafname of the generated shared libraries within mupdf_build_dir.
'''
(compiler_extra, linker_extra, includes, defines, optimise, debug, libpaths, libs, libraries) \
= _extension_flags( mupdf_local, mupdf_build_dir, build_type, Py_LIMITED_API)
log(f'_build_extension(): {Py_LIMITED_API=} {defines=}')
= _extension_flags( mupdf_local, mupdf_build_dir, build_type, g_py_limited_api)
log(f'_build_extension(): {g_py_limited_api=} {defines=}')
if mupdf_local:
includes = (
f'{mupdf_local}/platform/c++/include',
Expand Down Expand Up @@ -988,13 +984,13 @@ def _build_extension( mupdf_local, mupdf_build_dir, build_type, Py_LIMITED_API):
prerequisites_swig = None,
prerequisites_compile = f'{mupdf_local}/include',
prerequisites_link = libraries,
use_so_versioning=not Py_LIMITED_API,
py_limited_api = g_py_limited_api,
)

return path_so_leaf


def _extension_flags( mupdf_local, mupdf_build_dir, build_type, Py_LIMITED_API):
def _extension_flags( mupdf_local, mupdf_build_dir, build_type, g_py_limited_api):
'''
Returns various flags to pass to pipcl.build_extension().
'''
Expand All @@ -1010,9 +1006,9 @@ def _extension_flags( mupdf_local, mupdf_build_dir, build_type, Py_LIMITED_API):
debug = 'debug' in mupdf_build_dir_flags
r_extra = ''
defines = list()
log(f'{Py_LIMITED_API=}')
if Py_LIMITED_API:
defines.append(f'Py_LIMITED_API={Py_LIMITED_API}')
log(f'{g_py_limited_api=}')
if g_py_limited_api:
defines.append(f'Py_LIMITED_API={g_py_limited_api}')
if windows:
defines.append('FZ_DLL_CLIENT')
wp = pipcl.wdev.WindowsPython()
Expand Down Expand Up @@ -1188,9 +1184,6 @@ def get_requires_for_build_wheel(config_settings=None):
[console_scripts]
pymupdf = pymupdf.__main__:main
''')
if Py_LIMITED_API:
# Wheel will work on all Python versions.
tag_python = 'py3'
elif 'b' in PYMUPDF_SETUP_FLAVOUR:
version = version_b
name = 'PyMuPDFb'
Expand Down Expand Up @@ -1231,6 +1224,7 @@ def get_requires_for_build_wheel(config_settings=None):
fn_sdist=sdist,

tag_python=tag_python,
py_limited_api=g_py_limited_api,

# 30MB: 9 ZIP_DEFLATED
# 28MB: 9 ZIP_BZIP2
Expand Down

0 comments on commit 7a286f7

Please sign in to comment.