Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
24 changes: 20 additions & 4 deletions easybuild/tools/toolchain/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ def is_rpath_wrapper(path):
calls_rpath_args = b'rpath_args.py $CMD' in read_file(path, mode='rb')
return in_rpath_wrappers_dir and calls_rpath_args

def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None):
def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None, new_wrapper_dir=None, disable_wrapper_log=False, cmdDir=None):
"""
Put RPATH wrapper script in place for compiler and linker commands

Expand All @@ -967,7 +967,12 @@ def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None
rpath_filter_dirs.append(lib_stubs_pattern)

# directory where all wrappers will be placed
wrappers_dir = os.path.join(tempfile.mkdtemp(), RPATH_WRAPPERS_SUBDIR)
if new_wrapper_dir is None:
wrappers_dir = os.path.join(tempfile.mkdtemp(), RPATH_WRAPPERS_SUBDIR)
else:
wrappers_dir = new_wrapper_dir
if not os.path.exists(wrappers_dir):
os.mkdir(wrappers_dir)

# must also wrap compilers commands, required e.g. for Clang ('gcc' on OS X)?
c_comps, fortran_comps = self.compilers()
Expand All @@ -989,6 +994,15 @@ def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None
# create wrappers
for cmd in nub(c_comps + fortran_comps + ['ld', 'ld.gold', 'ld.bfd']):
orig_cmd = which(cmd)
if cmdDir is not None and os.path.exists(cmdDir):
orig_cmd = os.path.join(cmdDir,cmd)

# TODO: dirty hack to let module-shipped rpath wrappers point to EESSI software layer's ld
if cmdDir is not None and "ld" in cmd:
orig_cmd = which(cmd, retain_all=True)
orig_cmd = [a for a in orig_cmd if "/tmp" not in a][0]

self.log.debug("orig_cmd: %s", orig_cmd)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section is a bit critical.
The original prepare_rpath_wrappers is using which to lookup ld and compiler commands to wrap with the newly created rpath wrapper.
But we want to wrap the compiler command of the e.g. GCCcore module that currently is build! So we cannot look it up in PATH and instead have to pass a new cmdDir to the function and decide to set it manually.
This might be a first good reason to split this function into two.

Second, in EESSI we ship ld in the software layer on CVMFS. We don't want to pick up any ld commands that exist in the current /tmp locations. They are still around during module building, so we have to put a dirty hack here.
I don't really like putting an EESSI special case into EasyBuild code.
Do we have a general approach to this kind of problem?
Maybe this calls for another manual path, from where to pick up ld?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused which usage of prepare_rpath_wrappers you're trying to target here with the exception for ld: the usage by EasyBuild when installing with --rpath? Or is it to prevent the ld wrappers from being installed for EESSI? In the latter case, I'd say we should indeed make the ld wrapper installation part of binutils (as was suggested in easybuilders/easybuild-easyblocks#2638). That means --filter-deps binutils is enough to (also) make sure the RPATH wrappers aren't installed (and I guess we filter binutils already in EESSI? Can't remember exactly...).

If it's more about EasyBuild when installing with --rpath (i.e. you're afraid that this will pick up the ld wrappers from the tempdir that EasyBuild creates), I'd have to think how to elegantly solve this. I agree with the statement that we don't want special case things for EESSI in the EasyBuild source code, it should be something generic.

I'm generally a bit confused what we do currently in EESSI: do we set RPATH with our own ld wrapper? Or do we rely on EasyBuild to set RPATH? I thought it was the latter, but then you'd still want it to generate wrappers when installing with --rpath, right?


if orig_cmd:
# bail out early if command already is a wrapped;
Expand All @@ -1011,7 +1025,7 @@ def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None
raise EasyBuildError("Refusing the create a fork bomb, which(%s) == %s", cmd, orig_cmd)

# enable debug mode in wrapper script by specifying location for log file
if build_option('debug'):
if build_option('debug') and not disable_wrapper_log:
rpath_wrapper_log = os.path.join(tempfile.gettempdir(), 'rpath_wrapper_%s.log' % cmd)
else:
rpath_wrapper_log = '/dev/null'
Expand All @@ -1027,7 +1041,7 @@ def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None
'wrapper_dir': wrapper_dir,
}
write_file(cmd_wrapper, cmd_wrapper_txt)
adjust_permissions(cmd_wrapper, stat.S_IXUSR)
adjust_permissions(cmd_wrapper, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)

# prepend location to this wrapper to $PATH
setvar('PATH', '%s:%s' % (wrapper_dir, os.getenv('PATH')))
Expand All @@ -1036,6 +1050,8 @@ def prepare_rpath_wrappers(self, rpath_filter_dirs=None, rpath_include_dirs=None
else:
self.log.debug("Not installing RPATH wrapper for non-existing command '%s'", cmd)

return wrappers_dir

def handle_sysroot(self):
"""
Extra stuff to be done when alternate system root is specified via --sysroot EasyBuild configuration option.
Expand Down
14 changes: 14 additions & 0 deletions easybuild/tools/toolchain/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import copy
import re
import sys
import os

import easybuild.tools.toolchain
from easybuild.base import fancylogger
Expand Down Expand Up @@ -148,3 +149,16 @@ def get_toolchain(tc, tcopts, mns=None, tcdeps=None, modtool=None):
tc_inst.set_options(tcopts)

return tc_inst


def create_rpath_wrappers(targetdir, toolchain_name, toolchain_version, rpath_filter_dirs=[], rpath_include_dirs=[]):
tc = get_toolchain({'name': toolchain_name, 'version': toolchain_version}, {})

wrapperpath = tc.prepare_rpath_wrappers(
rpath_filter_dirs=rpath_filter_dirs,
rpath_include_dirs=rpath_include_dirs,
new_wrapper_dir=targetdir,
disable_wrapper_log=True,
cmdDir=os.path.join(targetdir, '..')
)
_log.debug("Installed RPATH wrappers in %s" % (str(wrapperpath)))