# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import inspect
import os
from typing import List # novm
from llnl.util.filesystem import working_dir
from spack.directives import depends_on, variant
from spack.package import PackageBase, run_after
[docs]class MesonPackage(PackageBase):
"""Specialized class for packages built using Meson
For more information on the Meson build system, see:
https://mesonbuild.com/
This class provides three phases that can be overridden:
1. :py:meth:`~.MesonPackage.meson`
2. :py:meth:`~.MesonPackage.build`
3. :py:meth:`~.MesonPackage.install`
They all have sensible defaults and for many packages the only thing
necessary will be to override :py:meth:`~.MesonPackage.meson_args`.
For a finer tuning you may also override:
+-----------------------------------------------+--------------------+
| **Method** | **Purpose** |
+===============================================+====================+
| :py:meth:`~.MesonPackage.root_mesonlists_dir` | Location of the |
| | root MesonLists.txt|
+-----------------------------------------------+--------------------+
| :py:meth:`~.MesonPackage.build_directory` | Directory where to |
| | build the package |
+-----------------------------------------------+--------------------+
"""
#: Phases of a Meson package
phases = ['meson', 'build', 'install']
#: This attribute is used in UI queries that need to know the build
#: system base class
build_system_class = 'MesonPackage'
build_targets = [] # type: List[str]
install_targets = ['install']
build_time_test_callbacks = ['check']
variant('buildtype', default='debugoptimized',
description='Meson build type',
values=('plain', 'debug', 'debugoptimized', 'release', 'minsize'))
variant('default_library', default='shared', values=('shared', 'static'),
multi=True, description='Build shared libs, static libs or both')
variant('strip', default=False, description='Strip targets on install')
depends_on('meson', type='build')
depends_on('ninja', type='build')
@property
def archive_files(self):
"""Files to archive for packages based on Meson"""
return [os.path.join(self.build_directory, 'meson-logs/meson-log.txt')]
@property
def root_mesonlists_dir(self):
"""The relative path to the directory containing meson.build
This path is relative to the root of the extracted tarball,
not to the ``build_directory``. Defaults to the current directory.
:return: directory containing meson.build
"""
return self.stage.source_path
@property
def std_meson_args(self):
"""Standard meson arguments provided as a property for
convenience of package writers
:return: standard meson arguments
"""
# standard Meson arguments
std_meson_args = MesonPackage._std_args(self)
std_meson_args += getattr(self, 'meson_flag_args', [])
return std_meson_args
@staticmethod
def _std_args(pkg):
"""Computes the standard meson arguments for a generic package"""
try:
build_type = pkg.spec.variants['buildtype'].value
except KeyError:
build_type = 'release'
strip = 'true' if '+strip' in pkg.spec else 'false'
if 'default_library=static,shared' in pkg.spec:
default_library = 'both'
elif 'default_library=static' in pkg.spec:
default_library = 'static'
else:
default_library = 'shared'
args = [
'--prefix={0}'.format(pkg.prefix),
# If we do not specify libdir explicitly, Meson chooses something
# like lib/x86_64-linux-gnu, which causes problems when trying to
# find libraries and pkg-config files.
# See https://github.com/mesonbuild/meson/issues/2197
'--libdir={0}'.format(pkg.prefix.lib),
'-Dbuildtype={0}'.format(build_type),
'-Dstrip={0}'.format(strip),
'-Ddefault_library={0}'.format(default_library)
]
return args
[docs] def flags_to_build_system_args(self, flags):
"""Produces a list of all command line arguments to pass the specified
compiler flags to meson."""
# Has to be dynamic attribute due to caching
setattr(self, 'meson_flag_args', [])
@property
def build_directory(self):
"""Returns the directory to use when building the package
:return: directory where to build the package
"""
return os.path.join(self.stage.source_path, 'spack-build')
[docs] def meson_args(self):
"""Produces a list containing all the arguments that must be passed to
meson, except:
* ``--prefix``
* ``--libdir``
* ``--buildtype``
* ``--strip``
* ``--default_library``
which will be set automatically.
:return: list of arguments for meson
"""
return []
[docs] def meson(self, spec, prefix):
"""Runs ``meson`` in the build directory"""
options = [os.path.abspath(self.root_mesonlists_dir)]
options += self.std_meson_args
options += self.meson_args()
with working_dir(self.build_directory, create=True):
inspect.getmodule(self).meson(*options)
[docs] def build(self, spec, prefix):
"""Make the build targets"""
options = ['-v']
options += self.build_targets
with working_dir(self.build_directory):
inspect.getmodule(self).ninja(*options)
[docs] def install(self, spec, prefix):
"""Make the install targets"""
with working_dir(self.build_directory):
inspect.getmodule(self).ninja(*self.install_targets)
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
[docs] def check(self):
"""Searches the Meson-generated file for the target ``test``
and runs it if found.
"""
with working_dir(self.build_directory):
self._if_ninja_target_execute('test')
self._if_ninja_target_execute('check')
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)