Repository: mesonbuild/meson

Issue:
intel compiler doesn't implement link_whole
Hi,
I got an error when including PETSc as external dependency. Here is my `meson.build`
```
project('xxx', 'cpp', default_options : ['cpp_std=c++11'])

pdep = dependency('PETSc')
```
this is what I get when I run meson

```The Meson build system
Version: 0.47.0
Source dir: /some/path/
Build dir: /some/path/build
Build type: native build
Project name: xxx
Project version: undefined
Native C++ compiler: icpc (intel 17.0.4 "icpc (ICC) 17.0.4 20170411")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.27.1)

meson.build:5:0: ERROR:  Language C++ does not support linking whole archives.

A full log can be found at /some/path/build/meson-logs/meson-log.txt
```
and the log is
```
Build started at 2018-07-10T11:48:00.454242
Main binary: /bin/python3
Python system: Linux
The Meson build system
Version: 0.47.0
Source dir: /some/path
Build dir: /some/path/build
Build type: native build
Project name: xxx
Project version: undefined
Sanity testing C++ compiler: icpc
Is cross compiler: False.
Sanity check compiler command line: icpc /some/path/build/meson-private/sanitycheckcpp.cc -o /some/path/build/meson-private/sanitycheckcpp.exe
Sanity check compile stdout:

-----
Sanity check compile stderr:

-----
Running test binary command: /some/path/build/meson-private/sanitycheckcpp.exe
Native C++ compiler: icpc (intel 17.0.4 "icpc (ICC) 17.0.4 20170411")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.27.1)
Determining dependency 'PETSc' with pkg-config executable '/usr/bin/pkg-config'
Called `/usr/bin/pkg-config --modversion PETSc` -> 0
3.9.2
Called `/usr/bin/pkg-config --cflags PETSc` -> 0
-I/...../petsc-3.9.2/arch-linux-c-dbg-g-real-avx-2-512-int64/include
Called `/usr/bin/pkg-config PETSc --libs` -> 0
-L/...../petsc-3.9.2/arch-linux-c-dbg-g-real-avx-2-512-int64/lib -lpetsc
Called `/usr/bin/pkg-config PETSc --libs` -> 0
-L/......./petsc-3.9.2/arch-linux-c-dbg-g-real-avx-2-512-int64/lib -lpetsc

meson.build:5:0: ERROR:  Language C++ does not support linking whole archives.
```

however, if I issue from the command line

```
icpc $(pkg-config --cflags --libs PETSc) meson-private/sanitycheckcpp.cc
```
it compiles and links..

What happens inside the call to `dependency`? Why I get that error and how can I solve it?

thanks



Discussion:
nirbheek: Another thing that would be a Very Nice Thing that ensures that stuff like this doesn't break the Intel compiler in the future is to find a way to add the latest version of ICC to the Docker instance that we use for running [Linux tests on the CI](https://github.com/mesonbuild/meson/blob/master/.travis.yml). Then we can run the tests against it in the same way that we run clang tests.
asartori86: > find a way to add the latest version of ICC to the Docker instance

don't you have to pay to have the intel compiler?
nirbheek: > don't you have to pay for intel compiler?

I believe you can get a free version for open source use: https://software.intel.com/en-us/qualify-for-free-software/opensourcecontributor

I remember getting it for FOSS use 1-2 years ago when I was implementing it for Meson, but I don't remember how.

Patch:
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index b62155b7b..af3e2c4a1 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -866,12 +866,29 @@ class CCompiler(Compiler):
         return patterns
 
     @staticmethod
-    def _get_trials_from_pattern(pattern, directory, libname):
+    def _sort_shlibs_openbsd(libs):
+        filtered = []
+        for lib in libs:
+            # Validate file as a shared library of type libfoo.so.X.Y
+            ret = lib.rsplit('.so.', maxsplit=1)
+            if len(ret) != 2:
+                continue
+            try:
+                float(ret[1])
+            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)
+
+    @classmethod
+    def _get_trials_from_pattern(cls, pattern, directory, libname):
         f = os.path.join(directory, pattern.format(libname))
+        # Globbing for OpenBSD
         if '*' in pattern:
             # NOTE: globbing matches directories and broken symlinks
             # so we have to do an isfile test on it later
-            return glob.glob(f)
+            return cls._sort_shlibs_openbsd(glob.glob(f))
         return [f]
 
     @staticmethod
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 21aab1163..25835a32d 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1561,6 +1561,9 @@ class IntelCompiler:
         else:
             return ['-openmp']
 
+    def get_link_whole_for(self, args):
+        return GnuCompiler.get_link_whole_for(self, args)
+
 
 class ArmCompiler:
     # Functionality that is common to all ARM family compilers.


Test patch:
diff --git a/run_unittests.py b/run_unittests.py
index df4603e3a..f4e95a302 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -522,12 +522,28 @@ class InternalTests(unittest.TestCase):
         self.assertEqual(p, shr)
         p = cc.get_library_naming(env, 'static')
         self.assertEqual(p, stc)
-        p = cc.get_library_naming(env, 'default')
-        self.assertEqual(p, shr + stc)
-        p = cc.get_library_naming(env, 'shared-static')
-        self.assertEqual(p, shr + stc)
         p = cc.get_library_naming(env, 'static-shared')
         self.assertEqual(p, stc + shr)
+        p = cc.get_library_naming(env, 'shared-static')
+        self.assertEqual(p, shr + stc)
+        p = cc.get_library_naming(env, 'default')
+        self.assertEqual(p, shr + stc)
+        # Test find library by mocking up openbsd
+        if platform != 'openbsd':
+            return
+        with tempfile.TemporaryDirectory() as tmpdir:
+            with open(os.path.join(tmpdir, 'libfoo.so.6.0'), 'w') as f:
+                f.write('')
+            with open(os.path.join(tmpdir, 'libfoo.so.5.0'), 'w') as f:
+                f.write('')
+            with open(os.path.join(tmpdir, 'libfoo.so.54.0'), 'w') as f:
+                f.write('')
+            with open(os.path.join(tmpdir, 'libfoo.so.66a.0b'), 'w') as f:
+                f.write('')
+            with open(os.path.join(tmpdir, 'libfoo.so.70.0.so.1'), 'w') as f:
+                f.write('')
+            found = cc.find_library_real('foo', env, [tmpdir], '', 'default')
+            self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0')
 
     def test_find_library_patterns(self):
         '''