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

improve Bazel easyblock: add support for running tests, enable static linking, use build dir rather than tmpdir, verbose output #2285

Merged
Merged
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
70 changes: 69 additions & 1 deletion easybuild/easyblocks/b/bazel.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,29 @@
from distutils.version import LooseVersion
import glob
import os
import tempfile

import easybuild.tools.environment as env
from easybuild.framework.easyblock import EasyBlock
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import apply_regex_substitutions, copy_file, which
from easybuild.tools.modules import get_software_root, get_software_version
from easybuild.tools.run import run_cmd
from easybuild.framework.easyconfig import CUSTOM


class EB_Bazel(EasyBlock):
"""Support for building/installing Bazel."""

@staticmethod
def extra_options():
"""Extra easyconfig parameters specific to EB_Bazel."""
extra_vars = {
'static': [None, 'Build statically linked executables ' +
'(default: True for Bazel >= 1.0 else False)', CUSTOM],
}
return EasyBlock.extra_options(extra_vars)

def fixup_hardcoded_paths(self):
"""Patch out hard coded paths to compiler and binutils tools"""
binutils_root = get_software_root('binutils')
Expand Down Expand Up @@ -96,13 +107,31 @@ def fixup_hardcoded_paths(self):

apply_regex_substitutions(os.path.join('tools', 'cpp', 'CROSSTOOL'), regex_subs)

def prepare_step(self, *args, **kwargs):
"""Setup bazel output root"""
super(EB_Bazel, self).prepare_step(*args, **kwargs)
self.bazel_tmp_dir = tempfile.mkdtemp(suffix='-bazel-tmp', dir=self.builddir)
self.output_user_root = tempfile.mkdtemp(suffix='-bazel-root', dir=self.builddir)

def extract_step(self):
"""Extract Bazel sources."""
# Older Bazel won't build when the output_user_root is a subfolder of the source folder
# So create a dedicated source folder
self.cfg.update('unpack_options', '-d src')
super(EB_Bazel, self).extract_step()

def configure_step(self):
"""Custom configuration procedure for Bazel."""

# Last instance of hardcoded paths was removed in 0.24.0
if LooseVersion(self.version) < LooseVersion('0.24.0'):
self.fixup_hardcoded_paths()

# Keep temporary directory in case of error. EB will clean it up on success
apply_regex_substitutions(os.path.join('scripts', 'bootstrap', 'buildenv.sh'), [
(r'atexit cleanup_tempdir_.*', '')
])

# enable building in parallel
bazel_args = '--jobs=%d' % self.cfg['parallel']

Expand All @@ -112,13 +141,52 @@ def configure_step(self):
# See https://github.com/bazelbuild/bazel/issues/10377
bazel_args += ' --host_javabase=@local_jdk//:jdk'

# Link C++ libs statically, see https://github.com/bazelbuild/bazel/issues/4137
static = self.cfg['static']
if static is None:
# Works for Bazel 1.x and higher
static = LooseVersion(self.version) >= LooseVersion('1.0.0')
if static:
env.setvar('BAZEL_LINKOPTS', '-static-libstdc++:-static-libgcc')
env.setvar('BAZEL_LINKLIBS', '-l%:libstdc++.a')

env.setvar('EXTRA_BAZEL_ARGS', bazel_args)
env.setvar('EMBED_LABEL', self.version)
env.setvar('VERBOSE', 'yes')

def build_step(self):
"""Custom build procedure for Bazel."""
cmd = '%s ./compile.sh' % self.cfg['prebuildopts']
cmd = ' '.join([
"export TMPDIR='%s' &&" % self.bazel_tmp_dir, # The initial bootstrap of bazel is done in TMPDIR
self.cfg['prebuildopts'],
Flamefire marked this conversation as resolved.
Show resolved Hide resolved
"bash -c 'set -x && ./compile.sh'", # Show the commands the script is running to faster debug failures
])
run_cmd(cmd, log_all=True, simple=True, log_ok=True)

def test_step(self):
"""Test the compilation"""

runtest = self.cfg['runtest']
if runtest:
# This could be used to pass options to Bazel: runtest = '--bazel-opt=foo test'
if runtest is True:
runtest = 'test'
lexming marked this conversation as resolved.
Show resolved Hide resolved
cmd = " ".join([
self.cfg['pretestopts'],
os.path.join('output', 'bazel'),
# Avoid bazel using $HOME
'--output_user_root=%s' % self.output_user_root,
runtest,
'--jobs=%d' % self.cfg['parallel'],
'--host_javabase=@local_jdk//:jdk',
# Be more verbose
'--subcommands', '--verbose_failures',
# Just build tests
'--build_tests_only',
self.cfg['testopts']
])
run_cmd(cmd, log_all=True, simple=True)

def install_step(self):
"""Custom install procedure for Bazel."""
copy_file(os.path.join('output', 'bazel'), os.path.join(self.installdir, 'bin', 'bazel'))
Expand Down