From 1fabb25a6d081d0517621cd829feb2780fbaa218 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Sat, 22 Aug 2026 00:21:09 +0000 Subject: [PATCH] Avoid recursive cache lock in SDL TTF ports When building port libraries, build_port compiles sources with emcc in a subprocess while the parent process holds EM_CACHE_IS_LOCKED. Passing -sUSE_* flags causes the child emcc to resolve ports and attempt to acquire the cache lock if dependencies like harfbuzz are not yet in the cache, causing an AssertionError. Pass include directories directly instead of port settings flags when compiling SDL TTF port sources. Also ensure parent directories exist when writing port assets. --- test/test_other.py | 13 ++++++++++++- tools/ports/__init__.py | 1 + tools/ports/sdl2_ttf.py | 9 +++++++-- tools/ports/sdl3_ttf.py | 10 ++++++++-- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 856d84a72191f..3bff6da7b57c3 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -99,7 +99,7 @@ with_env_modify, ) -from tools import building, cache, response_file, shared, utils, webassembly +from tools import building, cache, ports, response_file, shared, utils, webassembly from tools.building import get_building_env from tools.cmdline import options from tools.link import binary_encode @@ -2753,6 +2753,17 @@ def test_sdl3_ttf(self): self.emcc(test_file('browser/test_sdl3_ttf.c'), args=['-Wno-experimental', '-sUSE_SDL=3', '-sUSE_SDL_TTF=3']) self.emcc(test_file('browser/test_sdl3_ttf.c'), args=['-Wno-experimental', '--use-port=sdl3', '--use-port=sdl3_ttf']) + @requires_network + def test_sdl_ttf_parent_cache_lock(self): + # Verify that building sdl2_ttf while holding the cache lock (as a parent process does) + # succeeds even if libharfbuzz.a is not yet present in the cache. + shared.cache.erase_lib('libharfbuzz.a') + shared.cache.erase_lib('libSDL2_ttf.a') + self.set_setting('USE_SDL', 2) + self.set_setting('USE_SDL_TTF', 2) + with shared.cache.lock('test_sdl_ttf_parent_cache_lock'): + ports.get_port_by_name('sdl2_ttf').get(ports.Ports, settings, shared) + @requires_network def test_contrib_ports(self): # Verify that contrib ports can be used (using the only contrib port available ATM, but can be replaced diff --git a/tools/ports/__init__.py b/tools/ports/__init__.py index 3c9c566a78dd2..5a2e5b912e5d6 100644 --- a/tools/ports/__init__.py +++ b/tools/ports/__init__.py @@ -440,6 +440,7 @@ def clear_project_build(name): def write_file(filename, contents): if os.path.exists(filename) and utils.read_file(filename) == contents: return + utils.safe_ensure_dirs(os.path.dirname(filename)) utils.write_file(filename, contents) @staticmethod diff --git a/tools/ports/sdl2_ttf.py b/tools/ports/sdl2_ttf.py index 4e0d75f0e5330..19ef76ac73fb1 100644 --- a/tools/ports/sdl2_ttf.py +++ b/tools/ports/sdl2_ttf.py @@ -25,10 +25,15 @@ def get(ports, settings, shared): def create(final): src_root = ports.get_dir('sdl2_ttf', 'SDL_ttf-' + TAG) ports.install_headers(src_root, target='SDL2') - flags = ['-DTTF_USE_HARFBUZZ=1', '-sUSE_SDL=2', '-sUSE_FREETYPE', '-sUSE_HARFBUZZ'] + includes = [ + ports.get_include_dir('SDL2'), + ports.get_include_dir('freetype2'), + ports.get_include_dir('harfbuzz'), + ] + flags = ['-DTTF_USE_HARFBUZZ=1'] if settings.PTHREADS: flags += ['-pthread'] - ports.build_port(src_root, final, 'sdl2_ttf', flags=flags, srcs=['SDL_ttf.c']) + ports.build_port(src_root, final, 'sdl2_ttf', includes=includes, flags=flags, srcs=['SDL_ttf.c']) return [shared.cache.get_lib(get_lib_name(settings), create, what='port')] diff --git a/tools/ports/sdl3_ttf.py b/tools/ports/sdl3_ttf.py index 0d4fe4edc2192..67308e548d4b8 100644 --- a/tools/ports/sdl3_ttf.py +++ b/tools/ports/sdl3_ttf.py @@ -27,7 +27,13 @@ def get(ports, settings, shared): def create(final): src_root = ports.get_dir('sdl3_ttf', 'SDL_ttf-' + TAG) ports.install_header_dir(os.path.join(src_root, 'include'), target='.') - flags = ['-Wno-experimental', '-DTTF_USE_HARFBUZZ=1', '-sUSE_SDL=3', '-sUSE_FREETYPE', '-sUSE_HARFBUZZ'] + includes = [ + ports.get_include_dir(), + ports.get_include_dir('SDL3'), + ports.get_include_dir('freetype2'), + ports.get_include_dir('harfbuzz'), + ] + flags = ['-Wno-experimental', '-DTTF_USE_HARFBUZZ=1'] if settings.PTHREADS: flags += ['-pthread'] @@ -40,7 +46,7 @@ def create(final): 'src/SDL_ttf.c', ] - ports.build_port(src_root, final, 'sdl3_ttf', flags=flags, srcs=srcs) + ports.build_port(src_root, final, 'sdl3_ttf', includes=includes, flags=flags, srcs=srcs) return [shared.cache.get_lib(get_lib_name(settings), create, what='port')]