3232@author: Guilherme Peretti-Pezzi (CSCS)
3333@author: Oliver Stueker (Compute Canada/ACENET)
3434@author: Davide Vanzo (Vanderbilt University)
35+ @author: Alex Domingo (Vrije Universiteit Brussel)
3536"""
3637import glob
3738import os
3839import re
3940import shutil
40- from easybuild .tools import LooseVersion
4141
4242import easybuild .tools .environment as env
4343import easybuild .tools .toolchain as toolchain
44- from easybuild .easyblocks .generic .configuremake import ConfigureMake
4544from easybuild .easyblocks .generic .cmakemake import CMakeMake
45+ from easybuild .easyblocks .generic .configuremake import ConfigureMake
4646from easybuild .framework .easyconfig import CUSTOM
47+ from easybuild .tools import LooseVersion
4748from easybuild .tools .build_log import EasyBuildError , print_warning
4849from easybuild .tools .config import build_option
4950from easybuild .tools .filetools import copy_dir , find_backup_name_candidate , remove_dir , which
5051from easybuild .tools .modules import get_software_libdir , get_software_root , get_software_version
5152from easybuild .tools .run import run_shell_cmd
53+ from easybuild .tools .systemtools import X86_64 , get_cpu_architecture , get_cpu_features , get_shared_lib_ext
5254from easybuild .tools .toolchain .compiler import OPTARCH_GENERIC
53- from easybuild .tools .systemtools import X86_64 , get_cpu_architecture , get_shared_lib_ext , get_cpu_features
55+ from easybuild .tools .utilities import nub
5456from easybuild .tools .version import VERBOSE_VERSION as EASYBUILD_VERSION
5557
5658
@@ -79,12 +81,15 @@ def extra_options():
7981 def __init__ (self , * args , ** kwargs ):
8082 """Initialize GROMACS-specific variables."""
8183 super (EB_GROMACS , self ).__init__ (* args , ** kwargs )
82- self .lib_subdir = ''
84+
85+ self .lib_subdirs = ''
8386 self .pre_env = ''
8487 self .cfg ['build_shared_libs' ] = self .cfg .get ('build_shared_libs' , False )
88+
8589 if LooseVersion (self .version ) >= LooseVersion ('2019' ):
8690 # Building the gmxapi interface requires shared libraries
8791 self .cfg ['build_shared_libs' ] = True
92+
8893 if self .cfg ['build_shared_libs' ]:
8994 self .libext = get_shared_lib_ext ()
9095 else :
@@ -142,6 +147,7 @@ def get_gromacs_arch(self):
142147
143148 return res
144149
150+ @property
145151 def is_double_precision_cuda_build (self ):
146152 """Check if the current build step involves double precision and CUDA"""
147153 cuda = get_software_root ('CUDA' )
@@ -461,15 +467,15 @@ def build_step(self):
461467 iteration is for double precision
462468 """
463469
464- if self .is_double_precision_cuda_build () :
470+ if self .is_double_precision_cuda_build :
465471 self .log .info ("skipping build step" )
466472 else :
467473 super (EB_GROMACS , self ).build_step ()
468474
469475 def test_step (self ):
470476 """Run the basic tests (but not necessarily the full regression tests) using make check"""
471477
472- if self .is_double_precision_cuda_build () :
478+ if self .is_double_precision_cuda_build :
473479 self .log .info ("skipping test step" )
474480 else :
475481 # allow to escape testing by setting runtest to False
@@ -525,7 +531,7 @@ def install_step(self):
525531 Custom install step for GROMACS; figure out where libraries were installed to.
526532 """
527533 # Skipping if CUDA is enabled and the current iteration is double precision
528- if self .is_double_precision_cuda_build () :
534+ if self .is_double_precision_cuda_build :
529535 self .log .info ("skipping install step" )
530536 else :
531537 # run 'make install' in parallel since it involves more compilation
@@ -548,48 +554,55 @@ def extensions_step(self, fetch=False):
548554 super (EB_GROMACS , self ).extensions_step (fetch )
549555 self .cfg ['runtest' ] = orig_runtest
550556
551- def get_lib_subdir (self ):
552- # the GROMACS libraries get installed in different locations (deeper subdirectory),
553- # depending on the platform;
554- # this is determined by the GNUInstallDirs CMake module;
555- # rather than trying to replicate the logic, we just figure out where the library was placed
557+ def get_lib_subdirs (self ):
558+ """
559+ Return list of relative paths to sub-directories that contain GROMACS libraries
560+
561+ The GROMACS libraries get installed in different locations (deeper subdirectory),
562+ depending on the platform;
563+ this is determined by the GNUInstallDirs CMake module;
564+ rather than trying to replicate the logic, we just figure out where the library was placed
565+ """
556566
557567 if LooseVersion (self .version ) < LooseVersion ('5.0' ):
558- libname = 'libgmx*.%s' % self .libext
568+ libname = f 'libgmx*.{ self .libext } '
559569 else :
560- libname = 'libgromacs*.%s' % self .libext
561- lib_subdir = None
562- for libdir in ['lib' , 'lib64' ]:
563- if os .path .exists (os .path .join (self .installdir , libdir )):
564- for subdir in [libdir , os .path .join (libdir , '*' )]:
565- libpaths = glob .glob (os .path .join (self .installdir , subdir , libname ))
566- if libpaths :
567- lib_subdir = os .path .dirname (libpaths [0 ])[len (self .installdir ) + 1 :]
568- self .log .info ("Found lib subdirectory that contains %s: %s" , libname , lib_subdir )
569- break
570- if not lib_subdir :
571- raise EasyBuildError ("Failed to determine lib subdirectory in %s" , self .installdir )
572-
573- return lib_subdir
574-
575- def make_module_req_guess (self ):
570+ libname = f'libgromacs*.{ self .libext } '
571+
572+ lib_subdirs = []
573+ real_installdir = os .path .realpath (self .installdir )
574+ for lib_path in glob .glob (os .path .join (real_installdir , '**' , libname )):
575+ lib_relpath = os .path .realpath (lib_path ) # avoid symlinks
576+ lib_relpath = lib_relpath [len (real_installdir ) + 1 :] # relative path from installdir
577+ subdir = lib_relpath .split (os .sep )[0 :- 1 ]
578+ lib_subdirs .append (os .path .join (* subdir ))
579+
580+ if len (lib_subdirs ) == 0 :
581+ raise EasyBuildError (f"Failed to determine sub-directory with { libname } in { self .installdir } " )
582+
583+ # remove duplicates, 'libname' pattern can match symlinks to actual library file
584+ lib_subdirs = nub (lib_subdirs )
585+ self .log .info (f"Found sub-directories that contain { libname } : { ', ' .join (lib_subdirs )} " )
586+
587+ return lib_subdirs
588+
589+ def make_module_step (self , * args , ** kwargs ):
576590 """Custom library subdirectories for GROMACS."""
577- guesses = super (EB_GROMACS , self ).make_module_req_guess ()
578- if not self .lib_subdir :
591+ if not self .lib_subdirs :
579592 try :
580- self .lib_subdir = self .get_lib_subdir ()
593+ self .lib_subdirs = self .get_lib_subdirs ()
581594 except EasyBuildError as error :
582595 if build_option ('force' ) and build_option ('module_only' ):
583- self .log .info ("No lib subdirectory directory found in installation: %s" , error )
596+ self .log .info (f "No sub-directory with GROMACS libraries found in installation: { error } " )
584597 self .log .info ("You are forcing module creation for a non-existent installation!" )
585598 else :
586599 raise error
587- guesses . update ({
588- ' LD_LIBRARY_PATH' : [ self .lib_subdir ],
589- ' LIBRARY_PATH' : [ self .lib_subdir ],
590- ' PKG_CONFIG_PATH' : [os .path .join (self . lib_subdir , 'pkgconfig' )],
591- })
592- return guesses
600+
601+ self . module_load_environment . LD_LIBRARY_PATH = self .lib_subdirs
602+ self . module_load_environment . LIBRARY_PATH = self .lib_subdirs
603+ self . module_load_environment . PKG_CONFIG_PATH = [os .path .join (ld , 'pkgconfig' ) for ld in self . lib_subdirs ]
604+
605+ return super (). make_module_step ( * args , ** kwargs )
593606
594607 def sanity_check_step (self ):
595608 """Custom sanity check for GROMACS."""
@@ -660,21 +673,19 @@ def sanity_check_step(self):
660673 if dsuff :
661674 suffixes .extend ([dsuff ])
662675
663- lib_files .extend ([
664- 'lib%s%s.%s' % (x , suff , self .libext ) for x in libnames + mpi_libnames for suff in suffixes
665- ])
676+ lib_files .extend ([f'lib{ x } { suff } .{ self .libext } ' for x in libnames + mpi_libnames for suff in suffixes ])
666677 bin_files .extend ([b + suff for b in bins + mpi_bins for suff in suffixes ])
667678
668- if not self .lib_subdir :
669- self .lib_subdir = self .get_lib_subdir ()
679+ if not self .lib_subdirs :
680+ self .lib_subdirs = self .get_lib_subdirs ()
670681
671682 # pkgconfig dir not available for earlier versions, exact version to use here is unclear
672683 if LooseVersion (self .version ) >= LooseVersion ('4.6' ):
673- dirs .append ( os .path .join (self . lib_subdir , 'pkgconfig' ))
684+ dirs .extend ([ os .path .join (ld , 'pkgconfig' ) for ld in self . lib_subdirs ] )
674685
675686 custom_paths = {
676687 'files' : [os .path .join ('bin' , b ) for b in bin_files ] +
677- [os .path .join (self . lib_subdir , lib ) for lib in lib_files ],
688+ [os .path .join (libdir , lib ) for libdir in self . lib_subdirs for lib in lib_files ],
678689 'dirs' : dirs ,
679690 }
680691 super (EB_GROMACS , self ).sanity_check_step (custom_paths = custom_paths )
0 commit comments