Skip to content

Some refactorings on library resolution code #1766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 25, 2023
Merged
1 change: 0 additions & 1 deletion legacy/builder/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const FOLDER_TOOLS = "tools"
const FOLDER_LIBRARIES = "libraries"
const LIBRARY_ALL_ARCHS = "*"
const LIBRARY_EMAIL = "email"
const LIBRARY_FOLDER_ARCH = "arch"
const LIBRARY_FOLDER_SRC = "src"
const LOG_LEVEL_DEBUG = "debug"
const LOG_LEVEL_ERROR = "error"
Expand Down
84 changes: 49 additions & 35 deletions legacy/builder/container_find_includes.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (s *ContainerFindIncludes) findIncludes(ctx *types.Context) error {
}
}

if err := runCommand(ctx, &FailIfImportedLibraryIsWrong{}); err != nil {
if err := failIfImportedLibraryIsWrong(ctx); err != nil {
return errors.WithStack(err)
}

Expand All @@ -198,15 +198,6 @@ func appendIncludeFolder(ctx *types.Context, cache *includeCache, sourceFilePath
cache.ExpectEntry(sourceFilePath, include, folder)
}

func runCommand(ctx *types.Context, command types.Command) error {
PrintRingNameIfDebug(ctx, command)
err := command.Run(ctx)
if err != nil {
return errors.WithStack(err)
}
return nil
}

type includeCacheEntry struct {
Sourcefile *paths.Path
Include string
Expand Down Expand Up @@ -318,10 +309,10 @@ func writeCache(cache *includeCache, path *paths.Path) error {

func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQueue *types.UniqueSourceFileQueue) error {
sourceFile := sourceFileQueue.Pop()
sourcePath := sourceFile.SourcePath(ctx)
sourcePath := sourceFile.SourcePath()
targetFilePath := paths.NullPath()
depPath := sourceFile.DepfilePath(ctx)
objPath := sourceFile.ObjectPath(ctx)
depPath := sourceFile.DepfilePath()
objPath := sourceFile.ObjectPath()

// TODO: This should perhaps also compare against the
// include.cache file timestamp. Now, it only checks if the file
Expand All @@ -342,28 +333,21 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu

first := true
for {
var missingIncludeH string
cache.ExpectFile(sourcePath)

// Libraries may require the "utility" directory to be added to the include
// search path, but only for the source code of the library, so we temporary
// copy the current search path list and add the library' utility directory
// if needed.
includeFolders := ctx.IncludeFolders
if library, ok := sourceFile.Origin.(*libraries.Library); ok && library.UtilityDir != nil {
includeFolders = append(includeFolders, library.UtilityDir)
}

if library, ok := sourceFile.Origin.(*libraries.Library); ok {
if library.Precompiled && library.PrecompiledWithSources {
// Fully precompiled libraries should have no dependencies
// to avoid ABI breakage
if ctx.Verbose {
ctx.Info(tr("Skipping dependencies detection for precompiled library %[1]s", library.Name))
}
return nil
}
if extraInclude := sourceFile.ExtraIncludePath(); extraInclude != nil {
includeFolders = append(includeFolders, extraInclude)
}

var preprocErr error
var preprocStderr []byte

var missingIncludeH string
if unchanged && cache.valid {
missingIncludeH = cache.Next().Include
if first && ctx.Verbose {
Expand All @@ -377,14 +361,11 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
ctx.WriteStdout(preprocStderr)
}
// Unwrap error and see if it is an ExitError.
_, isExitErr := errors.Cause(preprocErr).(*exec.ExitError)
if preprocErr == nil {
// Preprocessor successful, done
missingIncludeH = ""
} else if !isExitErr || preprocStderr == nil {
// Ignore ExitErrors (e.g. gcc returning
// non-zero status), but bail out on
// other errors
} else if _, isExitErr := errors.Cause(preprocErr).(*exec.ExitError); !isExitErr || preprocStderr == nil {
// Ignore ExitErrors (e.g. gcc returning non-zero status), but bail out on other errors
return errors.WithStack(preprocErr)
} else {
missingIncludeH = IncludesFinderWithRegExp(string(preprocStderr))
Expand Down Expand Up @@ -427,9 +408,16 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
// include scanning
ctx.ImportedLibraries = append(ctx.ImportedLibraries, library)
appendIncludeFolder(ctx, cache, sourcePath, missingIncludeH, library.SourceDir)
sourceDirs := library.SourceDirs()
for _, sourceDir := range sourceDirs {
queueSourceFilesFromFolder(ctx, sourceFileQueue, library, sourceDir.Dir, sourceDir.Recurse)

if library.Precompiled && library.PrecompiledWithSources {
// Fully precompiled libraries should have no dependencies to avoid ABI breakage
if ctx.Verbose {
ctx.Info(tr("Skipping dependencies detection for precompiled library %[1]s", library.Name))
}
} else {
for _, sourceDir := range library.SourceDirs() {
queueSourceFilesFromFolder(ctx, sourceFileQueue, library, sourceDir.Dir, sourceDir.Recurse)
}
}
first = false
}
Expand Down Expand Up @@ -500,3 +488,29 @@ func ResolveLibrary(ctx *types.Context, header string) *libraries.Library {

return selected
}

func failIfImportedLibraryIsWrong(ctx *types.Context) error {
if len(ctx.ImportedLibraries) == 0 {
return nil
}

for _, library := range ctx.ImportedLibraries {
if !library.IsLegacy {
if library.InstallDir.Join("arch").IsDir() {
return errors.New(tr("%[1]s folder is no longer supported! See %[2]s for more information", "'arch'", "http://goo.gl/gfFJzU"))
}
for _, propName := range libraries.MandatoryProperties {
if !library.Properties.ContainsKey(propName) {
return errors.New(tr("Missing '%[1]s' from library in %[2]s", propName, library.InstallDir))
}
}
if library.Layout == libraries.RecursiveLayout {
if library.UtilityDir != nil {
return errors.New(tr("Library can't use both '%[1]s' and '%[2]s' folders. Double check in '%[3]s'.", "src", "utility", library.InstallDir))
}
}
}
}

return nil
}
52 changes: 0 additions & 52 deletions legacy/builder/fail_if_imported_library_is_wrong.go

This file was deleted.

82 changes: 44 additions & 38 deletions legacy/builder/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,69 +24,75 @@ import (
)

type SourceFile struct {
// Sketch or Library pointer that this source file lives in
Origin interface{}
// Path to the source file within the sketch/library root folder
RelativePath *paths.Path
relativePath *paths.Path

// ExtraIncludePath contains an extra include path that must be
// used to compile this source file.
// This is mainly used for source files that comes from old-style libraries
// (Arduino IDE <1.5) requiring an extra include path to the "utility" folder.
extraIncludePath *paths.Path

// The source root for the given origin, where its source files
// can be found. Prepending this to SourceFile.RelativePath will give
// the full path to that source file.
sourceRoot *paths.Path

// The build root for the given origin, where build products will
// be placed. Any directories inside SourceFile.RelativePath will be
// appended here.
buildRoot *paths.Path
}

func (f *SourceFile) Equals(g *SourceFile) bool {
return f.Origin == g.Origin &&
f.RelativePath.EqualsTo(g.RelativePath)
return f.relativePath.EqualsTo(g.relativePath) &&
f.buildRoot.EqualsTo(g.buildRoot) &&
f.sourceRoot.EqualsTo(g.sourceRoot)
}

// Create a SourceFile containing the given source file path within the
// given origin. The given path can be absolute, or relative within the
// origin's root source folder
func MakeSourceFile(ctx *Context, origin interface{}, path *paths.Path) (*SourceFile, error) {
if path.IsAbs() {
var err error
path, err = sourceRoot(ctx, origin).RelTo(path)
if err != nil {
return nil, err
}
}
return &SourceFile{Origin: origin, RelativePath: path}, nil
}
res := &SourceFile{}

// Return the build root for the given origin, where build products will
// be placed. Any directories inside SourceFile.RelativePath will be
// appended here.
func buildRoot(ctx *Context, origin interface{}) *paths.Path {
switch o := origin.(type) {
case *sketch.Sketch:
return ctx.SketchBuildPath
res.buildRoot = ctx.SketchBuildPath
res.sourceRoot = ctx.SketchBuildPath
case *libraries.Library:
return ctx.LibrariesBuildPath.Join(o.DirName)
res.buildRoot = ctx.LibrariesBuildPath.Join(o.DirName)
res.sourceRoot = o.SourceDir
res.extraIncludePath = o.UtilityDir
default:
panic("Unexpected origin for SourceFile: " + fmt.Sprint(origin))
}
}

// Return the source root for the given origin, where its source files
// can be found. Prepending this to SourceFile.RelativePath will give
// the full path to that source file.
func sourceRoot(ctx *Context, origin interface{}) *paths.Path {
switch o := origin.(type) {
case *sketch.Sketch:
return ctx.SketchBuildPath
case *libraries.Library:
return o.SourceDir
default:
panic("Unexpected origin for SourceFile: " + fmt.Sprint(origin))
if path.IsAbs() {
var err error
path, err = res.sourceRoot.RelTo(path)
if err != nil {
return nil, err
}
}
res.relativePath = path
return res, nil
}

func (f *SourceFile) ExtraIncludePath() *paths.Path {
return f.extraIncludePath
}

func (f *SourceFile) SourcePath(ctx *Context) *paths.Path {
return sourceRoot(ctx, f.Origin).JoinPath(f.RelativePath)
func (f *SourceFile) SourcePath() *paths.Path {
return f.sourceRoot.JoinPath(f.relativePath)
}

func (f *SourceFile) ObjectPath(ctx *Context) *paths.Path {
return buildRoot(ctx, f.Origin).Join(f.RelativePath.String() + ".o")
func (f *SourceFile) ObjectPath() *paths.Path {
return f.buildRoot.Join(f.relativePath.String() + ".o")
}

func (f *SourceFile) DepfilePath(ctx *Context) *paths.Path {
return buildRoot(ctx, f.Origin).Join(f.RelativePath.String() + ".d")
func (f *SourceFile) DepfilePath() *paths.Path {
return f.buildRoot.Join(f.relativePath.String() + ".d")
}

type LibraryResolutionResult struct {
Expand Down