@@ -164,7 +164,7 @@ def all_compilers_config(scope=None, init_config=True):
164164 return _cache_config_file
165165
166166
167- def all_compilers (scope = None , init_config = True ):
167+ def all_compiler_specs (scope = None , init_config = True ):
168168 # Return compiler specs from the merged config.
169169 return [spack .spec .CompilerSpec (s ['compiler' ]['spec' ])
170170 for s in all_compilers_config (scope , init_config )]
@@ -203,72 +203,93 @@ def supported(compiler_spec):
203203def find (compiler_spec , scope = None ):
204204 """Return specs of available compilers that match the supplied
205205 compiler spec. Return an empty list if nothing found."""
206- return [c for c in all_compilers (scope ) if c .satisfies (compiler_spec )]
206+ return [c for c in all_compiler_specs (scope ) if c .satisfies (compiler_spec )]
207+
208+
209+ def all_compilers (scope = None ):
210+ config = get_compiler_config (scope )
211+ compilers = list ()
212+ for items in config :
213+ items = items ['compiler' ]
214+ compilers .append (compiler_from_config_entry (items ))
215+ return compilers
207216
208217
209218@_auto_compiler_spec
210- def compilers_for_spec (compiler_spec , arch_spec = None , scope = None ):
219+ def compilers_for_spec (compiler_spec , arch_spec = None , scope = None ,
220+ use_cache = True ):
211221 """This gets all compilers that satisfy the supplied CompilerSpec.
212222 Returns an empty list if none are found.
213223 """
214- config = all_compilers_config (scope )
215-
216- def get_compilers (cspec ):
217- compilers = []
218-
219- for items in config :
220- items = items ['compiler' ]
221- if items ['spec' ] != str (cspec ):
222- continue
223-
224- # If an arch spec is given, confirm that this compiler
225- # is for the given operating system
226- os = items .get ('operating_system' , None )
227- if arch_spec and os != arch_spec .platform_os :
228- continue
229-
230- # If an arch spec is given, confirm that this compiler
231- # is for the given target. If the target is 'any', match
232- # any given arch spec. If the compiler has no assigned
233- # target this is an old compiler config file, skip this logic.
234- target = items .get ('target' , None )
235- if arch_spec and target and (target != arch_spec .target and
236- target != 'any' ):
237- continue
238-
239- if not ('paths' in items and
240- all (n in items ['paths' ] for n in _path_instance_vars )):
241- raise InvalidCompilerConfigurationError (cspec )
242-
243- cls = class_for_compiler_name (cspec .name )
244-
245- compiler_paths = []
246- for c in _path_instance_vars :
247- compiler_path = items ['paths' ][c ]
248- if compiler_path != 'None' :
249- compiler_paths .append (compiler_path )
250- else :
251- compiler_paths .append (None )
252-
253- mods = items .get ('modules' )
254- if mods == 'None' :
255- mods = []
256-
257- alias = items .get ('alias' , None )
258- compiler_flags = items .get ('flags' , {})
259- environment = items .get ('environment' , {})
260- extra_rpaths = items .get ('extra_rpaths' , [])
261-
262- compilers .append (
263- cls (cspec , os , target , compiler_paths , mods , alias ,
264- environment , extra_rpaths , ** compiler_flags ))
265-
266- return compilers
224+ if use_cache :
225+ config = all_compilers_config (scope )
226+ else :
227+ config = get_compiler_config (scope )
267228
268229 matches = set (find (compiler_spec , scope ))
269230 compilers = []
270231 for cspec in matches :
271- compilers .extend (get_compilers (cspec ))
232+ compilers .extend (get_compilers (cspec , config , arch_spec ))
233+ return compilers
234+
235+
236+ def compiler_from_config_entry (items ):
237+ cspec = spack .spec .CompilerSpec (items ['spec' ])
238+ os = items .get ('operating_system' , None )
239+ target = items .get ('target' , None )
240+
241+ if not ('paths' in items and
242+ all (n in items ['paths' ] for n in _path_instance_vars )):
243+ raise InvalidCompilerConfigurationError (cspec )
244+
245+ cls = class_for_compiler_name (cspec .name )
246+
247+ compiler_paths = []
248+ for c in _path_instance_vars :
249+ compiler_path = items ['paths' ][c ]
250+ if compiler_path != 'None' :
251+ compiler_paths .append (compiler_path )
252+ else :
253+ compiler_paths .append (None )
254+
255+ mods = items .get ('modules' )
256+ if mods == 'None' :
257+ mods = []
258+
259+ alias = items .get ('alias' , None )
260+ compiler_flags = items .get ('flags' , {})
261+ environment = items .get ('environment' , {})
262+ extra_rpaths = items .get ('extra_rpaths' , [])
263+
264+ return cls (cspec , os , target , compiler_paths , mods , alias ,
265+ environment , extra_rpaths , ** compiler_flags )
266+
267+
268+ def get_compilers (cspec , config , arch_spec = None ):
269+ compilers = []
270+
271+ for items in config :
272+ items = items ['compiler' ]
273+ if items ['spec' ] != str (cspec ):
274+ continue
275+
276+ # If an arch spec is given, confirm that this compiler
277+ # is for the given operating system
278+ os = items .get ('operating_system' , None )
279+ if arch_spec and os != arch_spec .platform_os :
280+ continue
281+
282+ # If an arch spec is given, confirm that this compiler
283+ # is for the given target. If the target is 'any', match
284+ # any given arch spec. If the compiler has no assigned
285+ # target this is an old compiler config file, skip this logic.
286+ target = items .get ('target' , None )
287+ if arch_spec and target and (target != arch_spec .target and
288+ target != 'any' ):
289+ continue
290+
291+ compilers .append (compiler_from_config_entry (items ))
292+
272293 return compilers
273294
274295
@@ -283,10 +304,28 @@ def compiler_for_spec(compiler_spec, arch_spec):
283304 if len (compilers ) < 1 :
284305 raise NoCompilerForSpecError (compiler_spec , arch_spec .platform_os )
285306 if len (compilers ) > 1 :
286- raise CompilerSpecInsufficientlySpecificError (compiler_spec )
307+ raise CompilerDuplicateError (compiler_spec , arch_spec )
287308 return compilers [0 ]
288309
289310
311+ @_auto_compiler_spec
312+ def get_compiler_duplicates (compiler_spec , arch_spec ):
313+ config_scopes = spack .config .config_scopes
314+ scope_to_compilers = dict ()
315+ for scope in config_scopes :
316+ compilers = compilers_for_spec (compiler_spec , arch_spec = arch_spec ,
317+ scope = scope , use_cache = False )
318+ if compilers :
319+ scope_to_compilers [scope ] = compilers
320+
321+ cfg_file_to_duplicates = dict ()
322+ for scope , compilers in scope_to_compilers .iteritems ():
323+ config_file = config_scopes [scope ].get_section_filename ('compilers' )
324+ cfg_file_to_duplicates [config_file ] = compilers
325+
326+ return cfg_file_to_duplicates
327+
328+
290329def class_for_compiler_name (compiler_name ):
291330 """Given a compiler module name, get the corresponding Compiler class."""
292331 assert (supported (compiler_name ))
@@ -341,6 +380,24 @@ def __init__(self, compiler_spec, target):
341380 % (target , compiler_spec ))
342381
343382
383+ class CompilerDuplicateError (spack .error .SpackError ):
384+ def __init__ (self , compiler_spec , arch_spec ):
385+ config_file_to_duplicates = get_compiler_duplicates (
386+ compiler_spec , arch_spec )
387+ duplicate_table = list (
388+ (x , len (y )) for x , y in config_file_to_duplicates .iteritems ())
389+ descriptor = lambda num : 'time' if num == 1 else 'times'
390+ duplicate_msg = (
391+ lambda cfgfile , count : "{0}: {1} {2}" .format (
392+ cfgfile , str (count ), descriptor (count )))
393+ msg = (
394+ "Compiler configuration contains entries with duplicate" +
395+ " specification ({0}, {1})" .format (compiler_spec , arch_spec ) +
396+ " in the following files:\n \t " +
397+ '\n \t ' .join (duplicate_msg (x , y ) for x , y in duplicate_table ))
398+ super (CompilerDuplicateError , self ).__init__ (msg )
399+
400+
344401class CompilerSpecInsufficientlySpecificError (spack .error .SpackError ):
345402 def __init__ (self , compiler_spec ):
346403 super (CompilerSpecInsufficientlySpecificError , self ).__init__ (
0 commit comments