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

update MXNet easyblock + don't try to install R extension by default for MXNet >= 1.0 #2955

Merged
merged 10 commits into from
Aug 17, 2023
67 changes: 55 additions & 12 deletions easybuild/easyblocks/m/mxnet.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
##
# Copyright 2018 Free University of Brussels (VUB)
# Copyright 2018-2023 Free University of Brussels (VUB)
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
Expand Down Expand Up @@ -32,6 +32,7 @@
import shutil
from distutils.version import LooseVersion

import easybuild.tools.environment as env
from easybuild.easyblocks.generic.makecp import MakeCp
from easybuild.easyblocks.generic.pythonpackage import PythonPackage
from easybuild.easyblocks.generic.rpackage import RPackage
Expand Down Expand Up @@ -63,11 +64,15 @@ class EB_MXNet(MakeCp):
"""Easyblock to build and install MXNet"""

@staticmethod
def extra_options(extra_vars=None):
def extra_options():
"""Change default values of options"""
extra = MakeCp.extra_options()
extra_vars = {
'install_r_ext': [None, "Enable installation of R extensions", CUSTOM],
}
extra = MakeCp.extra_options(extra_vars)
# files_to_copy is not mandatory here
extra['files_to_copy'][2] = CUSTOM

return extra

def __init__(self, *args, **kwargs):
Expand All @@ -79,6 +84,13 @@ def __init__(self, *args, **kwargs):
self.py_ext.module_generator = self.module_generator
self.r_ext = RPackage(self, {'name': self.name, 'version': self.version})
self.r_ext.module_generator = self.module_generator
# auto-enable building of R extensions only for old versions of MXNet (< 1.0),
# since for newer versions is broken
if self.cfg['install_r_ext'] is None:
if LooseVersion(self.version) < LooseVersion('1.0'):
self.cfg['install_r_ext'] = True
else:
self.cfg['install_r_ext'] = False

def extract_step(self):
"""
Expand All @@ -97,20 +109,36 @@ def extract_step(self):

for srcdir in [d for d in os.listdir(self.builddir) if d != os.path.basename(self.mxnet_src_dir)]:
submodule, _, _ = srcdir.rpartition('-')
newdir = os.path.join(self.mxnet_src_dir, submodule)
olddir = os.path.join(self.builddir, srcdir)

if LooseVersion(self.version) >= LooseVersion('1.0'):
# if newdir starts with 'oneDNN-', we rename it to mkldnn:
if submodule == 'oneDNN':
submodule = 'mkldnn'
# rename the file to 'mkldnn':
old_srcdir = srcdir
srcdir = srcdir.replace('oneDNN', 'mkldnn')
os.rename(os.path.join(self.builddir, old_srcdir), os.path.join(self.builddir, srcdir))

olddir = os.path.join(self.builddir, srcdir)
newdir = os.path.join(self.mxnet_src_dir, '3rdparty', submodule)
else:
olddir = os.path.join(self.builddir, srcdir)
newdir = os.path.join(self.mxnet_src_dir, submodule)

# first remove empty existing directory
remove_dir(newdir)

try:
shutil.move(olddir, newdir)
except IOError as err:
raise EasyBuildError("Failed to move %s to %s: %s", olddir, newdir, err)

# the nnvm submodules has dmlc-core as a submodule too. Let's put a symlink in place.
newdir = os.path.join(self.mxnet_src_dir, "nnvm", "dmlc-core")
olddir = os.path.join(self.mxnet_src_dir, "dmlc-core")
remove_dir(newdir)
symlink(olddir, newdir)
if LooseVersion(self.version) < LooseVersion('1.0'):
# the nnvm submodules has dmlc-core as a submodule too. Let's put a symlink in place.
newdir = os.path.join(self.mxnet_src_dir, "nnvm", "dmlc-core")
olddir = os.path.join(self.mxnet_src_dir, "dmlc-core")
remove_dir(newdir)
symlink(olddir, newdir)

def prepare_step(self, *args, **kwargs):
"""Prepare for building and installing MXNet."""
Expand All @@ -133,6 +161,9 @@ def configure_step(self):
blas = "atlas"
elif toolchain_blas == 'OpenBLAS':
blas = "openblas"
elif toolchain_blas == 'FlexiBLAS':
blas = "flexiblas"
env.setvar('CFLAGS', "%s -lflexiblas" % os.getenv('CFLAGS'))
elif toolchain_blas is None:
raise EasyBuildError("No BLAS library found in the toolchain")

Expand All @@ -145,8 +176,9 @@ def configure_step(self):

def install_step(self):
"""Specify list of files to copy"""
self.cfg['files_to_copy'] = ['bin', 'include', 'lib',
(['dmlc-core/include/dmlc', 'nnvm/include/nnvm'], 'include')]
self.cfg['files_to_copy'] = ['bin', 'include', 'lib']
if LooseVersion(self.version) < LooseVersion('1.0'):
self.cfg.update('files_to_copy', [(['dmlc-core/include/dmlc', 'nnvm/include/nnvm'], 'include')])
super(EB_MXNet, self).install_step()

def extensions_step(self):
Expand All @@ -159,6 +191,17 @@ def extensions_step(self):
self.py_ext.run(unpack_src=False)
self.py_ext.postrun()

if self.cfg['install_r_ext']:
# This is off by default, because it's been working in the old version of MXNet and now it's not.
# Also, from the website of MXNet, Python bindings seem to be the preferred ones so we'll focus on that.
self.install_r_ext()
else:
self.log.info("Skipping R extension installation")

def install_r_ext(self):
"""
Also install R extension for MXNet.
"""
# next up, the R bindings
self.r_ext.src = os.path.join(self.mxnet_src_dir, "R-package")
change_dir(self.r_ext.src)
Expand Down