@@ -342,12 +342,12 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
342
342
343
343
first := true
344
344
for {
345
- var include string
345
+ var missingIncludeH string
346
346
cache .ExpectFile (sourcePath )
347
347
348
- includes := ctx .IncludeFolders
348
+ includeFolders := ctx .IncludeFolders
349
349
if library , ok := sourceFile .Origin .(* libraries.Library ); ok && library .UtilityDir != nil {
350
- includes = append (includes , library .UtilityDir )
350
+ includeFolders = append (includeFolders , library .UtilityDir )
351
351
}
352
352
353
353
if library , ok := sourceFile .Origin .(* libraries.Library ); ok {
@@ -361,72 +361,72 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
361
361
}
362
362
}
363
363
364
- var preproc_err error
365
- var preproc_stderr []byte
364
+ var preprocErr error
365
+ var preprocStderr []byte
366
366
367
367
if unchanged && cache .valid {
368
- include = cache .Next ().Include
368
+ missingIncludeH = cache .Next ().Include
369
369
if first && ctx .Verbose {
370
370
ctx .Info (tr ("Using cached library dependencies for file: %[1]s" , sourcePath ))
371
371
}
372
372
} 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 )
375
375
if ctx .Verbose {
376
- ctx .WriteStdout (preproc_stdout )
377
- ctx .WriteStdout (preproc_stderr )
376
+ ctx .WriteStdout (preprocStdout )
377
+ ctx .WriteStdout (preprocStderr )
378
378
}
379
379
// 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 {
382
382
// Preprocessor successful, done
383
- include = ""
384
- } else if ! is_exit_error || preproc_stderr == nil {
383
+ missingIncludeH = ""
384
+ } else if ! isExitErr || preprocStderr == nil {
385
385
// Ignore ExitErrors (e.g. gcc returning
386
386
// non-zero status), but bail out on
387
387
// other errors
388
- return errors .WithStack (preproc_err )
388
+ return errors .WithStack (preprocErr )
389
389
} else {
390
- include = IncludesFinderWithRegExp (string (preproc_stderr ))
391
- if include == "" && ctx .Verbose {
390
+ missingIncludeH = IncludesFinderWithRegExp (string (preprocStderr ))
391
+ if missingIncludeH == "" && ctx .Verbose {
392
392
ctx .Info (tr ("Error while detecting libraries included by %[1]s" , sourcePath ))
393
393
}
394
394
}
395
395
}
396
396
397
- if include == "" {
397
+ if missingIncludeH == "" {
398
398
// No missing includes found, we're done
399
399
cache .ExpectEntry (sourcePath , "" , nil )
400
400
return nil
401
401
}
402
402
403
- library := ResolveLibrary (ctx , include )
403
+ library := ResolveLibrary (ctx , missingIncludeH )
404
404
if library == nil {
405
405
// Library could not be resolved, show error
406
- if preproc_err == nil || preproc_stderr == nil {
406
+ if preprocErr == nil || preprocStderr == nil {
407
407
// 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 )
410
410
if ctx .Verbose {
411
- ctx .WriteStdout (preproc_stdout )
411
+ ctx .WriteStdout (preprocStdout )
412
412
}
413
- if preproc_err == nil {
413
+ if preprocErr == nil {
414
414
// If there is a missing #include in the cache, but running
415
415
// gcc does not reproduce that, there is something wrong.
416
416
// Returning an error here will cause the cache to be
417
417
// deleted, so hopefully the next compilation will succeed.
418
418
return errors .New (tr ("Internal error in cache" ))
419
419
}
420
420
}
421
- ctx .WriteStderr (preproc_stderr )
422
- return errors .WithStack (preproc_err )
421
+ ctx .WriteStderr (preprocStderr )
422
+ return errors .WithStack (preprocErr )
423
423
}
424
424
425
425
// Add this library to the list of libraries, the
426
426
// include path and queue its source files for further
427
427
// include scanning
428
428
ctx .ImportedLibraries = append (ctx .ImportedLibraries , library )
429
- appendIncludeFolder (ctx , cache , sourcePath , include , library .SourceDir )
429
+ appendIncludeFolder (ctx , cache , sourcePath , missingIncludeH , library .SourceDir )
430
430
sourceDirs := library .SourceDirs ()
431
431
for _ , sourceDir := range sourceDirs {
432
432
queueSourceFilesFromFolder (ctx , sourceFileQueue , library , sourceDir .Dir , sourceDir .Recurse )
@@ -455,3 +455,48 @@ func queueSourceFilesFromFolder(ctx *types.Context, sourceFileQueue *types.Uniqu
455
455
456
456
return nil
457
457
}
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