Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'install-name' target property #11954

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class TargetInstallData:
optional: bool = False
tag: T.Optional[str] = None
can_strip: bool = False
install_fname: T.Optional[str] = None

def __post_init__(self, outdir_name: T.Optional[str]) -> None:
if outdir_name is None:
Expand Down Expand Up @@ -1714,7 +1715,7 @@ def generate_target_install(self, d: InstallData) -> None:
first_outdir_name,
should_strip, mappings, t.rpath_dirs_to_remove,
t.install_rpath, install_mode, t.subproject,
tag=tag, can_strip=can_strip)
tag=tag, can_strip=can_strip, install_fname=t.get_install_fname())
d.targets.append(i)

for alias, to, tag in t.get_aliases():
Expand Down
7 changes: 5 additions & 2 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3251,10 +3251,13 @@ def get_target_type_link_args(self, target, linker):
commands += linker.get_std_shared_lib_link_args()
# All shared libraries are PIC
commands += linker.get_pic_args()
if not isinstance(target, build.SharedModule) or target.force_soname:
soname = target.get_install_name()
if not isinstance(target, build.SharedModule) or target.force_soname or soname:
if not soname:
soname = target.name
# Add -Wl,-soname arguments on Linux, -install_name on OS X
commands += linker.get_soname_args(
self.environment, target.prefix, target.name, target.suffix,
self.environment, target.prefix, soname, target.suffix,
target.soversion, target.darwin_versions)
# This is only visited when building for Windows using either GCC or Visual Studio
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
Expand Down
99 changes: 82 additions & 17 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
get_filenames_templates_dict, substitute_values, has_path_sep,
OptionKey, PerMachineDefaultable, OptionOverrideProxy,
MesonBugException, EnvironmentVariables, pickle_load,
flatten_path,
)
from .compilers import (
is_object, clink_langs, sort_clink, all_languages,
Expand Down Expand Up @@ -92,6 +93,7 @@
'install_rpath',
'install_dir',
'install_mode',
'install_name',
'install_tag',
'name_prefix',
'name_suffix',
Expand Down Expand Up @@ -519,6 +521,7 @@ class Target(HoldableObject, metaclass=abc.ABCMeta):
build_always_stale: bool = False
extra_files: T.List[File] = field(default_factory=list)
override_options: InitVar[T.Optional[T.Dict[OptionKey, str]]] = None
install_name: T.Optional[str] = None

@abc.abstractproperty
def typename(self) -> str:
Expand All @@ -536,12 +539,14 @@ def __post_init__(self, overrides: T.Optional[T.Dict[OptionKey, str]]) -> None:
ovr = {}
self.options = OptionOverrideProxy(ovr, self.environment.coredata.options, self.subproject)
# XXX: this should happen in the interpreter
self.install_name_auto = None
if has_path_sep(self.name):
# Fix failing test 53 when this becomes an error.
mlog.warning(textwrap.dedent(f'''\
Target "{self.name}" has a path separator in its name.
This is not supported, it can cause unexpected failures and will become
a hard error in the future.'''))
a hard error in the future. Consider using the install_name property instead'''))
self.install_name_auto = os.path.basename(self.name)
self.name = flatten_path(self.name)

# dataclass comparators?
def __lt__(self, other: object) -> bool:
Expand All @@ -564,6 +569,21 @@ def __ge__(self, other: object) -> bool:
return NotImplemented
return self.get_id() >= other.get_id()

def get_install_fname(self) -> str:
return self.get_install_name()

def get_install_name(self) -> str:
if self.install_name:
return self.install_name
if not self.install_name_auto:
return None
prefix = None
if getattr(self, 'name_prefix_set', False) or hasattr(self, 'prefix'):
prefix = self.prefix
if prefix and self.install_name_auto.startswith(prefix):
return self.install_name_auto[len(prefix):]
return self.install_name_auto

def get_default_install_dir(self) -> T.Tuple[str, str]:
raise NotImplementedError

Expand Down Expand Up @@ -1136,6 +1156,7 @@ def process_kwargs(self, kwargs):
self.install_dir = typeslistify(kwargs.get('install_dir', []),
(str, bool))
self.install_mode = kwargs.get('install_mode', None)
self.install_name = kwargs.get('install_name', None)
self.install_tag = stringlistify(kwargs.get('install_tag', [None]))
main_class = kwargs.get('main_class', '')
if not isinstance(main_class, str):
Expand Down Expand Up @@ -1264,6 +1285,18 @@ def _extract_pic_pie(self, kwargs, arg: str, option: str):
def get_filename(self) -> str:
return self.filename

def get_install_fname(self) -> str:
install_name = self.get_install_name()
if not install_name:
return None
install_fname = ''
if self.name_prefix_set:
install_fname = self.prefix
install_fname += self.install_name
if self.name_suffix_set:
install_fname += '.' + self.suffix
return install_fname

def get_outputs(self) -> T.List[str]:
return self.outputs

Expand Down Expand Up @@ -1980,6 +2013,15 @@ def post_init(self) -> None:
def get_default_install_dir(self) -> T.Tuple[str, str]:
return self.environment.get_bindir(), '{bindir}'

def get_install_fname(self) -> str:
install_name = self.get_install_name()
if not install_name:
return None
install_fname = install_name
if self.suffix:
install_fname += '.' + self.suffix
return install_fname

def description(self):
'''Human friendly description of the executable'''
return self.name
Expand Down Expand Up @@ -2095,6 +2137,12 @@ def post_init(self) -> None:
self.filename = self.prefix + self.name + '.' + self.suffix
self.outputs = [self.filename]

def get_install_fname(self) -> str:
install_name = self.get_install_name()
if not install_name:
return None
return self.prefix + install_name + '.' + self.suffix

def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]:
return {}

Expand Down Expand Up @@ -2173,7 +2221,7 @@ def post_init(self) -> None:
self.prefix = None
if not hasattr(self, 'suffix'):
self.suffix = None
self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.basic_filename_tpl = '{0.prefix}{1}.{0.suffix}'
self.determine_filenames()

def get_link_deps_mapping(self, prefix: str) -> T.Mapping[str, str]:
Expand Down Expand Up @@ -2221,7 +2269,7 @@ def determine_filenames(self):
if 'cs' in self.compilers:
prefix = ''
suffix = 'dll'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
create_debug_file = True
# C, C++, Swift, Vala
# Only Windows uses a separate import library for linking
Expand Down Expand Up @@ -2252,9 +2300,9 @@ def determine_filenames(self):
self.import_filename = self.gcc_import_filename
# Shared library has the soversion if it is defined
if self.soversion:
self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}-{0.soversion}.{0.suffix}'
else:
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
elif self.environment.machines[self.for_machine].is_cygwin():
suffix = 'dll'
self.gcc_import_filename = '{}{}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name)
Expand All @@ -2264,47 +2312,53 @@ def determine_filenames(self):
# Import library is called libfoo.dll.a
self.import_filename = self.gcc_import_filename
if self.soversion:
self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}-{0.soversion}.{0.suffix}'
else:
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
elif self.environment.machines[self.for_machine].is_darwin():
prefix = 'lib'
suffix = 'dylib'
# On macOS, the filename can only contain the major version
if self.soversion:
# libfoo.X.dylib
self.filename_tpl = '{0.prefix}{0.name}.{0.soversion}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.soversion}.{0.suffix}'
else:
# libfoo.dylib
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
elif self.environment.machines[self.for_machine].is_android():
prefix = 'lib'
suffix = 'so'
# Android doesn't support shared_library versioning
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
else:
prefix = 'lib'
suffix = 'so'
if self.ltversion:
# libfoo.so.X[.Y[.Z]] (.Y and .Z are optional)
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.ltversion}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}.{0.ltversion}'
elif self.soversion:
# libfoo.so.X
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.soversion}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}.{0.soversion}'
else:
# No versioning, libfoo.so
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
self.filename_tpl = '{0.prefix}{1}.{0.suffix}'
if self.prefix is None:
self.prefix = prefix
if self.suffix is None:
self.suffix = suffix
self.filename = self.filename_tpl.format(self)
self.filename = self.filename_tpl.format(self, self.name)
# There may have been more outputs added by the time we get here, so
# only replace the first entry
self.outputs[0] = self.filename
if create_debug_file:
self.debug_filename = os.path.splitext(self.filename)[0] + '.pdb'

def get_install_fname(self) -> str:
install_name = self.get_install_name()
if not install_name:
return None
return self.filename_tpl.format(self, install_name)

@staticmethod
def _validate_darwin_versions(darwin_versions):
try:
Expand Down Expand Up @@ -2445,7 +2499,7 @@ def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
# Where libfoo.so.0.100.0 is the actual library
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)
ltversion_filename = alias_tpl.format(self, self.name)
tag = self.install_tag[0] or 'runtime'
aliases.append((ltversion_filename, self.filename, tag))
# libfoo.so.0/libfoo.0.dylib is the actual library
Expand All @@ -2455,7 +2509,7 @@ def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
# libfoo.so -> libfoo.so.0
# libfoo.dylib -> libfoo.0.dylib
tag = self.install_tag[0] or 'devel'
aliases.append((self.basic_filename_tpl.format(self), ltversion_filename, tag))
aliases.append((self.basic_filename_tpl.format(self, self.name), ltversion_filename, tag))
return aliases

def type_suffix(self):
Expand Down Expand Up @@ -2583,6 +2637,7 @@ def __init__(self,
install_tag: T.Optional[T.List[T.Optional[str]]] = None,
absolute_paths: bool = False,
backend: T.Optional['Backend'] = None,
install_name: T.Optional[str] = None,
):
# TODO expose keyword arg to make MachineChoice.HOST configurable
super().__init__(name, subdir, subproject, False, MachineChoice.HOST, environment,
Expand All @@ -2605,6 +2660,7 @@ def __init__(self,
self.feed = feed
self.install_dir = list(install_dir or [])
self.install_mode = install_mode
self.install_name = install_name
self.install_tag = _process_install_tag(install_tag, len(self.outputs))
self.name = name if name else self.outputs[0]

Expand Down Expand Up @@ -2924,6 +2980,12 @@ def get_classpath_args(self):
def get_default_install_dir(self) -> T.Tuple[str, str]:
return self.environment.get_jar_dir(), '{jardir}'

def get_install_fname(self) -> str:
install_name = self.get_install_name()
if not install_name:
return None
return install_name + '.jar'

@dataclass(eq=False)
class CustomTargetIndex(HoldableObject):

Expand Down Expand Up @@ -2957,6 +3019,9 @@ def get_subdir(self) -> str:
def get_filename(self) -> str:
return self.output

def get_install_fname(self) -> str:
return self.target.get_install_fname()

def get_id(self) -> str:
return self.target.get_id()

Expand Down
5 changes: 5 additions & 0 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
INSTALL_KW,
INSTALL_DIR_KW,
INSTALL_MODE_KW,
INSTALL_NAME_KW,
LINK_WITH_KW,
LINK_WHOLE_KW,
CT_INSTALL_TAG_KW,
Expand Down Expand Up @@ -1997,6 +1998,7 @@ def _validate_custom_target_outputs(has_multi_in: bool, outputs: T.Iterable[str]
ENV_KW.evolve(since='0.57.0'),
INSTALL_KW,
INSTALL_MODE_KW.evolve(since='0.47.0'),
INSTALL_NAME_KW,
KwargInfo('feed', bool, default=False, since='0.59.0'),
KwargInfo('capture', bool, default=False),
KwargInfo('console', bool, default=False, since='0.48.0'),
Expand Down Expand Up @@ -2089,6 +2091,7 @@ def func_custom_target(self, node: mparser.FunctionNode, args: T.Tuple[str],
install=kwargs['install'],
install_dir=kwargs['install_dir'],
install_mode=install_mode,
install_name=kwargs['install_name'],
install_tag=kwargs['install_tag'],
backend=self.backend)
self.add_target(tg.name, tg)
Expand Down Expand Up @@ -2454,6 +2457,7 @@ def _warn_kwarg_install_mode_sticky(self, mode: FileMode) -> None:
INSTALL_MODE_KW.evolve(since='0.38.0'),
INSTALL_TAG_KW.evolve(since='0.60.0'),
INSTALL_DIR_KW,
INSTALL_NAME_KW,
PRESERVE_PATH_KW.evolve(since='0.64.0'),
)
def func_install_data(self, node: mparser.BaseNode,
Expand Down Expand Up @@ -2548,6 +2552,7 @@ def func_install_subdir(self, node: mparser.BaseNode, args: T.Tuple[str],
'configure_file',
DEPFILE_KW.evolve(since='0.52.0'),
INSTALL_MODE_KW.evolve(since='0.47.0,'),
INSTALL_NAME_KW,
INSTALL_TAG_KW.evolve(since='0.60.0'),
KwargInfo('capture', bool, default=False, since='0.41.0'),
KwargInfo(
Expand Down
7 changes: 7 additions & 0 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ def variables_convertor(contents: T.Union[str, T.List[str], T.Dict[str, str]]) -
convertor=_install_mode_convertor,
)

INSTALL_NAME_KW: KwargInfo[T.Optional[str]] = KwargInfo(
'install_name',
(str, NoneType),
default=None,
since='1.3.0',
)

REQUIRED_KW: KwargInfo[T.Union[bool, UserFeatureOption]] = KwargInfo(
'required',
(bool, UserFeatureOption),
Expand Down
14 changes: 10 additions & 4 deletions mesonbuild/minstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,10 @@ def do_copyfile(self, from_file: str, to_file: str,
dirmaker, outdir = makedirs
# Create dirs if needed
dirmaker.makedirs(outdir, exist_ok=True)
self.log(f'Installing {from_file} to {outdir}')
if os.path.basename(from_file) != os.path.basename(to_file):
self.log(f'Installing {from_file} to {to_file}')
else:
self.log(f'Installing {from_file} to {outdir}')
if os.path.islink(from_file):
if not os.path.exists(from_file):
# Dangling symlink. Replicate as is.
Expand Down Expand Up @@ -728,8 +731,11 @@ def install_targets(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix
file_copied = False # not set when a directory is copied
fname = check_for_stampfile(t.fname)
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))
install_fname = t.install_fname
if install_fname is None:
install_fname = os.path.basename(fname)
outname = os.path.join(outdir, install_fname)
final_path = os.path.join(d.prefix, t.outdir, install_fname)
should_strip = t.strip or (t.can_strip and self.options.strip)
install_rpath = t.install_rpath
install_name_mappings = t.install_name_mappings
Expand All @@ -752,7 +758,7 @@ def install_targets(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix
file_copied = self.do_copyfile(wasm_source, wasm_output)
elif os.path.isdir(fname):
fname = os.path.join(d.build_dir, fname.rstrip('/'))
outname = os.path.join(outdir, os.path.basename(fname))
outname = os.path.join(outdir, install_fname)
dm.makedirs(outdir, exist_ok=True)
self.do_copydir(d, fname, outname, None, install_mode, dm)
else:
Expand Down
Loading