@@ -212,6 +212,7 @@ def __init__(self, ec, hooks=None):
212212
213213 # keep track of initial environment we start in, so we can restore it if needed
214214 self .initial_environ = copy .deepcopy (os .environ )
215+ self .tweaked_env_vars = {}
215216
216217 # should we keep quiet?
217218 self .silent = build_option ('silent' )
@@ -1282,7 +1283,14 @@ def load_module(self, mod_paths=None, purge=True):
12821283 if self .mod_subdir and self .toolchain .name != DUMMY_TOOLCHAIN_NAME :
12831284 mods .insert (0 , self .toolchain .det_short_module_name ())
12841285
1286+ # pass initial environment, to use it for resetting the environment before loading the modules
12851287 self .modules_tool .load (mods , mod_paths = all_mod_paths , purge = purge , init_env = self .initial_environ )
1288+
1289+ # handle environment variables that need to be updated after loading modules
1290+ for var , val in sorted (self .tweaked_env_vars .items ()):
1291+ self .log .info ("Tweaking $%s: %s" , var , val )
1292+ env .setvar (var , val )
1293+
12861294 else :
12871295 self .log .warning ("Not loading module, since self.full_mod_name is not set." )
12881296
@@ -1297,7 +1305,7 @@ def load_fake_module(self, purge=False):
12971305 fake_mod_path = self .make_module_step (fake = True )
12981306
12991307 # load fake module
1300- self .modules_tool .prepend_module_path (os .path .join (fake_mod_path , self .mod_subdir ))
1308+ self .modules_tool .prepend_module_path (os .path .join (fake_mod_path , self .mod_subdir ), priority = 10000 )
13011309 self .load_module (purge = purge )
13021310
13031311 return (fake_mod_path , env )
@@ -1752,6 +1760,14 @@ def prepare_step(self, start_dir=True):
17521760 self .toolchain .prepare (self .cfg ['onlytcmod' ], silent = self .silent , rpath_filter_dirs = self .rpath_filter_dirs ,
17531761 rpath_include_dirs = self .rpath_include_dirs )
17541762
1763+ # keep track of environment variables that were tweaked and need to be restored after environment got reset
1764+ # $TMPDIR may be tweaked for OpenMPI 2.x, which doesn't like long $TMPDIR paths...
1765+ for var in ['TMPDIR' ]:
1766+ if os .environ .get (var ) != self .initial_environ .get (var ):
1767+ self .tweaked_env_vars [var ] = os .environ .get (var )
1768+ self .log .info ("Found tweaked value for $%s: %s (was: %s)" ,
1769+ var , self .tweaked_env_vars [var ], self .initial_environ [var ])
1770+
17551771 # handle allowed system dependencies
17561772 for (name , version ) in self .cfg ['allow_system_deps' ]:
17571773 # root is set to name, not an actual path
@@ -1859,7 +1875,7 @@ def extensions_step(self, fetch=False):
18591875
18601876 cls , inst = None , None
18611877 class_name = encode_class_name (ext ['name' ])
1862- mod_path = get_module_path (class_name )
1878+ mod_path = get_module_path (class_name , generic = False )
18631879
18641880 # try instantiating extension-specific class
18651881 try :
@@ -2143,10 +2159,57 @@ def _sanity_check_step_dry_run(self, custom_paths=None, custom_commands=None, **
21432159 else :
21442160 self .log .debug ("Skiping RPATH sanity check" )
21452161
2162+ def _sanity_check_step_extensions (self ):
2163+ """Sanity check on extensions (if any)."""
2164+ failed_exts = []
2165+ for ext in self .ext_instances :
2166+ success , fail_msg = None , None
2167+ res = ext .sanity_check_step ()
2168+ # if result is a tuple, we expect a (<bool (success)>, <custom_message>) format
2169+ if isinstance (res , tuple ):
2170+ if len (res ) != 2 :
2171+ raise EasyBuildError ("Wrong sanity check result type for '%s' extension: %s" , ext .name , res )
2172+ success , fail_msg = res
2173+ else :
2174+ # if result of extension sanity check is not a 2-tuple, treat it as a boolean indicating success
2175+ success , fail_msg = res , "(see log for details)"
2176+
2177+ if not success :
2178+ fail_msg = "failing sanity check for '%s' extension: %s" % (ext .name , fail_msg )
2179+ failed_exts .append ((ext .name , fail_msg ))
2180+ self .log .warning (fail_msg )
2181+ else :
2182+ self .log .info ("Sanity check for '%s' extension passed!" , ext .name )
2183+
2184+ if failed_exts :
2185+ overall_fail_msg = "extensions sanity check failed for %d extensions: " % len (failed_exts )
2186+ self .log .warning (overall_fail_msg )
2187+ self .sanity_check_fail_msgs .append (overall_fail_msg + ', ' .join (x [0 ] for x in failed_exts ))
2188+ self .sanity_check_fail_msgs .extend (x [1 ] for x in failed_exts )
2189+
21462190 def _sanity_check_step (self , custom_paths = None , custom_commands = None , extension = False ):
21472191 """Real version of sanity_check_step method."""
21482192 paths , path_keys_and_check , commands = self ._sanity_check_step_common (custom_paths , custom_commands )
21492193
2194+ # helper function to sanity check (alternatives for) one particular path
2195+ def check_path (xs , typ , check_fn ):
2196+ """Sanity check for one particular path."""
2197+ found = False
2198+ for name in xs :
2199+ path = os .path .join (self .installdir , name )
2200+ if check_fn (path ):
2201+ self .log .debug ("Sanity check: found %s %s in %s" % (typ , name , self .installdir ))
2202+ found = True
2203+ break
2204+ else :
2205+ self .log .debug ("Could not find %s %s in %s" % (typ , name , self .installdir ))
2206+
2207+ return found
2208+
2209+ def xs2str (xs ):
2210+ """Human-readable version of alternative locations for a particular file/directory."""
2211+ return ' or ' .join ("'%s'" % x for x in xs )
2212+
21502213 # check sanity check paths
21512214 for key , (typ , check_fn ) in path_keys_and_check .items ():
21522215
@@ -2156,21 +2219,28 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
21562219 elif not isinstance (xs , tuple ):
21572220 raise EasyBuildError ("Unsupported type '%s' encountered in %s, not a string or tuple" ,
21582221 key , type (xs ))
2159- found = False
2160- for name in xs :
2161- path = os .path .join (self .installdir , name )
2162- if check_fn (path ):
2163- self .log .debug ("Sanity check: found %s %s in %s" % (typ , name , self .installdir ))
2164- found = True
2165- break
2166- else :
2167- self .log .debug ("Could not find %s %s in %s" % (typ , name , self .installdir ))
2222+
2223+ found = check_path (xs , typ , check_fn )
2224+
2225+ # for library files in lib/, also consider fallback to lib64/ equivalent (and vice versa)
2226+ if not found and build_option ('lib64_fallback_sanity_check' ):
2227+ xs_alt = None
2228+ if all (x .startswith ('lib/' ) for x in xs ):
2229+ xs_alt = [os .path .join ('lib64' , * os .path .split (x )[1 :]) for x in xs ]
2230+ elif all (x .startswith ('lib64/' ) for x in xs ):
2231+ xs_alt = [os .path .join ('lib' , * os .path .split (x )[1 :]) for x in xs ]
2232+
2233+ if xs_alt :
2234+ self .log .info ("%s not found at %s in %s, consider fallback locations: %s" ,
2235+ typ , xs2str (xs ), self .installdir , xs2str (xs_alt ))
2236+ found = check_path (xs_alt , typ , check_fn )
2237+
21682238 if not found :
2169- self .sanity_check_fail_msgs .append ("no %s of %s in %s" % (typ , xs , self .installdir ))
2170- self .log .warning ("Sanity check: %s" % self .sanity_check_fail_msgs [- 1 ])
2239+ sanity_check_fail_msg = "no %s found at %s in %s" % (typ , xs2str (xs ), self .installdir )
2240+ self .sanity_check_fail_msgs .append (sanity_check_fail_msg )
2241+ self .log .warning ("Sanity check: %s" , sanity_check_fail_msg )
21712242
2172- cand_paths = ' or ' .join (["'%s'" % x for x in xs ])
2173- trace_msg ("%s %s found: %s" % (typ , cand_paths , ('FAILED' , 'OK' )[found ]))
2243+ trace_msg ("%s %s found: %s" % (typ , xs2str (xs ), ('FAILED' , 'OK' )[found ]))
21742244
21752245 fake_mod_data = None
21762246 # only load fake module for non-extensions, and not during dry run
@@ -2189,7 +2259,6 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
21892259
21902260 # run sanity check commands
21912261 for command in commands :
2192-
21932262 out , ec = run_cmd (command , simple = False , log_ok = False , log_all = False , trace = False )
21942263 if ec != 0 :
21952264 fail_msg = "sanity check command %s exited with code %s (output: %s)" % (command , ec , out )
@@ -2200,12 +2269,9 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
22002269
22012270 trace_msg ("running command '%s': %s" % (command , ('FAILED' , 'OK' )[ec == 0 ]))
22022271
2272+ # also run sanity check for extensions (unless we are an extension ourselves)
22032273 if not extension :
2204- failed_exts = [ext .name for ext in self .ext_instances if not ext .sanity_check_step ()]
2205-
2206- if failed_exts :
2207- self .sanity_check_fail_msgs .append ("sanity checks for %s extensions failed!" % failed_exts )
2208- self .log .warning ("Sanity check: %s" % self .sanity_check_fail_msgs [- 1 ])
2274+ self ._sanity_check_step_extensions ()
22092275
22102276 # cleanup
22112277 if fake_mod_data :
@@ -2221,21 +2287,21 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
22212287
22222288 # pass or fail
22232289 if self .sanity_check_fail_msgs :
2224- raise EasyBuildError ("Sanity check failed: %s" , ', ' .join (self .sanity_check_fail_msgs ))
2290+ raise EasyBuildError ("Sanity check failed: %s" , '\n ' .join (self .sanity_check_fail_msgs ))
22252291 else :
22262292 self .log .debug ("Sanity check passed!" )
22272293
2228- def _set_module_as_default (self ):
2294+ def _set_module_as_default (self , fake = False ):
22292295 """
2230- Defining default module Version
2296+ Sets the default module version except if we are in dry run
22312297
2232- sets the default module version except if we are in dry run.
2298+ :param fake: set default for 'fake' module in temporary location
22332299 """
22342300 version = self .full_mod_name .split ('/' )[- 1 ]
22352301 if self .dry_run :
22362302 dry_run_msg ("Marked %s v%s as default version" % (self .name , version ))
22372303 else :
2238- mod_folderpath = os .path .dirname (self .module_generator .get_module_filepath ())
2304+ mod_folderpath = os .path .dirname (self .module_generator .get_module_filepath (fake = fake ))
22392305 self .module_generator .set_as_default (mod_folderpath , version )
22402306
22412307 def cleanup_step (self ):
@@ -2343,8 +2409,10 @@ def make_module_step(self, fake=False):
23432409 else :
23442410 self .log .info ("Skipping devel module..." )
23452411
2346- if build_option ('set_default_module' ):
2347- self ._set_module_as_default ()
2412+ # always set default for temporary module file,
2413+ # to avoid that it gets overruled by an existing module file that is set as default
2414+ if fake or build_option ('set_default_module' ):
2415+ self ._set_module_as_default (fake = fake )
23482416
23492417 return modpath
23502418
0 commit comments