Moved install data file generation to base class.
This commit is contained in:
parent
efba193872
commit
808d229c37
|
@ -23,7 +23,7 @@ import subprocess
|
|||
from ..mesonlib import MesonException, OrderedSet
|
||||
from ..mesonlib import classify_unity_sources
|
||||
from ..mesonlib import File
|
||||
from ..compilers import CompilerArgs
|
||||
from ..compilers import CompilerArgs, get_macos_dylib_install_name
|
||||
from collections import OrderedDict
|
||||
import shlex
|
||||
|
||||
|
@ -922,3 +922,222 @@ class Backend:
|
|||
for s in self.build.postconf_scripts:
|
||||
cmd = s['exe'] + s['args']
|
||||
subprocess.check_call(cmd, env=child_env)
|
||||
|
||||
def create_install_data_files(self):
|
||||
if self.environment.is_cross_build():
|
||||
bins = self.environment.cross_info.config['binaries']
|
||||
if 'strip' not in bins:
|
||||
mlog.warning('Cross file does not specify strip binary, result will not be stripped.')
|
||||
strip_bin = None
|
||||
else:
|
||||
strip_bin = mesonlib.stringlistify(bins['strip'])
|
||||
else:
|
||||
strip_bin = self.environment.native_strip_bin
|
||||
d = InstallData(self.environment.get_source_dir(),
|
||||
self.environment.get_build_dir(),
|
||||
self.environment.get_prefix(),
|
||||
strip_bin,
|
||||
self.environment.coredata.get_builtin_option('install_umask'),
|
||||
self.environment.get_build_command() + ['introspect'])
|
||||
self.generate_depmf_install(d)
|
||||
self.generate_target_install(d)
|
||||
self.generate_header_install(d)
|
||||
self.generate_man_install(d)
|
||||
self.generate_data_install(d)
|
||||
self.generate_custom_install_script(d)
|
||||
self.generate_subdir_install(d)
|
||||
return d
|
||||
|
||||
def get_target_install_dirs(self, t):
|
||||
# Find the installation directory.
|
||||
if isinstance(t, build.SharedModule):
|
||||
default_install_dir = self.environment.get_shared_module_dir()
|
||||
elif isinstance(t, build.SharedLibrary):
|
||||
default_install_dir = self.environment.get_shared_lib_dir()
|
||||
elif isinstance(t, build.StaticLibrary):
|
||||
default_install_dir = self.environment.get_static_lib_dir()
|
||||
elif isinstance(t, build.Executable):
|
||||
default_install_dir = self.environment.get_bindir()
|
||||
elif isinstance(t, build.CustomTarget):
|
||||
default_install_dir = None
|
||||
else:
|
||||
assert(isinstance(t, build.BuildTarget))
|
||||
# XXX: Add BuildTarget-specific install dir cases here
|
||||
default_install_dir = self.environment.get_libdir()
|
||||
outdirs = t.get_custom_install_dir()
|
||||
if outdirs[0] is not None and outdirs[0] != default_install_dir and outdirs[0] is not True:
|
||||
# Either the value is set to a non-default value, or is set to
|
||||
# False (which means we want this specific output out of many
|
||||
# outputs to not be installed).
|
||||
custom_install_dir = True
|
||||
else:
|
||||
custom_install_dir = False
|
||||
outdirs[0] = default_install_dir
|
||||
return outdirs, custom_install_dir
|
||||
|
||||
def get_target_link_deps_mappings(self, t, prefix):
|
||||
'''
|
||||
On macOS, we need to change the install names of all built libraries
|
||||
that a target depends on using install_name_tool so that the target
|
||||
continues to work after installation. For this, we need a dictionary
|
||||
mapping of the install_name value to the new one, so we can change them
|
||||
on install.
|
||||
'''
|
||||
result = {}
|
||||
if isinstance(t, build.StaticLibrary):
|
||||
return result
|
||||
for ld in t.get_all_link_deps():
|
||||
if ld is t or not isinstance(ld, build.SharedLibrary):
|
||||
continue
|
||||
old = get_macos_dylib_install_name(ld.prefix, ld.name, ld.suffix, ld.soversion)
|
||||
if old in result:
|
||||
continue
|
||||
fname = ld.get_filename()
|
||||
outdirs, _ = self.get_target_install_dirs(ld)
|
||||
new = os.path.join(prefix, outdirs[0], fname)
|
||||
result.update({old: new})
|
||||
return result
|
||||
|
||||
def generate_target_install(self, d):
|
||||
for t in self.build.get_targets().values():
|
||||
if not t.should_install():
|
||||
continue
|
||||
outdirs, custom_install_dir = self.get_target_install_dirs(t)
|
||||
# Sanity-check the outputs and install_dirs
|
||||
num_outdirs, num_out = len(outdirs), len(t.get_outputs())
|
||||
if num_outdirs != 1 and num_outdirs != num_out:
|
||||
m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \
|
||||
"Pass 'false' for outputs that should not be installed and 'true' for\n" \
|
||||
'using the default installation directory for an output.'
|
||||
raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs))
|
||||
install_mode = t.get_custom_install_mode()
|
||||
# Install the target output(s)
|
||||
if isinstance(t, build.BuildTarget):
|
||||
should_strip = self.get_option_for_target('strip', t)
|
||||
# Install primary build output (library/executable/jar, etc)
|
||||
# Done separately because of strip/aliases/rpath
|
||||
if outdirs[0] is not False:
|
||||
mappings = self.get_target_link_deps_mappings(t, d.prefix)
|
||||
i = TargetInstallData(self.get_target_filename(t), outdirs[0],
|
||||
t.get_aliases(), should_strip, mappings,
|
||||
t.install_rpath, install_mode)
|
||||
d.targets.append(i)
|
||||
# On toolchains/platforms that use an import library for
|
||||
# linking (separate from the shared library with all the
|
||||
# code), we need to install that too (dll.a/.lib).
|
||||
if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)) and t.get_import_filename():
|
||||
if custom_install_dir:
|
||||
# If the DLL is installed into a custom directory,
|
||||
# install the import library into the same place so
|
||||
# it doesn't go into a surprising place
|
||||
implib_install_dir = outdirs[0]
|
||||
else:
|
||||
implib_install_dir = self.environment.get_import_lib_dir()
|
||||
# Install the import library.
|
||||
i = TargetInstallData(self.get_target_filename_for_linking(t),
|
||||
implib_install_dir, {}, False, {}, '', install_mode)
|
||||
d.targets.append(i)
|
||||
# Install secondary outputs. Only used for Vala right now.
|
||||
if num_outdirs > 1:
|
||||
for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]):
|
||||
# User requested that we not install this output
|
||||
if outdir is False:
|
||||
continue
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
elif isinstance(t, build.CustomTarget):
|
||||
# If only one install_dir is specified, assume that all
|
||||
# outputs will be installed into it. This is for
|
||||
# backwards-compatibility and because it makes sense to
|
||||
# avoid repetition since this is a common use-case.
|
||||
#
|
||||
# To selectively install only some outputs, pass `false` as
|
||||
# the install_dir for the corresponding output by index
|
||||
if num_outdirs == 1 and num_out > 1:
|
||||
for output in t.get_outputs():
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
else:
|
||||
for output, outdir in zip(t.get_outputs(), outdirs):
|
||||
# User requested that we not install this output
|
||||
if outdir is False:
|
||||
continue
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
|
||||
def generate_custom_install_script(self, d):
|
||||
result = []
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for i in self.build.install_scripts:
|
||||
exe = i['exe']
|
||||
args = i['args']
|
||||
fixed_args = []
|
||||
for a in args:
|
||||
a = a.replace('@SOURCE_ROOT@', srcdir)
|
||||
a = a.replace('@BUILD_ROOT@', builddir)
|
||||
fixed_args.append(a)
|
||||
result.append(build.RunScript(exe, fixed_args))
|
||||
d.install_scripts = result
|
||||
|
||||
def generate_header_install(self, d):
|
||||
incroot = self.environment.get_includedir()
|
||||
headers = self.build.get_headers()
|
||||
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for h in headers:
|
||||
outdir = h.get_custom_install_dir()
|
||||
if outdir is None:
|
||||
outdir = os.path.join(incroot, h.get_install_subdir())
|
||||
for f in h.get_sources():
|
||||
if not isinstance(f, File):
|
||||
msg = 'Invalid header type {!r} can\'t be installed'
|
||||
raise MesonException(msg.format(f))
|
||||
abspath = f.absolute_path(srcdir, builddir)
|
||||
i = [abspath, outdir, h.get_custom_install_mode()]
|
||||
d.headers.append(i)
|
||||
|
||||
def generate_man_install(self, d):
|
||||
manroot = self.environment.get_mandir()
|
||||
man = self.build.get_man()
|
||||
for m in man:
|
||||
for f in m.get_sources():
|
||||
num = f.split('.')[-1]
|
||||
subdir = m.get_custom_install_dir()
|
||||
if subdir is None:
|
||||
subdir = os.path.join(manroot, 'man' + num)
|
||||
srcabs = f.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())
|
||||
dstabs = os.path.join(subdir, os.path.basename(f.fname) + '.gz')
|
||||
i = [srcabs, dstabs, m.get_custom_install_mode()]
|
||||
d.man.append(i)
|
||||
|
||||
def generate_data_install(self, d):
|
||||
data = self.build.get_data()
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for de in data:
|
||||
assert(isinstance(de, build.Data))
|
||||
subdir = de.install_dir
|
||||
if not subdir:
|
||||
subdir = os.path.join(self.environment.get_datadir(), self.interpreter.build.project_name)
|
||||
for src_file, dst_name in zip(de.sources, de.rename):
|
||||
assert(isinstance(src_file, mesonlib.File))
|
||||
dst_abs = os.path.join(subdir, dst_name)
|
||||
i = [src_file.absolute_path(srcdir, builddir), dst_abs, de.install_mode]
|
||||
d.data.append(i)
|
||||
|
||||
def generate_subdir_install(self, d):
|
||||
for sd in self.build.get_install_subdirs():
|
||||
src_dir = os.path.join(self.environment.get_source_dir(),
|
||||
sd.source_subdir,
|
||||
sd.installable_subdir).rstrip('/')
|
||||
dst_dir = os.path.join(self.environment.get_prefix(),
|
||||
sd.install_dir)
|
||||
if not sd.strip_directory:
|
||||
dst_dir = os.path.join(dst_dir, os.path.basename(src_dir))
|
||||
d.install_subdirs.append([src_dir, dst_dir, sd.install_mode,
|
||||
sd.exclude])
|
||||
|
|
|
@ -28,7 +28,7 @@ from .. import build
|
|||
from .. import mlog
|
||||
from .. import dependencies
|
||||
from .. import compilers
|
||||
from ..compilers import CompilerArgs, CCompiler, get_macos_dylib_install_name
|
||||
from ..compilers import CompilerArgs, CCompiler
|
||||
from ..linkers import ArLinker
|
||||
from ..mesonlib import File, MesonException, OrderedSet
|
||||
from ..mesonlib import get_compiler_for_source, has_path_sep
|
||||
|
@ -669,33 +669,13 @@ int dummy;
|
|||
|
||||
def generate_install(self, outfile):
|
||||
install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat')
|
||||
if self.environment.is_cross_build():
|
||||
bins = self.environment.cross_info.config['binaries']
|
||||
if 'strip' not in bins:
|
||||
mlog.warning('Cross file does not specify strip binary, result will not be stripped.')
|
||||
strip_bin = None
|
||||
else:
|
||||
strip_bin = mesonlib.stringlistify(bins['strip'])
|
||||
else:
|
||||
strip_bin = self.environment.native_strip_bin
|
||||
d = InstallData(self.environment.get_source_dir(),
|
||||
self.environment.get_build_dir(),
|
||||
self.environment.get_prefix(),
|
||||
strip_bin,
|
||||
self.environment.coredata.get_builtin_option('install_umask'),
|
||||
self.environment.get_build_command() + ['introspect'])
|
||||
|
||||
d = self.create_install_data_files()
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_dep('all')
|
||||
elem.add_item('DESC', 'Installing files.')
|
||||
elem.add_item('COMMAND', self.environment.get_build_command() + ['install', '--no-rebuild'])
|
||||
elem.add_item('pool', 'console')
|
||||
self.generate_depmf_install(d)
|
||||
self.generate_target_install(d)
|
||||
self.generate_header_install(d)
|
||||
self.generate_man_install(d)
|
||||
self.generate_data_install(d)
|
||||
self.generate_custom_install_script(d)
|
||||
self.generate_subdir_install(d)
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-install', outfile)
|
||||
|
@ -703,200 +683,6 @@ int dummy;
|
|||
with open(install_data_file, 'wb') as ofile:
|
||||
pickle.dump(d, ofile)
|
||||
|
||||
def get_target_install_dirs(self, t):
|
||||
# Find the installation directory.
|
||||
if isinstance(t, build.SharedModule):
|
||||
default_install_dir = self.environment.get_shared_module_dir()
|
||||
elif isinstance(t, build.SharedLibrary):
|
||||
default_install_dir = self.environment.get_shared_lib_dir()
|
||||
elif isinstance(t, build.StaticLibrary):
|
||||
default_install_dir = self.environment.get_static_lib_dir()
|
||||
elif isinstance(t, build.Executable):
|
||||
default_install_dir = self.environment.get_bindir()
|
||||
elif isinstance(t, build.CustomTarget):
|
||||
default_install_dir = None
|
||||
else:
|
||||
assert(isinstance(t, build.BuildTarget))
|
||||
# XXX: Add BuildTarget-specific install dir cases here
|
||||
default_install_dir = self.environment.get_libdir()
|
||||
outdirs = t.get_custom_install_dir()
|
||||
if outdirs[0] is not None and outdirs[0] != default_install_dir and outdirs[0] is not True:
|
||||
# Either the value is set to a non-default value, or is set to
|
||||
# False (which means we want this specific output out of many
|
||||
# outputs to not be installed).
|
||||
custom_install_dir = True
|
||||
else:
|
||||
custom_install_dir = False
|
||||
outdirs[0] = default_install_dir
|
||||
return outdirs, custom_install_dir
|
||||
|
||||
def get_target_link_deps_mappings(self, t, prefix):
|
||||
'''
|
||||
On macOS, we need to change the install names of all built libraries
|
||||
that a target depends on using install_name_tool so that the target
|
||||
continues to work after installation. For this, we need a dictionary
|
||||
mapping of the install_name value to the new one, so we can change them
|
||||
on install.
|
||||
'''
|
||||
result = {}
|
||||
if isinstance(t, build.StaticLibrary):
|
||||
return result
|
||||
for ld in t.get_all_link_deps():
|
||||
if ld is t or not isinstance(ld, build.SharedLibrary):
|
||||
continue
|
||||
old = get_macos_dylib_install_name(ld.prefix, ld.name, ld.suffix, ld.soversion)
|
||||
if old in result:
|
||||
continue
|
||||
fname = ld.get_filename()
|
||||
outdirs, _ = self.get_target_install_dirs(ld)
|
||||
new = os.path.join(prefix, outdirs[0], fname)
|
||||
result.update({old: new})
|
||||
return result
|
||||
|
||||
def generate_target_install(self, d):
|
||||
for t in self.build.get_targets().values():
|
||||
if not t.should_install():
|
||||
continue
|
||||
outdirs, custom_install_dir = self.get_target_install_dirs(t)
|
||||
# Sanity-check the outputs and install_dirs
|
||||
num_outdirs, num_out = len(outdirs), len(t.get_outputs())
|
||||
if num_outdirs != 1 and num_outdirs != num_out:
|
||||
m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \
|
||||
"Pass 'false' for outputs that should not be installed and 'true' for\n" \
|
||||
'using the default installation directory for an output.'
|
||||
raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs))
|
||||
install_mode = t.get_custom_install_mode()
|
||||
# Install the target output(s)
|
||||
if isinstance(t, build.BuildTarget):
|
||||
should_strip = self.get_option_for_target('strip', t)
|
||||
# Install primary build output (library/executable/jar, etc)
|
||||
# Done separately because of strip/aliases/rpath
|
||||
if outdirs[0] is not False:
|
||||
mappings = self.get_target_link_deps_mappings(t, d.prefix)
|
||||
i = TargetInstallData(self.get_target_filename(t), outdirs[0],
|
||||
t.get_aliases(), should_strip, mappings,
|
||||
t.install_rpath, install_mode)
|
||||
d.targets.append(i)
|
||||
# On toolchains/platforms that use an import library for
|
||||
# linking (separate from the shared library with all the
|
||||
# code), we need to install that too (dll.a/.lib).
|
||||
if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)) and t.get_import_filename():
|
||||
if custom_install_dir:
|
||||
# If the DLL is installed into a custom directory,
|
||||
# install the import library into the same place so
|
||||
# it doesn't go into a surprising place
|
||||
implib_install_dir = outdirs[0]
|
||||
else:
|
||||
implib_install_dir = self.environment.get_import_lib_dir()
|
||||
# Install the import library.
|
||||
i = TargetInstallData(self.get_target_filename_for_linking(t),
|
||||
implib_install_dir, {}, False, {}, '', install_mode)
|
||||
d.targets.append(i)
|
||||
# Install secondary outputs. Only used for Vala right now.
|
||||
if num_outdirs > 1:
|
||||
for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]):
|
||||
# User requested that we not install this output
|
||||
if outdir is False:
|
||||
continue
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
elif isinstance(t, build.CustomTarget):
|
||||
# If only one install_dir is specified, assume that all
|
||||
# outputs will be installed into it. This is for
|
||||
# backwards-compatibility and because it makes sense to
|
||||
# avoid repetition since this is a common use-case.
|
||||
#
|
||||
# To selectively install only some outputs, pass `false` as
|
||||
# the install_dir for the corresponding output by index
|
||||
if num_outdirs == 1 and num_out > 1:
|
||||
for output in t.get_outputs():
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
else:
|
||||
for output, outdir in zip(t.get_outputs(), outdirs):
|
||||
# User requested that we not install this output
|
||||
if outdir is False:
|
||||
continue
|
||||
f = os.path.join(self.get_target_dir(t), output)
|
||||
i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
|
||||
d.targets.append(i)
|
||||
|
||||
def generate_custom_install_script(self, d):
|
||||
result = []
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for i in self.build.install_scripts:
|
||||
exe = i['exe']
|
||||
args = i['args']
|
||||
fixed_args = []
|
||||
for a in args:
|
||||
a = a.replace('@SOURCE_ROOT@', srcdir)
|
||||
a = a.replace('@BUILD_ROOT@', builddir)
|
||||
fixed_args.append(a)
|
||||
result.append(build.RunScript(exe, fixed_args))
|
||||
d.install_scripts = result
|
||||
|
||||
def generate_header_install(self, d):
|
||||
incroot = self.environment.get_includedir()
|
||||
headers = self.build.get_headers()
|
||||
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for h in headers:
|
||||
outdir = h.get_custom_install_dir()
|
||||
if outdir is None:
|
||||
outdir = os.path.join(incroot, h.get_install_subdir())
|
||||
for f in h.get_sources():
|
||||
if not isinstance(f, File):
|
||||
msg = 'Invalid header type {!r} can\'t be installed'
|
||||
raise MesonException(msg.format(f))
|
||||
abspath = f.absolute_path(srcdir, builddir)
|
||||
i = [abspath, outdir, h.get_custom_install_mode()]
|
||||
d.headers.append(i)
|
||||
|
||||
def generate_man_install(self, d):
|
||||
manroot = self.environment.get_mandir()
|
||||
man = self.build.get_man()
|
||||
for m in man:
|
||||
for f in m.get_sources():
|
||||
num = f.split('.')[-1]
|
||||
subdir = m.get_custom_install_dir()
|
||||
if subdir is None:
|
||||
subdir = os.path.join(manroot, 'man' + num)
|
||||
srcabs = f.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())
|
||||
dstabs = os.path.join(subdir, os.path.basename(f.fname) + '.gz')
|
||||
i = [srcabs, dstabs, m.get_custom_install_mode()]
|
||||
d.man.append(i)
|
||||
|
||||
def generate_data_install(self, d):
|
||||
data = self.build.get_data()
|
||||
srcdir = self.environment.get_source_dir()
|
||||
builddir = self.environment.get_build_dir()
|
||||
for de in data:
|
||||
assert(isinstance(de, build.Data))
|
||||
subdir = de.install_dir
|
||||
if not subdir:
|
||||
subdir = os.path.join(self.environment.get_datadir(), self.interpreter.build.project_name)
|
||||
for src_file, dst_name in zip(de.sources, de.rename):
|
||||
assert(isinstance(src_file, mesonlib.File))
|
||||
dst_abs = os.path.join(subdir, dst_name)
|
||||
i = [src_file.absolute_path(srcdir, builddir), dst_abs, de.install_mode]
|
||||
d.data.append(i)
|
||||
|
||||
def generate_subdir_install(self, d):
|
||||
for sd in self.build.get_install_subdirs():
|
||||
src_dir = os.path.join(self.environment.get_source_dir(),
|
||||
sd.source_subdir,
|
||||
sd.installable_subdir).rstrip('/')
|
||||
dst_dir = os.path.join(self.environment.get_prefix(),
|
||||
sd.install_dir)
|
||||
if not sd.strip_directory:
|
||||
dst_dir = os.path.join(dst_dir, os.path.basename(src_dir))
|
||||
d.install_subdirs.append([src_dir, dst_dir, sd.install_mode,
|
||||
sd.exclude])
|
||||
|
||||
def generate_tests(self, outfile):
|
||||
self.serialize_tests()
|
||||
cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild']
|
||||
|
|
Loading…
Reference in New Issue