From 821966edecede7ea4a11e8d7616240029e9af2fb Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Thu, 21 Mar 2024 13:20:57 +0000 Subject: [PATCH] gh-71052: Implement `ctypes.util.find_library` on Android (GH-116379) --- Doc/library/ctypes.rst | 5 ++-- Lib/ctypes/util.py | 9 ++++++++ Lib/test/test_ctypes/test_find.py | 23 +++++++++++++++++++ ...4-03-05-19-56-29.gh-issue-71052.PMDK--.rst | 1 + 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-03-05-19-56-29.gh-issue-71052.PMDK--.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 36976470b5a4688..9f7d6456e623a22 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1334,8 +1334,9 @@ Here are some examples:: 'libbz2.so.1.0' >>> -On macOS, :func:`~ctypes.util.find_library` tries several predefined naming schemes and paths -to locate the library, and returns a full pathname if successful:: +On macOS and Android, :func:`~ctypes.util.find_library` uses the system's +standard naming schemes and paths to locate the library, and returns a full +pathname if successful:: >>> from ctypes.util import find_library >>> find_library("c") diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 12d7428fe9a776e..117bf06cb01013b 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -89,6 +89,15 @@ def find_library(name): from ctypes._aix import find_library +elif sys.platform == "android": + def find_library(name): + directory = "/system/lib" + if "64" in os.uname().machine: + directory += "64" + + fname = f"{directory}/lib{name}.so" + return fname if os.path.isfile(fname) else None + elif os.name == "posix": # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump import re, tempfile diff --git a/Lib/test/test_ctypes/test_find.py b/Lib/test/test_ctypes/test_find.py index 7732ff373088480..85b28617d2d7549 100644 --- a/Lib/test/test_ctypes/test_find.py +++ b/Lib/test/test_ctypes/test_find.py @@ -129,5 +129,28 @@ def test_gh114257(self): self.assertIsNone(find_library("libc")) +@unittest.skipUnless(sys.platform == 'android', 'Test only valid for Android') +class FindLibraryAndroid(unittest.TestCase): + def test_find(self): + for name in [ + "c", "m", # POSIX + "z", # Non-POSIX, but present on Linux + "log", # Not present on Linux + ]: + with self.subTest(name=name): + path = find_library(name) + self.assertIsInstance(path, str) + self.assertEqual( + os.path.dirname(path), + "/system/lib64" if "64" in os.uname().machine + else "/system/lib") + self.assertEqual(os.path.basename(path), f"lib{name}.so") + self.assertTrue(os.path.isfile(path), path) + + for name in ["libc", "nonexistent"]: + with self.subTest(name=name): + self.assertIsNone(find_library(name)) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2024-03-05-19-56-29.gh-issue-71052.PMDK--.rst b/Misc/NEWS.d/next/Library/2024-03-05-19-56-29.gh-issue-71052.PMDK--.rst new file mode 100644 index 000000000000000..ddca54c7c9ed7b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-03-05-19-56-29.gh-issue-71052.PMDK--.rst @@ -0,0 +1 @@ +Implement :func:`ctypes.util.find_library` on Android.