aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py19
-rw-r--r--mesonbuild/backend/ninjabackend.py3
-rw-r--r--mesonbuild/build.py14
-rw-r--r--mesonbuild/minstall.py10
-rw-r--r--mesonbuild/mintro.py20
-rw-r--r--test cases/unit/99 install all targets/meson.build6
-rw-r--r--unittests/allplatformstests.py21
7 files changed, 65 insertions, 28 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index dae9c47..b98eb08 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -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)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 560fe53..a66111b 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -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)
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index bb57ec8..e0f07ab 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -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):
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index 80b0239..b51d4f0 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -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:
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 130cf93..e3a613f 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -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):
diff --git a/test cases/unit/99 install all targets/meson.build b/test cases/unit/99 install all targets/meson.build
index 94bd1fe..3d131e6 100644
--- a/test cases/unit/99 install all targets/meson.build
+++ b/test cases/unit/99 install all targets/meson.build
@@ -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'),
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 3eea9a3..665e0c6 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -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'),