Skip to content

Commit 9741cfc

Browse files
miss-islingtonryanking13blurb-it[bot]freakboy3742
authored
[3.14] gh-99948: Support ctypes.util.find_library in emscripten environment (GH-138519) (#139022)
Co-authored-by: Gyeongjae Choi <[email protected]> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Russell Keith-Magee <[email protected]>
1 parent c115494 commit 9741cfc

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

Lib/ctypes/util.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,25 @@ def find_library(name):
173173
fname = f"{directory}/lib{name}.so"
174174
return fname if os.path.isfile(fname) else None
175175

176+
elif sys.platform == "emscripten":
177+
def _is_wasm(filename):
178+
# Return True if the given file is an WASM module
179+
wasm_header = b"\x00asm"
180+
with open(filename, 'br') as thefile:
181+
return thefile.read(4) == wasm_header
182+
183+
def find_library(name):
184+
candidates = [f"lib{name}.so", f"lib{name}.wasm"]
185+
paths = os.environ.get("LD_LIBRARY_PATH", "")
186+
for libdir in paths.split(":"):
187+
for name in candidates:
188+
libfile = os.path.join(libdir, name)
189+
190+
if os.path.isfile(libfile) and _is_wasm(libfile):
191+
return libfile
192+
193+
return None
194+
176195
elif os.name == "posix":
177196
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
178197
import re, tempfile

Lib/test/test_ctypes/test_find.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,73 @@ def test_find(self):
153153
self.assertIsNone(find_library(name))
154154

155155

156+
@unittest.skipUnless(test.support.is_emscripten,
157+
'Test only valid for Emscripten')
158+
class FindLibraryEmscripten(unittest.TestCase):
159+
@classmethod
160+
def setUpClass(cls):
161+
import tempfile
162+
163+
# A very simple wasm module
164+
# In WAT format: (module)
165+
cls.wasm_module = b'\x00asm\x01\x00\x00\x00\x00\x08\x04name\x02\x01\x00'
166+
167+
cls.non_wasm_content = b'This is not a WASM file'
168+
169+
cls.temp_dir = tempfile.mkdtemp()
170+
cls.libdummy_so_path = os.path.join(cls.temp_dir, 'libdummy.so')
171+
with open(cls.libdummy_so_path, 'wb') as f:
172+
f.write(cls.wasm_module)
173+
174+
cls.libother_wasm_path = os.path.join(cls.temp_dir, 'libother.wasm')
175+
with open(cls.libother_wasm_path, 'wb') as f:
176+
f.write(cls.wasm_module)
177+
178+
cls.libnowasm_so_path = os.path.join(cls.temp_dir, 'libnowasm.so')
179+
with open(cls.libnowasm_so_path, 'wb') as f:
180+
f.write(cls.non_wasm_content)
181+
182+
@classmethod
183+
def tearDownClass(cls):
184+
import shutil
185+
shutil.rmtree(cls.temp_dir)
186+
187+
def test_find_wasm_file_with_so_extension(self):
188+
with os_helper.EnvironmentVarGuard() as env:
189+
env.set('LD_LIBRARY_PATH', self.temp_dir)
190+
result = find_library('dummy')
191+
self.assertEqual(result, self.libdummy_so_path)
192+
def test_find_wasm_file_with_wasm_extension(self):
193+
with os_helper.EnvironmentVarGuard() as env:
194+
env.set('LD_LIBRARY_PATH', self.temp_dir)
195+
result = find_library('other')
196+
self.assertEqual(result, self.libother_wasm_path)
197+
198+
def test_ignore_non_wasm_file(self):
199+
with os_helper.EnvironmentVarGuard() as env:
200+
env.set('LD_LIBRARY_PATH', self.temp_dir)
201+
result = find_library('nowasm')
202+
self.assertIsNone(result)
203+
204+
def test_find_nothing_without_ld_library_path(self):
205+
with os_helper.EnvironmentVarGuard() as env:
206+
if 'LD_LIBRARY_PATH' in env:
207+
del env['LD_LIBRARY_PATH']
208+
result = find_library('dummy')
209+
self.assertIsNone(result)
210+
result = find_library('other')
211+
self.assertIsNone(result)
212+
213+
def test_find_nothing_with_wrong_ld_library_path(self):
214+
import tempfile
215+
with tempfile.TemporaryDirectory() as empty_dir:
216+
with os_helper.EnvironmentVarGuard() as env:
217+
env.set('LD_LIBRARY_PATH', empty_dir)
218+
result = find_library('dummy')
219+
self.assertIsNone(result)
220+
result = find_library('other')
221+
self.assertIsNone(result)
222+
223+
156224
if __name__ == "__main__":
157225
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`ctypes.util.find_library` now works in Emscripten build.

0 commit comments

Comments
 (0)