Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Lib/ctypes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,25 @@ def find_library(name):
fname = f"{directory}/lib{name}.so"
return fname if os.path.isfile(fname) else None

elif sys.platform == "emscripten":
def _is_wasm(filename):
# Return True if the given file is an WASM module
wasm_header = b"\x00asm"
with open(filename, 'br') as thefile:
return thefile.read(4) == wasm_header

def find_library(name):
candidates = [f"lib{name}.so", f"lib{name}.wasm"]
paths = os.environ.get("LD_LIBRARY_PATH", "")
for libdir in paths.split(":"):
for name in candidates:
libfile = os.path.join(libdir, name)

if os.path.isfile(libfile) and _is_wasm(libfile):
return libfile

return None

elif os.name == "posix":
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile
Expand Down
68 changes: 68 additions & 0 deletions Lib/test/test_ctypes/test_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,73 @@ def test_find(self):
self.assertIsNone(find_library(name))


@unittest.skipUnless(test.support.is_emscripten,
'Test only valid for Emscripten')
class FindLibraryEmscripten(unittest.TestCase):
@classmethod
def setUpClass(cls):
import tempfile

# A very simple wasm module
# In WAT format: (module)
cls.wasm_module = b'\x00asm\x01\x00\x00\x00\x00\x08\x04name\x02\x01\x00'

cls.non_wasm_content = b'This is not a WASM file'

cls.temp_dir = tempfile.mkdtemp()
cls.libdummy_so_path = os.path.join(cls.temp_dir, 'libdummy.so')
with open(cls.libdummy_so_path, 'wb') as f:
f.write(cls.wasm_module)

cls.libother_wasm_path = os.path.join(cls.temp_dir, 'libother.wasm')
with open(cls.libother_wasm_path, 'wb') as f:
f.write(cls.wasm_module)

cls.libnowasm_so_path = os.path.join(cls.temp_dir, 'libnowasm.so')
with open(cls.libnowasm_so_path, 'wb') as f:
f.write(cls.non_wasm_content)

@classmethod
def tearDownClass(cls):
import shutil
shutil.rmtree(cls.temp_dir)

def test_find_wasm_file_with_so_extension(self):
with os_helper.EnvironmentVarGuard() as env:
env.set('LD_LIBRARY_PATH', self.temp_dir)
result = find_library('dummy')
self.assertEqual(result, self.libdummy_so_path)
def test_find_wasm_file_with_wasm_extension(self):
with os_helper.EnvironmentVarGuard() as env:
env.set('LD_LIBRARY_PATH', self.temp_dir)
result = find_library('other')
self.assertEqual(result, self.libother_wasm_path)

def test_ignore_non_wasm_file(self):
with os_helper.EnvironmentVarGuard() as env:
env.set('LD_LIBRARY_PATH', self.temp_dir)
result = find_library('nowasm')
self.assertIsNone(result)

def test_find_nothing_without_ld_library_path(self):
with os_helper.EnvironmentVarGuard() as env:
if 'LD_LIBRARY_PATH' in env:
del env['LD_LIBRARY_PATH']
result = find_library('dummy')
self.assertIsNone(result)
result = find_library('other')
self.assertIsNone(result)

def test_find_nothing_with_wrong_ld_library_path(self):
import tempfile
with tempfile.TemporaryDirectory() as empty_dir:
with os_helper.EnvironmentVarGuard() as env:
env.set('LD_LIBRARY_PATH', empty_dir)
result = find_library('dummy')
self.assertIsNone(result)
result = find_library('other')
self.assertIsNone(result)


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:func:`ctypes.util.find_library` now works in Emscripten build.
Loading