Repository: mesonbuild/meson

Issue:
Stop calling ldconfig on `meson install`
We've now had three different bugs around this, and it's slow when we don't need to call it, and it doesn't always yield the desired results anyway. I'd like to call for its removal in 0.61. I'm opening this, so we can generate some consensus in a single place.


Discussion:
I was originally a bit nervous about the potential for this to behave unexpectedly, but I have to admit I never in my wildest dreams expected it to brick the OS as it did on *BSD.

I have no objections to removing it. I keep on fearfully expecting a 4th bug to be reported, obviously only after 0.61 is released.
It should perhaps become an option. On Linux I never ran into issues with ldconfig (unless I would mix different glibc-versions and the new compiled one can not be handled by older compiled programs, but there are ways to work around and deal with that; I also only rarely have to upgrade glibc as such); sad to hear that BSDs can not handle this. The default may then be to disable it, and only enable it if the author states so, and perhaps conditionally - just so that operating systems that get ldconfig-nuked don't get ldconfig-nuked any longer.
Originally we did not call it, but added it because people wanted it.
> It should perhaps become an option. 

No. No options. Either get it working reliably automatically or do nothing.
I don't think we can make it work reliably without a switch, because we have to know the intention of the user to know what the right thing to do is. That said, by the time we add a flag a user can just call ldconfig themselves...

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -119,7 +119,6 @@ class InstallData:
     install_umask: T.Union[str, int]
     mesonintrospect: T.List[str]
     version: str
-    is_cross_build: bool
 
     def __post_init__(self) -> None:
         self.targets: T.List[TargetInstallData] = []
@@ -1502,8 +1501,7 @@ def create_install_data(self) -> InstallData:
                         strip_bin,
                         umask,
                         self.environment.get_build_command() + ['introspect'],
-                        self.environment.coredata.version,
-                        self.environment.is_cross_build())
+                        self.environment.coredata.version)
         self.generate_depmf_install(d)
         self.generate_target_install(d)
         self.generate_header_install(d)
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -18,7 +18,6 @@
 import errno
 import os
 import pickle
-import platform
 import shlex
 import shutil
 import subprocess
@@ -248,41 +247,6 @@ def restore_selinux_contexts() -> None:
               'Standard output:', out,
               'Standard error:', err, sep='\n')
 
-def apply_ldconfig(dm: DirMaker, libdir: str) -> None:
-    '''
-    Apply ldconfig to update the ld.so.cache.
-    '''
-    if not shutil.which('ldconfig'):
-        # If we don't have ldconfig, failure is ignored quietly.
-        return
-
-    platlower = platform.system().lower()
-    if platlower == 'dragonfly' or 'bsd' in platlower:
-        if libdir in dm.all_dirs:
-            proc, out, err = Popen_safe(['ldconfig', '-m', libdir])
-            if proc.returncode != 0:
-                print('Failed to apply ldconfig ...',
-                      'Standard output:', out,
-                      'Standard error:', err, sep='\n')
-        return
-
-    # Try to update ld cache, it could fail if we don't have permission.
-    proc, out, err = Popen_safe(['ldconfig', '-v'])
-    if proc.returncode == 0:
-        return
-
-    # ldconfig failed, print the error only if we actually installed files in
-    # any of the directories it lookup for libraries. Otherwise quietly ignore
-    # the error.
-    for l in out.splitlines():
-        # Lines that start with a \t are libraries, not directories.
-        if not l or l[0].isspace():
-            continue
-        # Example: `/usr/lib/i386-linux-gnu/i686: (hwcap: 0x0002000000000000)`
-        if l[:l.find(':')] in dm.all_dirs:
-            print(f'Failed to apply ldconfig:\n{err}')
-            break
-
 def get_destdir_path(destdir: str, fullprefix: str, path: str) -> str:
     if os.path.isabs(path):
         output = destdir_join(destdir, path)
@@ -384,11 +348,6 @@ def restore_selinux_contexts(self, destdir: str) -> None:
         if not self.dry_run and not destdir:
             restore_selinux_contexts()
 
-    def apply_ldconfig(self, dm: DirMaker, destdir: str, is_cross_build: bool, libdir: str) -> None:
-        if any([self.dry_run, destdir, is_cross_build]):
-            return
-        apply_ldconfig(dm, libdir)
-
     def Popen_safe(self, *args: T.Any, **kwargs: T.Any) -> T.Tuple[int, str, str]:
         if not self.dry_run:
             p, o, e = Popen_safe(*args, **kwargs)
@@ -574,7 +533,6 @@ def do_install(self, datafilename: str) -> None:
             os.environ['DESTDIR'] = destdir
         destdir = destdir or ''
         fullprefix = destdir_join(destdir, d.prefix)
-        libdir = os.path.join(d.prefix, d.libdir)
 
         if d.install_umask != 'preserve':
             assert isinstance(d.install_umask, int)
@@ -591,7 +549,6 @@ def do_install(self, datafilename: str) -> None:
                 self.install_data(d, dm, destdir, fullprefix)
                 self.install_symlinks(d, dm, destdir, fullprefix)
                 self.restore_selinux_contexts(destdir)
-                self.apply_ldconfig(dm, destdir, d.is_cross_build, libdir)
                 self.run_install_script(d, destdir, fullprefix)
                 if not self.did_install_something:
                     self.log('Nothing to install.')


Test patch: