diff --git a/easybuild/easyblocks/generic/mesonninja.py b/easybuild/easyblocks/generic/mesonninja.py index e31e4cc4397..0c178139c65 100644 --- a/easybuild/easyblocks/generic/mesonninja.py +++ b/easybuild/easyblocks/generic/mesonninja.py @@ -30,7 +30,7 @@ from easybuild.tools import LooseVersion from easybuild.framework.easyblock import EasyBlock -from easybuild.framework.easyconfig import CUSTOM +from easybuild.framework.easyconfig import BUILD, CUSTOM from easybuild.tools.build_log import EasyBuildError from easybuild.tools.filetools import change_dir, create_unused_dir, which from easybuild.tools.modules import get_software_version @@ -38,6 +38,7 @@ DEFAULT_CONFIGURE_CMD = 'meson' DEFAULT_BUILD_CMD = 'ninja' +DEFAULT_TEST_CMD = 'meson' DEFAULT_INSTALL_CMD = 'ninja' @@ -59,7 +60,9 @@ def extra_options(extra_vars=None): "This disabled costly asserts in code, typical for production.", CUSTOM], 'configure_cmd': [DEFAULT_CONFIGURE_CMD, "Configure command to use", CUSTOM], 'install_cmd': [DEFAULT_INSTALL_CMD, "Install command to use", CUSTOM], + 'runtest': [None, "Meson target to test build, or True to use 'meson test'", BUILD], 'separate_build_dir': [True, "Perform build in a separate directory", CUSTOM], + 'test_cmd': [DEFAULT_TEST_CMD, "Test command to use ('runtest' value is appended)", CUSTOM], }) return extra_vars @@ -149,13 +152,45 @@ def build_step(self, *args, **kwargs): def test_step(self): """ - Run tests using Ninja. + Run tests using Meson. """ - if self.cfg['runtest']: - cmd = "%s %s %s" % (self.cfg['pretestopts'], self.cfg['runtest'], self.cfg['testopts']) + runtest = self.cfg['runtest'] + + if runtest: + # Essentially runtest = True. Use the default behavior. + if isinstance(runtest, bool): + test_cmd = self.cfg.get('test_cmd') or DEFAULT_TEST_CMD + + # Run tests as recommended in https://mesonbuild.com/Unit-tests.html#testing-tool + if test_cmd == DEFAULT_TEST_CMD: + runtest = 'test' + # User has defined the test_cmd. Adding test by default here might cause trouble, hence omit. + else: + runtest = '' + # EasyConfig defined the test command to be executed via runtest + else: + test_cmd = '' + + full_test_cmd = ' '.join([x for x in (test_cmd, runtest, self.cfg['testopts']) if x]) + # Make sure Meson does not use more resources than we want. + # From the documentation: + # By default Meson uses as many concurrent processes as there are cores on the test machine. + if self.cfg.parallel >= 1 and 'meson' in full_test_cmd: + if 'MESON_TESTTHREADS' not in self.cfg['pretestopts']: + self.cfg.update('pretestopts', f" export MESON_TESTTHREADS={self.cfg.parallel} && ") + # Preferred way to set parallelism since Meson v1.7.0, but does not hurt to set both. + if 'MESON_NUM_PROCESSES' not in self.cfg['pretestopts']: + self.cfg.update('pretestopts', f" export MESON_NUM_PROCESSES={self.cfg.parallel} && ") + + # Compose command filtering out empty values + cmd = ' '.join([x for x in (self.cfg['pretestopts'], full_test_cmd) if x]) res = run_shell_cmd(cmd) + return res.output + # No test executed, hence no output to return + return '' + def install_step(self): """ Install with 'ninja install'.