@@ -688,6 +688,62 @@ def post_sanitycheck_cuda(self, *args, **kwargs):
688688 raise EasyBuildError ("CUDA-specific hook triggered for non-CUDA easyconfig?!" )
689689
690690
691+ def post_sanitycheck_cuDNN (self , * args , ** kwargs ):
692+ """
693+ Remove files from cuDNN installation that we are not allowed to ship,
694+ and replace them with a symlink to a corresponding installation under host_injections.
695+ """
696+ if self .name == 'cuDNN' :
697+ print_msg ("Replacing files in cuDNN installation that we can not ship with symlinks to host_injections..." )
698+
699+ allowlist = ['LICENSE' ]
700+
701+ # read cuDNN LICENSE, construct allowlist based on section 2.6 that specifies list of files that can be shipped
702+ license_path = os .path .join (self .installdir , 'LICENSE' )
703+ search_string = "2. Distribution. The following portions of the SDK are distributable under the Agreement:"
704+ with open (license_path ) as infile :
705+ for line in infile :
706+ if line .strip ().startswith (search_string ):
707+ # remove search string, split into words, remove trailing
708+ # dots '.' and only retain words starting with a dot '.'
709+ distributable = line [len (search_string ):]
710+ for word in distributable .split ():
711+ if word [0 ] == '.' :
712+ allowlist .append (word .rstrip ('.' ))
713+
714+ allowlist = sorted (set (allowlist ))
715+ self .log .info ("Allowlist for files in cuDNN installation that can be redistributed: " + ', ' .join (allowlist ))
716+
717+ # iterate over all files in the CUDA installation directory
718+ for dir_path , _ , files in os .walk (self .installdir ):
719+ for filename in files :
720+ full_path = os .path .join (dir_path , filename )
721+ # we only really care about real files, i.e. not symlinks
722+ if not os .path .islink (full_path ):
723+ # check if the current file is part of the allowlist
724+ basename = filename .split ('.' )[0 ]
725+ if '.' in filename :
726+ extension = '.' + filename .split ('.' )[1 ]
727+ if basename in allowlist :
728+ self .log .debug ("%s is found in allowlist, so keeping it: %s" , basename , full_path )
729+ elif '.' in filename and extension in allowlist :
730+ self .log .debug ("%s is found in allowlist, so keeping it: %s" , extension , full_path )
731+ else :
732+ self .log .debug ("%s is not found in allowlist, so replacing it with symlink: %s" ,
733+ filename , full_path )
734+ # if it is not in the allowlist, delete the file and create a symlink to host_injections
735+ host_inj_path = full_path .replace ('versions' , 'host_injections' )
736+ # make sure source and target of symlink are not the same
737+ if full_path == host_inj_path :
738+ raise EasyBuildError ("Source (%s) and target (%s) are the same location, are you sure you "
739+ "are using this hook for a NESSI installation?" ,
740+ full_path , host_inj_path )
741+ remove_file (full_path )
742+ symlink (host_inj_path , full_path )
743+ else :
744+ raise EasyBuildError ("cuDNN-specific hook triggered for non-cuDNN easyconfig?!" )
745+
746+
691747def inject_gpu_property (ec ):
692748 """
693749 Add 'gpu' property, via modluafooter easyconfig parameter
@@ -712,6 +768,25 @@ def inject_gpu_property(ec):
712768 ec [key ] = '\n ' .join ([ec_dict [key ], value ])
713769 else :
714770 ec [key ] = value
771+ # Check if cuDNN is in the dependencies, if so add the 'gpu' Lmod property
772+ if ('cuDNN' in [dep [0 ] for dep in iter (ec_dict ['dependencies' ])]):
773+ ec .log .info ("Injecting gpu as Lmod arch property and envvar with cuDNN version" )
774+ key = 'modluafooter'
775+ value = 'add_property("arch","gpu")'
776+ cudnn_version = 0
777+ for dep in iter (ec_dict ['dependencies' ]):
778+ # Make cuDNN a build dependency only (rpathing saves us from link errors)
779+ if 'cuDNN' in dep [0 ]:
780+ cudnn_version = dep [1 ]
781+ ec_dict ['dependencies' ].remove (dep )
782+ if dep not in ec_dict ['builddependencies' ]:
783+ ec_dict ['builddependencies' ].append (dep )
784+ value = '\n ' .join ([value , 'setenv("EESSICUDNNVERSION","%s")' % cudnn_version ])
785+ if key in ec_dict :
786+ if not value in ec_dict [key ]:
787+ ec [key ] = '\n ' .join ([ec_dict [key ], value ])
788+ else :
789+ ec [key ] = value
715790 return ec
716791
717792
@@ -768,4 +843,5 @@ def inject_gpu_property(ec):
768843
769844POST_SANITYCHECK_HOOKS = {
770845 'CUDA' : post_sanitycheck_cuda ,
846+ 'cuDNN' : post_sanitycheck_cuDNN ,
771847}
0 commit comments