minstall: stop running ldconfig for the user

This was a nice idea in theory, but in practice it had various problems:

- On the only platform where ldconfig is expected to be run, it is
  really slow, even when the user uses a non-default prefix and ldconfig
  doesn't even have permission to run, nor can do anything useful due to
  ld.so.conf state
- On FreeBSD, it bricked the system: #9592
- On cross builds, it should not be used and broke installing, because
  ldconfig may not be runnable without binfmt + qemu: #9707
- it prints weird and confusing errors in the common "custom prefix"
  layout: #9241

Some of these problems can be or have been fixed. But it's a constant
source of footguns and complaints and for something that was originally
supposed to be just "it's the right thing to do anyway, so just do it
automatically" it is entirely too risky.

Ultimately I do not think there is justification for keeping this
feature in since it doesn't actually make everyone happy. Better for
users to decide whether they need this themselves.

This is anyways the case for cmake and autotools and generally any other
build system, so it should not be too intimidating...

Fixes #9721
pull/9926/head
Eli Schwartz 3 years ago
parent 6c1bb02f13
commit a45446b6e5
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 5
      docs/markdown/snippets/no_ldconfig.md
  2. 4
      mesonbuild/backend/backends.py
  3. 43
      mesonbuild/minstall.py

@ -0,0 +1,5 @@
## ldconfig is no longer run on install
Due to various issues of fragility and concern that it doesn't predictably do
the right thing, meson no longer runs ldconfig during `meson install`, and
users who need it run should run it themselves, instead.

@ -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 @@ class Backend:
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)

@ -18,7 +18,6 @@ import argparse
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 @@ class Installer:
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 @@ class Installer:
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 @@ class Installer:
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.')

Loading…
Cancel
Save