Repository: mesonbuild/meson

Issue:
wrong shared library 7.9, want 7.10 on OpenBSD
**Describe the bug**
Given versions x.9 and x.10 of a shared library on OpenBSD, Meson finds the wrong one. It picks x.9, but I want x.10.

**To Reproduce**
Meson has a test to find shared libraries on OpenBSD, so I added a failing case,

```diff
diff --git a/unittests/internaltests.py b/unittests/internaltests.py
index 56d36117a..37cbbc3bd 100644
--- a/unittests/internaltests.py
+++ b/unittests/internaltests.py
@@ -549,11 +549,13 @@ class InternalTests(unittest.TestCase):
         if platform != 'openbsd':
             return
         with tempfile.TemporaryDirectory() as tmpdir:
-            for i in ['libfoo.so.6.0', 'libfoo.so.5.0', 'libfoo.so.54.0', 'libfoo.so.66a.0b', 'libfoo.so.70.0.so.1']:
+            for i in ['libfoo.so.6.0', 'libfoo.so.5.0', 'libfoo.so.54.0', 'libfoo.so.66a.0b', 'libfoo.so.70.0.so.1', 'libbar.so.7.10', 'libbar.so.7.9']:
                 libpath = Path(tmpdir) / i
                 libpath.write_text('', encoding='utf-8')
             found = cc._find_library_real('foo', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True)
             self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0')
+            found = cc._find_library_real('bar', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True)
+            self.assertEqual(os.path.basename(found[0]), 'libbar.so.7.10')
 
     def test_find_library_patterns(self):
         '''
```

Do `./run_unittests.py -k internaltests`, then the test fails:

```
    self.assertEqual(os.path.basename(found[0]), 'libbar.so.7.10')
AssertionError: 'libbar.so.7.9' != 'libbar.so.7.10'                             
```

**Expected behavior**
Meson should find `libbar.so.7.10` because it has a higher minor version number than `libbar.so.7.9`. The code in mesonbuild/compilers/mixins/clike.py _sort_shlibs_openbsd is comparing floats 7.9 > 7.10. I want to compare tuples (7, 9) < (7, 10), but I don't have Python code to make the tuples.

**system parameters**
* OpenBSD 7.3-current, Python 3.10.12, Meson 025bcc0 (master on Sep 1, 2023)



Discussion:
Is it required to be a two-component version?
Yes, shared libraries are named [libfoo.so.major.minor](https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs), always with 2 components (major and minor). That's why meson's _get_patterns has `{}.so.[0-9]*.[0-9]*`

Resolving patch:
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -1084,6 +1084,10 @@ def get_library_naming(self, env: 'Environment', libtype: LibType, strict: bool
 
     @staticmethod
     def _sort_shlibs_openbsd(libs: T.List[str]) -> T.List[str]:
+        def tuple_key(x: str) -> T.Tuple[int, ...]:
+            ver = x.rsplit('.so.', maxsplit=1)[1]
+            return tuple(int(i) for i in ver.split('.'))
+
         filtered: T.List[str] = []
         for lib in libs:
             # Validate file as a shared library of type libfoo.so.X.Y
@@ -1091,12 +1095,11 @@ def _sort_shlibs_openbsd(libs: T.List[str]) -> T.List[str]:
             if len(ret) != 2:
                 continue
             try:
-                float(ret[1])
+                tuple(int(i) for i in ret[1].split('.'))
             except ValueError:
                 continue
             filtered.append(lib)
-        float_cmp = lambda x: float(x.rsplit('.so.', maxsplit=1)[1])
-        return sorted(filtered, key=float_cmp, reverse=True)
+        return sorted(filtered, key=tuple_key, reverse=True)
 
     @classmethod
     def _get_trials_from_pattern(cls, pattern: str, directory: str, libname: str) -> T.List[Path]:
diff --git a/unittests/internaltests.py b/unittests/internaltests.py
--- a/unittests/internaltests.py
+++ b/unittests/internaltests.py
@@ -549,11 +549,14 @@ def _test_all_naming(self, cc, env, patterns, platform):
         if platform != 'openbsd':
             return
         with tempfile.TemporaryDirectory() as tmpdir:
-            for i in ['libfoo.so.6.0', 'libfoo.so.5.0', 'libfoo.so.54.0', 'libfoo.so.66a.0b', 'libfoo.so.70.0.so.1']:
+            for i in ['libfoo.so.6.0', 'libfoo.so.5.0', 'libfoo.so.54.0', 'libfoo.so.66a.0b', 'libfoo.so.70.0.so.1',
+                      'libbar.so.7.10', 'libbar.so.7.9', 'libbar.so.7.9.3']:
                 libpath = Path(tmpdir) / i
                 libpath.write_text('', encoding='utf-8')
             found = cc._find_library_real('foo', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True)
             self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0')
+            found = cc._find_library_real('bar', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True)
+            self.assertEqual(os.path.basename(found[0]), 'libbar.so.7.10')
 
     def test_find_library_patterns(self):
         '''


Test patch: