Fix default install tag for shared lib symlinks
Versioned shared libraries should have .so file in devel, .so.1 and .so.1.2.3 in runtime. Fixes: #9811
This commit is contained in:
parent
219f40c1e4
commit
01e92dc543
|
@ -135,7 +135,6 @@ class TargetInstallData:
|
|||
fname: str
|
||||
outdir: str
|
||||
outdir_name: InitVar[str]
|
||||
aliases: T.Dict[str, str]
|
||||
strip: bool
|
||||
install_name_mappings: T.Mapping[str, str]
|
||||
rpath_dirs_to_remove: T.Set[bytes]
|
||||
|
@ -173,6 +172,7 @@ class InstallSymlinkData:
|
|||
install_path: str
|
||||
subproject: str
|
||||
tag: T.Optional[str] = None
|
||||
allow_missing: bool = False
|
||||
|
||||
# cannot use dataclass here because "exclude" is out of order
|
||||
class SubdirInstallData(InstallDataBase):
|
||||
|
@ -1581,12 +1581,17 @@ class Backend:
|
|||
tag = t.install_tag[0] or ('devel' if isinstance(t, build.StaticLibrary) else 'runtime')
|
||||
mappings = t.get_link_deps_mapping(d.prefix, self.environment)
|
||||
i = TargetInstallData(self.get_target_filename(t), outdirs[0],
|
||||
install_dir_name, t.get_aliases(),
|
||||
install_dir_name,
|
||||
should_strip, mappings, t.rpath_dirs_to_remove,
|
||||
t.install_rpath, install_mode, t.subproject,
|
||||
tag=tag)
|
||||
d.targets.append(i)
|
||||
|
||||
for alias, to, tag in t.get_aliases():
|
||||
alias = os.path.join(outdirs[0], alias)
|
||||
s = InstallSymlinkData(to, alias, outdirs[0], t.subproject, tag, allow_missing=True)
|
||||
d.symlinks.append(s)
|
||||
|
||||
if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)):
|
||||
# On toolchains/platforms that use an import library for
|
||||
# linking (separate from the shared library with all the
|
||||
|
@ -1602,7 +1607,7 @@ class Backend:
|
|||
# Install the import library; may not exist for shared modules
|
||||
i = TargetInstallData(self.get_target_filename_for_linking(t),
|
||||
implib_install_dir, install_dir_name,
|
||||
{}, False, {}, set(), '', install_mode,
|
||||
False, {}, set(), '', install_mode,
|
||||
t.subproject, optional=isinstance(t, build.SharedModule),
|
||||
tag='devel')
|
||||
d.targets.append(i)
|
||||
|
@ -1611,7 +1616,7 @@ class Backend:
|
|||
debug_file = os.path.join(self.get_target_dir(t), t.get_debug_filename())
|
||||
i = TargetInstallData(debug_file, outdirs[0],
|
||||
install_dir_name,
|
||||
{}, False, {}, set(), '',
|
||||
False, {}, set(), '',
|
||||
install_mode, t.subproject,
|
||||
optional=True, tag='devel')
|
||||
d.targets.append(i)
|
||||
|
@ -1622,7 +1627,7 @@ class Backend:
|
|||
if outdir is False:
|
||||
continue
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdir, install_dir_name, {}, False, {}, set(), None,
|
||||
i = TargetInstallData(f, outdir, install_dir_name, False, {}, set(), None,
|
||||
install_mode, t.subproject,
|
||||
tag=tag)
|
||||
d.targets.append(i)
|
||||
|
@ -1639,7 +1644,7 @@ class Backend:
|
|||
f = os.path.join(self.get_target_dir(t), output)
|
||||
if not install_dir_name:
|
||||
dir_name = os.path.join('{prefix}', outdirs[0])
|
||||
i = TargetInstallData(f, outdirs[0], dir_name, {},
|
||||
i = TargetInstallData(f, outdirs[0], dir_name,
|
||||
False, {}, set(), None, install_mode,
|
||||
t.subproject, optional=not t.build_by_default,
|
||||
tag=tag)
|
||||
|
@ -1653,7 +1658,7 @@ class Backend:
|
|||
if not install_dir_name:
|
||||
dir_name = os.path.join('{prefix}', outdir)
|
||||
i = TargetInstallData(f, outdir, dir_name,
|
||||
{}, False, {}, set(), None, install_mode,
|
||||
False, {}, set(), None, install_mode,
|
||||
t.subproject, optional=not t.build_by_default,
|
||||
tag=tag)
|
||||
d.targets.append(i)
|
||||
|
|
|
@ -3092,8 +3092,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
|
|||
return self.get_target_filename(t)
|
||||
|
||||
def generate_shlib_aliases(self, target, outdir):
|
||||
aliases = target.get_aliases()
|
||||
for alias, to in aliases.items():
|
||||
for alias, to, tag in target.get_aliases():
|
||||
aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
|
||||
try:
|
||||
os.remove(aliasfile)
|
||||
|
|
|
@ -1471,8 +1471,8 @@ You probably should put it in link_with instead.''')
|
|||
else:
|
||||
self.extra_args[language] = args
|
||||
|
||||
def get_aliases(self) -> T.Dict[str, str]:
|
||||
return {}
|
||||
def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
|
||||
return []
|
||||
|
||||
def get_langs_used_by_deps(self) -> T.List[str]:
|
||||
'''
|
||||
|
@ -2240,7 +2240,7 @@ class SharedLibrary(BuildTarget):
|
|||
def get_all_link_deps(self):
|
||||
return [self] + self.get_transitive_link_deps()
|
||||
|
||||
def get_aliases(self) -> T.Dict[str, str]:
|
||||
def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
|
||||
"""
|
||||
If the versioned library name is libfoo.so.0.100.0, aliases are:
|
||||
* libfoo.so.0 (soversion) -> libfoo.so.0.100.0
|
||||
|
@ -2248,7 +2248,7 @@ class SharedLibrary(BuildTarget):
|
|||
Same for dylib:
|
||||
* libfoo.dylib (unversioned; for linking) -> libfoo.0.dylib
|
||||
"""
|
||||
aliases: T.Dict[str, str] = {}
|
||||
aliases: T.List[T.Tuple[str, str, str]] = []
|
||||
# Aliases are only useful with .so and .dylib libraries. Also if
|
||||
# there's no self.soversion (no versioning), we don't need aliases.
|
||||
if self.suffix not in ('so', 'dylib') or not self.soversion:
|
||||
|
@ -2260,14 +2260,16 @@ class SharedLibrary(BuildTarget):
|
|||
if self.suffix == 'so' and self.ltversion and self.ltversion != self.soversion:
|
||||
alias_tpl = self.filename_tpl.replace('ltversion', 'soversion')
|
||||
ltversion_filename = alias_tpl.format(self)
|
||||
aliases[ltversion_filename] = self.filename
|
||||
tag = self.install_tag[0] or 'runtime'
|
||||
aliases.append((ltversion_filename, self.filename, tag))
|
||||
# libfoo.so.0/libfoo.0.dylib is the actual library
|
||||
else:
|
||||
ltversion_filename = self.filename
|
||||
# Unversioned alias:
|
||||
# libfoo.so -> libfoo.so.0
|
||||
# libfoo.dylib -> libfoo.0.dylib
|
||||
aliases[self.basic_filename_tpl.format(self)] = ltversion_filename
|
||||
tag = self.install_tag[0] or 'devel'
|
||||
aliases.append((self.basic_filename_tpl.format(self), ltversion_filename, tag))
|
||||
return aliases
|
||||
|
||||
def type_suffix(self):
|
||||
|
|
|
@ -428,11 +428,11 @@ class Installer:
|
|||
append_to_log(self.lf, to_file)
|
||||
return True
|
||||
|
||||
def do_symlink(self, target: str, link: str, full_dst_dir: str) -> bool:
|
||||
def do_symlink(self, target: str, link: str, full_dst_dir: str, allow_missing: bool) -> bool:
|
||||
abs_target = target
|
||||
if not os.path.isabs(target):
|
||||
abs_target = os.path.join(full_dst_dir, target)
|
||||
if not os.path.exists(abs_target):
|
||||
if not os.path.exists(abs_target) and not allow_missing:
|
||||
raise MesonException(f'Tried to install symlink to missing file {abs_target}')
|
||||
if os.path.exists(link):
|
||||
if not os.path.islink(link):
|
||||
|
@ -592,7 +592,7 @@ class Installer:
|
|||
full_dst_dir = get_destdir_path(destdir, fullprefix, s.install_path)
|
||||
full_link_name = get_destdir_path(destdir, fullprefix, s.name)
|
||||
dm.makedirs(full_dst_dir, exist_ok=True)
|
||||
if self.do_symlink(s.target, full_link_name, full_dst_dir):
|
||||
if self.do_symlink(s.target, full_link_name, full_dst_dir, s.allow_missing):
|
||||
self.did_install_something = True
|
||||
|
||||
def install_man(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
|
||||
|
@ -676,7 +676,6 @@ class Installer:
|
|||
outdir = get_destdir_path(destdir, fullprefix, t.outdir)
|
||||
outname = os.path.join(outdir, os.path.basename(fname))
|
||||
final_path = os.path.join(d.prefix, t.outdir, os.path.basename(fname))
|
||||
aliases = t.aliases
|
||||
should_strip = t.strip
|
||||
install_rpath = t.install_rpath
|
||||
install_name_mappings = t.install_name_mappings
|
||||
|
@ -711,9 +710,6 @@ class Installer:
|
|||
self.do_copydir(d, fname, outname, None, install_mode, dm)
|
||||
else:
|
||||
raise RuntimeError(f'Unknown file type for {fname!r}')
|
||||
for alias, target in aliases.items():
|
||||
symlinkfilename = os.path.join(outdir, alias)
|
||||
self.do_symlink(target, symlinkfilename, outdir)
|
||||
if file_copied:
|
||||
self.did_install_something = True
|
||||
try:
|
||||
|
|
|
@ -107,9 +107,6 @@ def list_installed(installdata: backends.InstallData) -> T.Dict[str, str]:
|
|||
for t in installdata.targets:
|
||||
res[os.path.join(installdata.build_dir, t.fname)] = \
|
||||
os.path.join(installdata.prefix, t.outdir, os.path.basename(t.fname))
|
||||
for alias in t.aliases.keys():
|
||||
res[os.path.join(installdata.build_dir, alias)] = \
|
||||
os.path.join(installdata.prefix, t.outdir, os.path.basename(alias))
|
||||
for i in installdata.data:
|
||||
res[i.path] = os.path.join(installdata.prefix, i.install_path)
|
||||
for i in installdata.headers:
|
||||
|
@ -118,6 +115,9 @@ def list_installed(installdata: backends.InstallData) -> T.Dict[str, str]:
|
|||
res[i.path] = os.path.join(installdata.prefix, i.install_path)
|
||||
for i in installdata.install_subdirs:
|
||||
res[i.path] = os.path.join(installdata.prefix, i.install_path)
|
||||
for s in installdata.symlinks:
|
||||
basename = os.path.basename(s.name)
|
||||
res[basename] = os.path.join(installdata.prefix, s.install_path, basename)
|
||||
return res
|
||||
|
||||
def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[str, T.Dict[str, T.Optional[str]]]]:
|
||||
|
@ -216,9 +216,17 @@ def list_targets(builddata: build.Build, installdata: backends.InstallData, back
|
|||
# Fast lookup table for installation files
|
||||
install_lookuptable = {}
|
||||
for i in installdata.targets:
|
||||
out = [os.path.join(installdata.prefix, i.outdir, os.path.basename(i.fname))]
|
||||
out += [os.path.join(installdata.prefix, i.outdir, os.path.basename(x)) for x in i.aliases]
|
||||
install_lookuptable[os.path.basename(i.fname)] = [str(PurePath(x)) for x in out]
|
||||
basename = os.path.basename(i.fname)
|
||||
install_lookuptable[basename] = [str(PurePath(installdata.prefix, i.outdir, basename))]
|
||||
for s in installdata.symlinks:
|
||||
# Symlink's target must already be in the table. They share the same list
|
||||
# to support symlinks to symlinks recursively, such as .so -> .so.0 -> .so.1.2.3
|
||||
basename = os.path.basename(s.name)
|
||||
try:
|
||||
install_lookuptable[basename] = install_lookuptable[os.path.basename(s.target)]
|
||||
install_lookuptable[basename].append(str(PurePath(installdata.prefix, s.install_path, basename)))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for (idname, target) in builddata.get_targets().items():
|
||||
if not isinstance(target, build.Target):
|
||||
|
|
|
@ -43,6 +43,12 @@ both_libraries('both', 'lib.c',
|
|||
install: true,
|
||||
)
|
||||
|
||||
# Unversioned .so file should have 'devel' tag, others should have 'runtime' tag
|
||||
shared_library('versioned_shared', 'lib.c',
|
||||
install: true,
|
||||
version: '1.2.3',
|
||||
)
|
||||
|
||||
# Those files should have custom tag
|
||||
install_data('bar-custom.txt',
|
||||
install_dir: get_option('datadir'),
|
||||
|
|
|
@ -3886,10 +3886,12 @@ class AllPlatformTests(BasePlatformTests):
|
|||
Path(installpath, 'usr/bin/both2.pdb'),
|
||||
Path(installpath, 'usr/bin/bothcustom.pdb'),
|
||||
Path(installpath, 'usr/bin/shared.pdb'),
|
||||
Path(installpath, 'usr/bin/versioned_shared-1.pdb'),
|
||||
Path(installpath, 'usr/lib/both.lib'),
|
||||
Path(installpath, 'usr/lib/both2.lib'),
|
||||
Path(installpath, 'usr/lib/bothcustom.lib'),
|
||||
Path(installpath, 'usr/lib/shared.lib'),
|
||||
Path(installpath, 'usr/lib/versioned_shared.lib'),
|
||||
}
|
||||
elif is_windows() or is_cygwin():
|
||||
expected_devel |= {
|
||||
|
@ -3897,6 +3899,11 @@ class AllPlatformTests(BasePlatformTests):
|
|||
Path(installpath, 'usr/lib/libboth2.dll.a'),
|
||||
Path(installpath, 'usr/lib/libshared.dll.a'),
|
||||
Path(installpath, 'usr/lib/libbothcustom.dll.a'),
|
||||
Path(installpath, 'usr/lib/libversioned_shared.dll.a'),
|
||||
}
|
||||
else:
|
||||
expected_devel |= {
|
||||
Path(installpath, 'usr/' + shared_lib_name('versioned_shared')),
|
||||
}
|
||||
|
||||
expected_runtime = expected_common | {
|
||||
|
@ -3908,6 +3915,20 @@ class AllPlatformTests(BasePlatformTests):
|
|||
Path(installpath, 'usr/' + shared_lib_name('both2')),
|
||||
}
|
||||
|
||||
if is_windows() or is_cygwin():
|
||||
expected_runtime |= {
|
||||
Path(installpath, 'usr/' + shared_lib_name('versioned_shared-1')),
|
||||
}
|
||||
elif is_osx():
|
||||
expected_runtime |= {
|
||||
Path(installpath, 'usr/' + shared_lib_name('versioned_shared.1')),
|
||||
}
|
||||
else:
|
||||
expected_runtime |= {
|
||||
Path(installpath, 'usr/' + shared_lib_name('versioned_shared') + '.1'),
|
||||
Path(installpath, 'usr/' + shared_lib_name('versioned_shared') + '.1.2.3'),
|
||||
}
|
||||
|
||||
expected_custom = expected_common | {
|
||||
Path(installpath, 'usr/share'),
|
||||
Path(installpath, 'usr/share/bar-custom.txt'),
|
||||
|
|
Loading…
Reference in New Issue