Skip to content

Commit 7bfeb3a

Browse files
committed
Cythonize in one pass with a shared utility module
Each extension was cythonized in its own call, so Cython's generated utility code was duplicated into every module. Build the whole list in a single cythonize() call with shared_utility_qualified_name set, which emits the common code once into av._cyutil and has the other modules import it.
1 parent 7dee9f0 commit 7bfeb3a

2 files changed

Lines changed: 45 additions & 37 deletions

File tree

‎pyproject.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools>=77.0", "cython>=3.1.0,<4"]
2+
requires = ["setuptools>=78.0", "cython>=3.3.0,<4"]
33

44
[project]
55
name = "av"
@@ -23,6 +23,7 @@ classifiers = [
2323
"Programming Language :: Python :: 3.12",
2424
"Programming Language :: Python :: 3.13",
2525
"Programming Language :: Python :: 3.14",
26+
"Programming Language :: Python :: 3.15",
2627
"Topic :: Software Development :: Libraries :: Python Modules",
2728
"Topic :: Multimedia :: Sound/Audio",
2829
"Topic :: Multimedia :: Sound/Audio :: Conversion",

‎setup.py‎

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,7 @@ def parse_cflags(raw_flags):
140140
}
141141

142142
IMPORT_NAME = "av"
143-
144-
loudnorm_extension = Extension(
145-
f"{IMPORT_NAME}.filter.loudnorm",
146-
sources=[
147-
f"{IMPORT_NAME}/filter/loudnorm.py",
148-
f"{IMPORT_NAME}/filter/loudnorm_impl.c",
149-
],
150-
include_dirs=[f"{IMPORT_NAME}/filter"] + extension_extra["include_dirs"],
151-
libraries=extension_extra["libraries"],
152-
library_dirs=extension_extra["library_dirs"],
153-
define_macros=define_macros,
154-
py_limited_api=py_limited_api,
155-
)
143+
SHARED_MODULE_NAME = f"{IMPORT_NAME}._cyutil"
156144

157145
compiler_directives = {
158146
"c_string_type": "str",
@@ -163,17 +151,37 @@ def parse_cflags(raw_flags):
163151
"freethreading_compatible": True,
164152
}
165153

166-
# Add the cythonized loudnorm extension to ext_modules
167-
ext_modules = cythonize(
168-
loudnorm_extension,
169-
compiler_directives=compiler_directives,
170-
build_dir="src",
171-
include_path=["include"],
172-
)
154+
155+
def make_extension(name, sources, extra_include_dirs=()):
156+
return Extension(
157+
name,
158+
sources=sources,
159+
include_dirs=[*extra_include_dirs, *extension_extra["include_dirs"]],
160+
libraries=extension_extra["libraries"],
161+
library_dirs=extension_extra["library_dirs"],
162+
define_macros=define_macros,
163+
py_limited_api=py_limited_api,
164+
)
165+
166+
167+
LOUDNORM_SOURCE = os.path.join(IMPORT_NAME, "filter", "loudnorm.py")
168+
169+
extensions = [
170+
Extension(
171+
SHARED_MODULE_NAME,
172+
sources=[],
173+
define_macros=define_macros,
174+
py_limited_api=py_limited_api,
175+
),
176+
make_extension(
177+
f"{IMPORT_NAME}.filter.loudnorm",
178+
[LOUDNORM_SOURCE, os.path.join(IMPORT_NAME, "filter", "loudnorm_impl.c")],
179+
[os.path.join(IMPORT_NAME, "filter")],
180+
),
181+
]
173182

174183
for dirname, dirnames, filenames in os.walk(IMPORT_NAME):
175184
for filename in filenames:
176-
# We are looking for Cython sources.
177185
if filename.startswith("."):
178186
continue
179187
if filename in {"__init__.py", "__main__.py", "about.py", "datasets.py"}:
@@ -182,27 +190,26 @@ def parse_cflags(raw_flags):
182190
continue
183191

184192
pyx_path = os.path.join(dirname, filename)
193+
if pyx_path == LOUDNORM_SOURCE:
194+
continue
195+
185196
base = os.path.splitext(pyx_path)[0]
186197

187198
# Need to be a little careful because Windows will accept / or \
188199
# (where os.sep will be \ on Windows).
189200
mod_name = base.replace("/", ".").replace(os.sep, ".")
190201

191-
# Cythonize the module.
192-
ext_modules += cythonize(
193-
Extension(
194-
mod_name,
195-
include_dirs=extension_extra["include_dirs"],
196-
libraries=extension_extra["libraries"],
197-
library_dirs=extension_extra["library_dirs"],
198-
sources=[pyx_path],
199-
define_macros=define_macros,
200-
py_limited_api=py_limited_api,
201-
),
202-
compiler_directives=compiler_directives,
203-
build_dir="src",
204-
include_path=["include"],
205-
)
202+
extensions.append(make_extension(mod_name, [pyx_path]))
203+
204+
# Cythonize in one pass so that the shared module can be generated alongside the
205+
# modules that import from it.
206+
ext_modules = cythonize(
207+
extensions,
208+
compiler_directives=compiler_directives,
209+
build_dir="src",
210+
include_path=["include"],
211+
shared_utility_qualified_name=SHARED_MODULE_NAME,
212+
)
206213

207214

208215
package_folders = pathlib.Path(IMPORT_NAME).glob("**/")

0 commit comments

Comments
 (0)