@@ -342,12 +342,12 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
342342
343343 first := true
344344 for {
345- var include string
345+ var missingIncludeH string
346346 cache .ExpectFile (sourcePath )
347347
348- includes := ctx .IncludeFolders
348+ includeFolders := ctx .IncludeFolders
349349 if library , ok := sourceFile .Origin .(* libraries.Library ); ok && library .UtilityDir != nil {
350- includes = append (includes , library .UtilityDir )
350+ includeFolders = append (includeFolders , library .UtilityDir )
351351 }
352352
353353 if library , ok := sourceFile .Origin .(* libraries.Library ); ok {
@@ -361,72 +361,72 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
361361 }
362362 }
363363
364- var preproc_err error
365- var preproc_stderr []byte
364+ var preprocErr error
365+ var preprocStderr []byte
366366
367367 if unchanged && cache .valid {
368- include = cache .Next ().Include
368+ missingIncludeH = cache .Next ().Include
369369 if first && ctx .Verbose {
370370 ctx .Info (tr ("Using cached library dependencies for file: %[1]s" , sourcePath ))
371371 }
372372 } else {
373- var preproc_stdout []byte
374- preproc_stdout , preproc_stderr , preproc_err = preprocessor .GCC (sourcePath , targetFilePath , includes , ctx .BuildProperties )
373+ var preprocStdout []byte
374+ preprocStdout , preprocStderr , preprocErr = preprocessor .GCC (sourcePath , targetFilePath , includeFolders , ctx .BuildProperties )
375375 if ctx .Verbose {
376- ctx .WriteStdout (preproc_stdout )
377- ctx .WriteStdout (preproc_stderr )
376+ ctx .WriteStdout (preprocStdout )
377+ ctx .WriteStdout (preprocStderr )
378378 }
379379 // Unwrap error and see if it is an ExitError.
380- _ , is_exit_error := errors .Cause (preproc_err ).(* exec.ExitError )
381- if preproc_err == nil {
380+ _ , isExitErr := errors .Cause (preprocErr ).(* exec.ExitError )
381+ if preprocErr == nil {
382382 // Preprocessor successful, done
383- include = ""
384- } else if ! is_exit_error || preproc_stderr == nil {
383+ missingIncludeH = ""
384+ } else if ! isExitErr || preprocStderr == nil {
385385 // Ignore ExitErrors (e.g. gcc returning
386386 // non-zero status), but bail out on
387387 // other errors
388- return errors .WithStack (preproc_err )
388+ return errors .WithStack (preprocErr )
389389 } else {
390- include = IncludesFinderWithRegExp (string (preproc_stderr ))
391- if include == "" && ctx .Verbose {
390+ missingIncludeH = IncludesFinderWithRegExp (string (preprocStderr ))
391+ if missingIncludeH == "" && ctx .Verbose {
392392 ctx .Info (tr ("Error while detecting libraries included by %[1]s" , sourcePath ))
393393 }
394394 }
395395 }
396396
397- if include == "" {
397+ if missingIncludeH == "" {
398398 // No missing includes found, we're done
399399 cache .ExpectEntry (sourcePath , "" , nil )
400400 return nil
401401 }
402402
403- library := ResolveLibrary (ctx , include )
403+ library := ResolveLibrary (ctx , missingIncludeH )
404404 if library == nil {
405405 // Library could not be resolved, show error
406- if preproc_err == nil || preproc_stderr == nil {
406+ if preprocErr == nil || preprocStderr == nil {
407407 // Filename came from cache, so run preprocessor to obtain error to show
408- var preproc_stdout []byte
409- preproc_stdout , preproc_stderr , preproc_err = preprocessor .GCC (sourcePath , targetFilePath , includes , ctx .BuildProperties )
408+ var preprocStdout []byte
409+ preprocStdout , preprocStderr , preprocErr = preprocessor .GCC (sourcePath , targetFilePath , includeFolders , ctx .BuildProperties )
410410 if ctx .Verbose {
411- ctx .WriteStdout (preproc_stdout )
411+ ctx .WriteStdout (preprocStdout )
412412 }
413- if preproc_err == nil {
413+ if preprocErr == nil {
414414 // If there is a missing #include in the cache, but running
415415 // gcc does not reproduce that, there is something wrong.
416416 // Returning an error here will cause the cache to be
417417 // deleted, so hopefully the next compilation will succeed.
418418 return errors .New (tr ("Internal error in cache" ))
419419 }
420420 }
421- ctx .WriteStderr (preproc_stderr )
422- return errors .WithStack (preproc_err )
421+ ctx .WriteStderr (preprocStderr )
422+ return errors .WithStack (preprocErr )
423423 }
424424
425425 // Add this library to the list of libraries, the
426426 // include path and queue its source files for further
427427 // include scanning
428428 ctx .ImportedLibraries = append (ctx .ImportedLibraries , library )
429- appendIncludeFolder (ctx , cache , sourcePath , include , library .SourceDir )
429+ appendIncludeFolder (ctx , cache , sourcePath , missingIncludeH , library .SourceDir )
430430 sourceDirs := library .SourceDirs ()
431431 for _ , sourceDir := range sourceDirs {
432432 queueSourceFilesFromFolder (ctx , sourceFileQueue , library , sourceDir .Dir , sourceDir .Recurse )
@@ -455,3 +455,48 @@ func queueSourceFilesFromFolder(ctx *types.Context, sourceFileQueue *types.Uniqu
455455
456456 return nil
457457}
458+
459+ func ResolveLibrary (ctx * types.Context , header string ) * libraries.Library {
460+ resolver := ctx .LibrariesResolver
461+ importedLibraries := ctx .ImportedLibraries
462+
463+ candidates := resolver .AlternativesFor (header )
464+
465+ if ctx .Verbose {
466+ ctx .Info (tr ("Alternatives for %[1]s: %[2]s" , header , candidates ))
467+ ctx .Info (fmt .Sprintf ("ResolveLibrary(%s)" , header ))
468+ ctx .Info (fmt .Sprintf (" -> %s: %s" , tr ("candidates" ), candidates ))
469+ }
470+
471+ if len (candidates ) == 0 {
472+ return nil
473+ }
474+
475+ for _ , candidate := range candidates {
476+ if importedLibraries .Contains (candidate ) {
477+ return nil
478+ }
479+ }
480+
481+ selected := resolver .ResolveFor (header , ctx .TargetPlatform .Platform .Architecture )
482+ if alreadyImported := importedLibraries .FindByName (selected .Name ); alreadyImported != nil {
483+ // Certain libraries might have the same name but be different.
484+ // This usually happens when the user includes two or more custom libraries that have
485+ // different header name but are stored in a parent folder with identical name, like
486+ // ./libraries1/Lib/lib1.h and ./libraries2/Lib/lib2.h
487+ // Without this check the library resolution would be stuck in a loop.
488+ // This behaviour has been reported in this issue:
489+ // https://github.com/arduino/arduino-cli/issues/973
490+ if selected == alreadyImported {
491+ selected = alreadyImported
492+ }
493+ }
494+
495+ candidates .Remove (selected )
496+ ctx .LibrariesResolutionResults [header ] = types.LibraryResolutionResult {
497+ Library : selected ,
498+ NotUsedLibraries : candidates ,
499+ }
500+
501+ return selected
502+ }
0 commit comments