Repository: mesonbuild/meson

Issue:
Don't require import library on installation for shared modules
Shared modules might not export any symbols at all, so while we should install an import library if the linker generated one, if it doesn't exist, we should print a message about that and continue the installation instead of throwing a traceback:

```pytb
Traceback (most recent call last):
  File "d:\\projects\\cerbero\\meson\\master\\build\\build-tools\\Scripts\\meson.py", line 4, in <module>
    __import__('pkg_resources').run_script('meson==0.47.0', 'meson.py')
  File "c:\Python36-32\lib\site-packages\pkg_resources\__init__.py", line 658, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "c:\Python36-32\lib\site-packages\pkg_resources\__init__.py", line 1438, in run_script
    exec(code, namespace, namespace)
  File "d:\projects\cerbero\meson\master\build\build-tools\lib\site-packages\meson-0.47.0-py3.6.egg\EGG-INFO\scripts\meson.py", line 29, in <module>
    sys.exit(mesonmain.main())
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\mesonmain.py", line 367, in main
    return run(sys.argv[1:], launcher)
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\mesonmain.py", line 281, in run
    return minstall.run(remaining_args)
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\minstall.py", line 466, in run
    installer.do_install(datafilename)
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\minstall.py", line 298, in do_install
    self.install_targets(d)
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\minstall.py", line 387, in install_targets
    fname = check_for_stampfile(t.fname)
  File "d:\projects\cerbero\meson\master\build\build-tools\Lib\site-packages\meson-0.47.0-py3.6.egg\mesonbuild\minstall.py", line 170, in check_for_stampfile
    if os.stat(fname).st_size == 0:
FileNotFoundError: [WinError 2] The system cannot find the file specified: 'tls/gnutls\\giognutls.lib'
FAILED: meson-install
"c:\\Python36-32\\python.exe" "d:\\projects\\cerbero\\meson\\master\\build\\build-tools\\Scripts\\meson.py" "install" "--no-rebuild"
ninja: build stopped: subcommand failed.
```


Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -55,7 +55,7 @@ def __init__(self, source_dir, build_dir, prefix, strip_bin,
         self.mesonintrospect = mesonintrospect
 
 class TargetInstallData:
-    def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode):
+    def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode, optional=False):
         self.fname = fname
         self.outdir = outdir
         self.aliases = aliases
@@ -63,6 +63,7 @@ def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install
         self.install_name_mappings = install_name_mappings
         self.install_rpath = install_rpath
         self.install_mode = install_mode
+        self.optional = optional
 
 class ExecutableSerialisation:
     def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper,
@@ -1047,9 +1048,10 @@ def generate_target_install(self, d):
                             implib_install_dir = outdirs[0]
                         else:
                             implib_install_dir = self.environment.get_import_lib_dir()
-                        # Install the import library.
+                        # Install the import library; may not exist for shared modules
                         i = TargetInstallData(self.get_target_filename_for_linking(t),
-                                              implib_install_dir, {}, False, {}, '', install_mode)
+                                              implib_install_dir, {}, False, {}, '', install_mode,
+                                              optional=isinstance(t, build.SharedModule))
                         d.targets.append(i)
                 # Install secondary outputs. Only used for Vala right now.
                 if num_outdirs > 1:
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -1274,6 +1274,9 @@ def get_gui_app_args(self):
     def get_pic_args(self):
         return [] # PIC is handled by the loader on Windows
 
+    def gen_export_dynamic_link_args(self, env):
+        return [] # Not applicable with MSVC
+
     def get_std_shared_lib_link_args(self):
         return ['/DLL']
 
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -384,6 +384,13 @@ def run_install_script(self, d):
 
     def install_targets(self, d):
         for t in d.targets:
+            if not os.path.exists(t.fname):
+                # For example, import libraries of shared modules are optional
+                if t.optional:
+                    print('File {!r} not found, skipping'.format(t.fname))
+                    continue
+                else:
+                    raise RuntimeError('File {!r} could not be found'.format(t.fname))
             fname = check_for_stampfile(t.fname)
             outdir = get_destdir_path(d, t.outdir)
             outname = os.path.join(outdir, os.path.basename(fname))


Test patch:
diff --git a/test cases/common/125 shared module/installed_files.txt b/test cases/common/125 shared module/installed_files.txt
new file mode 100644
--- /dev/null
+++ b/test cases/common/125 shared module/installed_files.txt	
@@ -0,0 +1 @@
+usr/lib/libnosyms.so
diff --git a/test cases/common/125 shared module/meson.build b/test cases/common/125 shared module/meson.build
--- a/test cases/common/125 shared module/meson.build	
+++ b/test cases/common/125 shared module/meson.build	
@@ -11,3 +11,10 @@ m = shared_module('mymodule', 'module.c')
 e = executable('prog', 'prog.c',
   link_with : l, export_dynamic : true, dependencies : dl)
 test('import test', e, args : m)
+
+# Shared module that does not export any symbols
+shared_module('nosyms', 'nosyms.c', install : true,
+              # Because we don't have cross-platform library support in
+              # installed_files.txt
+              name_suffix : 'so',
+              name_prefix : 'lib')
diff --git a/test cases/common/125 shared module/nosyms.c b/test cases/common/125 shared module/nosyms.c
new file mode 100644
--- /dev/null
+++ b/test cases/common/125 shared module/nosyms.c	
@@ -0,0 +1,4 @@
+static int
+func_not_exported (void) {
+    return 99;
+}