Repository: mesonbuild/meson

Issue:
Warn or error out when targets try to link_with: shared modules
On osx shared modules are NOT getting -install arguments, (there seems to be a reason for this).

But when creating the .symol files, we rely on finding a LC_ID_DYLIB. Which will read to a crash.


Discussion:
It's not really clear what you are trying to say, could you please describe:

1. What version of meson you are using
2. What you are trying to do
3. Why it doesn't work (and how did it work earlier, and with what build system)
The bug meanwhile clarified itself a bit more, and i managed to fix it on my side, however, there are a few things:

First of all, what was my mistake:
I used 
```
tmp = shared_module(...) 
[...]
shared_library(...
   link_with : tmp
)
```

Which does not give a error at `meson` stage. However, when building you will get a meson crash, since meson wants to create a .SYMBOL file of a .so file, this means it searches for a LC_ID_DYLIB in the .so file, but that one is not set. And thus the code fails.

What I would have expected:
It would be super usefull if meson would tell me in such a case that that is usally not really what i should do, (linking a shared_module into a shared_library).

Resolving patch:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -380,6 +380,7 @@ def __init__(self, name, subdir, subproject, is_cross, sources, objects, environ
         self.process_compilers_late()
         self.validate_sources()
         self.validate_cross_install(environment)
+        self.check_module_linking()
 
     def __lt__(self, other):
         return self.get_id() < other.get_id()
@@ -1027,6 +1028,15 @@ def get_using_msvc(self):
     def is_linkable_target(self):
         return False
 
+    def check_module_linking(self):
+        '''
+        Warn if shared modules are linked with target: (link_with) #2865
+        '''
+        for link_target in self.link_targets:
+            if isinstance(link_target, SharedModule):
+                mlog.warning('''target links against shared modules. This is not
+recommended as it can lead to undefined behaviour on some platforms''')
+                return
 
 class Generator:
     def __init__(self, args, kwargs):
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1897,6 +1897,16 @@ def test_flock(self):
                     exception_raised = True
         self.assertTrue(exception_raised, 'Double locking did not raise exception.')
 
+    def test_check_module_linking(self):
+        """
+        Test that shared modules are not linked with targets(link_with:) #2865
+        """
+        tdir = os.path.join(self.unit_test_dir, '26 shared_mod linking')
+        out = self.init(tdir)
+        msg = ('''WARNING: target links against shared modules. This is not
+recommended as it can lead to undefined behaviour on some platforms''')
+        self.assertIn(msg, out)
+
     def test_ndebug_if_release_disabled(self):
         testdir = os.path.join(self.unit_test_dir, '25 ndebug if-release')
         self.init(testdir, extra_args=['--buildtype=release', '-Db_ndebug=if-release'])


Test patch:
diff --git a/test cases/unit/26 shared_mod linking/libfile.c b/test cases/unit/26 shared_mod linking/libfile.c
new file mode 100644
--- /dev/null
+++ b/test cases/unit/26 shared_mod linking/libfile.c	
@@ -0,0 +1,14 @@
+#if defined _WIN32 || defined __CYGWIN__
+  #define DLL_PUBLIC __declspec(dllexport)
+#else
+  #if defined __GNUC__
+    #define DLL_PUBLIC __attribute__ ((visibility("default")))
+  #else
+    #pragma message ("Compiler does not support symbol visibility.")
+    #define DLL_PUBLIC
+  #endif
+#endif
+
+int DLL_PUBLIC func() {
+    return 0;
+}
diff --git a/test cases/unit/26 shared_mod linking/main.c b/test cases/unit/26 shared_mod linking/main.c
new file mode 100644
--- /dev/null
+++ b/test cases/unit/26 shared_mod linking/main.c	
@@ -0,0 +1,11 @@
+#if defined _WIN32 || defined __CYGWIN__
+  #define DLL_IMPORT __declspec(dllimport)
+#else
+  #define DLL_IMPORT
+#endif
+
+int DLL_IMPORT func();
+
+int main(int argc, char **arg) {
+    return func();
+}
diff --git a/test cases/unit/26 shared_mod linking/meson.build b/test cases/unit/26 shared_mod linking/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/unit/26 shared_mod linking/meson.build	
@@ -0,0 +1,5 @@
+project('shared library linking test', 'c', 'cpp')
+
+mod = shared_module('mymod', 'libfile.c')
+
+exe = executable('prog', 'main.c', link_with : mod, install : true)
\ No newline at end of file