diff --git a/arduino/builder/compilation_database.go b/arduino/builder/compilation/database.go similarity index 72% rename from arduino/builder/compilation_database.go rename to arduino/builder/compilation/database.go index 6a7e2e475dd..f6a6b1ab5f0 100644 --- a/arduino/builder/compilation_database.go +++ b/arduino/builder/compilation/database.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package builder +package compilation import ( "encoding/json" @@ -21,44 +21,47 @@ import ( "os" "github.com/arduino/arduino-cli/executils" + "github.com/arduino/arduino-cli/i18n" "github.com/arduino/go-paths-helper" ) -// CompilationDatabase keeps track of all the compile commands run by the builder -type CompilationDatabase struct { - Contents []CompilationCommand +var tr = i18n.Tr + +// Database keeps track of all the compile commands run by the builder +type Database struct { + Contents []Command File *paths.Path } -// CompilationCommand keeps track of a single run of a compile command -type CompilationCommand struct { +// Command keeps track of a single run of a compile command +type Command struct { Directory string `json:"directory"` Command string `json:"command,omitempty"` Arguments []string `json:"arguments,omitempty"` File string `json:"file"` } -// NewCompilationDatabase creates an empty CompilationDatabase -func NewCompilationDatabase(filename *paths.Path) *CompilationDatabase { - return &CompilationDatabase{ +// NewDatabase creates an empty CompilationDatabase +func NewDatabase(filename *paths.Path) *Database { + return &Database{ File: filename, - Contents: []CompilationCommand{}, + Contents: []Command{}, } } -// LoadCompilationDatabase reads a compilation database from a file -func LoadCompilationDatabase(file *paths.Path) (*CompilationDatabase, error) { +// LoadDatabase reads a compilation database from a file +func LoadDatabase(file *paths.Path) (*Database, error) { f, err := file.ReadFile() if err != nil { return nil, err } - res := NewCompilationDatabase(file) + res := NewDatabase(file) return res, json.Unmarshal(f, &res.Contents) } // SaveToFile save the CompilationDatabase to file as a clangd-compatible compile_commands.json, // see https://clang.llvm.org/docs/JSONCompilationDatabase.html -func (db *CompilationDatabase) SaveToFile() { +func (db *Database) SaveToFile() { if jsonContents, err := json.MarshalIndent(db.Contents, "", " "); err != nil { fmt.Println(tr("Error serializing compilation database: %s", err)) return @@ -68,7 +71,7 @@ func (db *CompilationDatabase) SaveToFile() { } // Add adds a new CompilationDatabase entry -func (db *CompilationDatabase) Add(target *paths.Path, command *executils.Process) { +func (db *Database) Add(target *paths.Path, command *executils.Process) { commandDir := command.GetDir() if commandDir == "" { // This mimics what Cmd.Run also does: Use Dir if specified, @@ -80,7 +83,7 @@ func (db *CompilationDatabase) Add(target *paths.Path, command *executils.Proces commandDir = dir } - entry := CompilationCommand{ + entry := Command{ Directory: commandDir, Arguments: command.GetArgs(), File: target.String(), diff --git a/arduino/builder/compilation_database_test.go b/arduino/builder/compilation/database_test.go similarity index 93% rename from arduino/builder/compilation_database_test.go rename to arduino/builder/compilation/database_test.go index 8a715533617..26badfc6cb2 100644 --- a/arduino/builder/compilation_database_test.go +++ b/arduino/builder/compilation/database_test.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package builder +package compilation import ( "testing" @@ -30,11 +30,11 @@ func TestCompilationDatabase(t *testing.T) { cmd, err := executils.NewProcess(nil, "gcc", "arg1", "arg2") require.NoError(t, err) - db := NewCompilationDatabase(tmpfile) + db := NewDatabase(tmpfile) db.Add(paths.New("test"), cmd) db.SaveToFile() - db2, err := LoadCompilationDatabase(tmpfile) + db2, err := LoadDatabase(tmpfile) require.NoError(t, err) require.Equal(t, db, db2) require.Len(t, db2.Contents, 1) diff --git a/arduino/builder/core.go b/arduino/builder/core.go index c4d096f6f27..9bec697cb96 100644 --- a/arduino/builder/core.go +++ b/arduino/builder/core.go @@ -1,8 +1,222 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package builder -import "github.com/arduino/go-paths-helper" +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "os" + "strings" + + "github.com/arduino/arduino-cli/arduino/builder/compilation" + "github.com/arduino/arduino-cli/arduino/builder/cpp" + "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/builder/progress" + "github.com/arduino/arduino-cli/arduino/builder/utils" + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/buildcache" + f "github.com/arduino/arduino-cli/internal/algorithms" + rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/pkg/errors" +) // CoreBuildCachePath fixdoc func (b *Builder) CoreBuildCachePath() *paths.Path { return b.coreBuildCachePath } + +// CoreBuilder fixdoc +func CoreBuilder( + buildPath, coreBuildPath, coreBuildCachePath *paths.Path, + buildProperties *properties.Map, + actualPlatform *cores.PlatformRelease, + onlyUpdateCompilationDatabase, clean bool, + compilationDatabase *compilation.Database, + jobs int, + builderLogger *logger.BuilderLogger, + progress *progress.Struct, progressCB rpc.TaskProgressCB, +) (paths.PathList, *paths.Path, error) { + if err := coreBuildPath.MkdirAll(); err != nil { + return nil, nil, errors.WithStack(err) + } + + if coreBuildCachePath != nil { + if _, err := coreBuildCachePath.RelTo(buildPath); err != nil { + builderLogger.Info(tr("Couldn't deeply cache core build: %[1]s", err)) + builderLogger.Info(tr("Running normal build of the core...")) + coreBuildCachePath = nil + } else if err := coreBuildCachePath.MkdirAll(); err != nil { + return nil, nil, errors.WithStack(err) + } + } + + archiveFile, objectFiles, err := compileCore( + onlyUpdateCompilationDatabase, clean, + actualPlatform, + coreBuildPath, coreBuildCachePath, + buildProperties, + compilationDatabase, + jobs, + builderLogger, + progress, progressCB, + ) + if err != nil { + return nil, nil, errors.WithStack(err) + } + + return objectFiles, archiveFile, nil +} + +func compileCore( + onlyUpdateCompilationDatabase, clean bool, + actualPlatform *cores.PlatformRelease, + buildPath, buildCachePath *paths.Path, + buildProperties *properties.Map, + compilationDatabase *compilation.Database, + jobs int, + builderLogger *logger.BuilderLogger, + progress *progress.Struct, progressCB rpc.TaskProgressCB, +) (*paths.Path, paths.PathList, error) { + coreFolder := buildProperties.GetPath("build.core.path") + variantFolder := buildProperties.GetPath("build.variant.path") + targetCoreFolder := buildProperties.GetPath("runtime.platform.path") + + includes := []string{coreFolder.String()} + if variantFolder != nil && variantFolder.IsDir() { + includes = append(includes, variantFolder.String()) + } + includes = f.Map(includes, cpp.WrapWithHyphenI) + + var err error + variantObjectFiles := paths.NewPathList() + if variantFolder != nil && variantFolder.IsDir() { + variantObjectFiles, err = utils.CompileFilesRecursive( + variantFolder, buildPath, buildProperties, includes, + onlyUpdateCompilationDatabase, + compilationDatabase, + jobs, + builderLogger, + progress, progressCB, + ) + if err != nil { + return nil, nil, errors.WithStack(err) + } + } + + var targetArchivedCore *paths.Path + if buildCachePath != nil { + realCoreFolder := coreFolder.Parent().Parent() + archivedCoreName := GetCachedCoreArchiveDirName( + buildProperties.Get("build.fqbn"), + buildProperties.Get("compiler.optimization_flags"), + realCoreFolder, + ) + targetArchivedCore = buildCachePath.Join(archivedCoreName, "core.a") + + if _, err := buildcache.New(buildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) { + return nil, nil, fmt.Errorf(tr("creating core cache folder: %s", err)) + } + + var canUseArchivedCore bool + if onlyUpdateCompilationDatabase || clean { + canUseArchivedCore = false + } else if isOlder, err := utils.DirContentIsOlderThan(realCoreFolder, targetArchivedCore); err != nil || !isOlder { + // Recreate the archive if ANY of the core files (including platform.txt) has changed + canUseArchivedCore = false + } else if targetCoreFolder == nil || realCoreFolder.EquivalentTo(targetCoreFolder) { + canUseArchivedCore = true + } else if isOlder, err := utils.DirContentIsOlderThan(targetCoreFolder, targetArchivedCore); err != nil || !isOlder { + // Recreate the archive if ANY of the build core files (including platform.txt) has changed + canUseArchivedCore = false + } else { + canUseArchivedCore = true + } + + if canUseArchivedCore { + // use archived core + if builderLogger.Verbose() { + builderLogger.Info(tr("Using precompiled core: %[1]s", targetArchivedCore)) + } + return targetArchivedCore, variantObjectFiles, nil + } + } + + coreObjectFiles, err := utils.CompileFilesRecursive( + coreFolder, buildPath, buildProperties, includes, + onlyUpdateCompilationDatabase, + compilationDatabase, + jobs, + builderLogger, + progress, progressCB, + ) + if err != nil { + return nil, nil, errors.WithStack(err) + } + + archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles( + buildPath, paths.New("core.a"), coreObjectFiles, buildProperties, + onlyUpdateCompilationDatabase, builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), + ) + if builderLogger.Verbose() { + builderLogger.Info(string(verboseInfo)) + } + if err != nil { + return nil, nil, errors.WithStack(err) + } + + // archive core.a + if targetArchivedCore != nil && !onlyUpdateCompilationDatabase { + err := archiveFile.CopyTo(targetArchivedCore) + if builderLogger.Verbose() { + if err == nil { + builderLogger.Info(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore)) + } else if os.IsNotExist(err) { + builderLogger.Info(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s", + actualPlatform, + "https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-build-the-corea-archive-file")) + } else { + builderLogger.Info(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err)) + } + } + } + + return archiveFile, variantObjectFiles, nil +} + +// GetCachedCoreArchiveDirName returns the directory name to be used to store +// the global cached core.a. +func GetCachedCoreArchiveDirName(fqbn string, optimizationFlags string, coreFolder *paths.Path) string { + fqbnToUnderscore := strings.ReplaceAll(fqbn, ":", "_") + fqbnToUnderscore = strings.ReplaceAll(fqbnToUnderscore, "=", "_") + if absCoreFolder, err := coreFolder.Abs(); err == nil { + coreFolder = absCoreFolder + } // silently continue if absolute path can't be detected + + md5Sum := func(data []byte) string { + md5sumBytes := md5.Sum(data) + return hex.EncodeToString(md5sumBytes[:]) + } + hash := md5Sum([]byte(coreFolder.String() + optimizationFlags)) + realName := fqbnToUnderscore + "_" + hash + if len(realName) > 100 { + // avoid really long names, simply hash the name again + realName = md5Sum([]byte(realName)) + } + return realName +} diff --git a/arduino/builder/detector/detector.go b/arduino/builder/detector/detector.go index 5543236f18d..1de2017d773 100644 --- a/arduino/builder/detector/detector.go +++ b/arduino/builder/detector/detector.go @@ -26,6 +26,7 @@ import ( "golang.org/x/exp/slices" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/preprocessor" "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/cores" @@ -52,41 +53,30 @@ type SketchLibrariesDetector struct { librariesManager *librariesmanager.LibrariesManager librariesResolver *librariesresolver.Cpp useCachedLibrariesResolution bool - verbose bool onlyUpdateCompilationDatabase bool - verboseInfoFn func(msg string) - verboseWarnFn func(msg string) - verboseStdoutFn func(data []byte) - verboseStderrFn func(data []byte) importedLibraries libraries.List librariesResolutionResults map[string]libraryResolutionResult includeFolders paths.PathList + logger *logger.BuilderLogger } // NewSketchLibrariesDetector todo func NewSketchLibrariesDetector( lm *librariesmanager.LibrariesManager, libsResolver *librariesresolver.Cpp, - verbose, useCachedLibrariesResolution bool, + useCachedLibrariesResolution bool, onlyUpdateCompilationDatabase bool, - verboseInfoFn func(msg string), - verboseWarnFn func(msg string), - verboseStdoutFn func(data []byte), - verboseStderrFn func(data []byte), + logger *logger.BuilderLogger, ) *SketchLibrariesDetector { return &SketchLibrariesDetector{ librariesManager: lm, librariesResolver: libsResolver, useCachedLibrariesResolution: useCachedLibrariesResolution, librariesResolutionResults: map[string]libraryResolutionResult{}, - verbose: verbose, - verboseInfoFn: verboseInfoFn, - verboseWarnFn: verboseWarnFn, - verboseStdoutFn: verboseStdoutFn, - verboseStderrFn: verboseStderrFn, importedLibraries: libraries.List{}, includeFolders: paths.PathList{}, onlyUpdateCompilationDatabase: onlyUpdateCompilationDatabase, + logger: logger, } } @@ -95,10 +85,10 @@ func (l *SketchLibrariesDetector) resolveLibrary(header, platformArch string) *l importedLibraries := l.importedLibraries candidates := l.librariesResolver.AlternativesFor(header) - if l.verbose { - l.verboseInfoFn(tr("Alternatives for %[1]s: %[2]s", header, candidates)) - l.verboseInfoFn(fmt.Sprintf("ResolveLibrary(%s)", header)) - l.verboseInfoFn(fmt.Sprintf(" -> %s: %s", tr("candidates"), candidates)) + if l.logger.Verbose() { + l.logger.Info(tr("Alternatives for %[1]s: %[2]s", header, candidates)) + l.logger.Info(fmt.Sprintf("ResolveLibrary(%s)", header)) + l.logger.Info(fmt.Sprintf(" -> %s: %s", tr("candidates"), candidates)) } if len(candidates) == 0 { @@ -152,7 +142,7 @@ func (l *SketchLibrariesDetector) PrintUsedAndNotUsedLibraries(sketchError bool) // - as warning, when the sketch didn't compile // - as info, when verbose is on // - otherwise, output nothing - if !sketchError && !l.verbose { + if !sketchError && !l.logger.Verbose() { return } @@ -169,9 +159,9 @@ func (l *SketchLibrariesDetector) PrintUsedAndNotUsedLibraries(sketchError bool) } res = strings.TrimSpace(res) if sketchError { - l.verboseWarnFn(res) + l.logger.Warn(res) } else { - l.verboseInfoFn(res) + l.logger.Info(res) } // todo why?? should we remove this? time.Sleep(100 * time.Millisecond) @@ -214,7 +204,7 @@ func (l *SketchLibrariesDetector) FindIncludes( ) error { err := l.findIncludes(buildPath, buildCorePath, buildVariantPath, sketchBuildPath, sketch, librariesBuildPath, buildProperties, platformArch) if err != nil && l.onlyUpdateCompilationDatabase { - l.verboseInfoFn( + l.logger.Info( fmt.Sprintf( "%s: %s", tr("An error occurred detecting libraries"), @@ -246,8 +236,8 @@ func (l *SketchLibrariesDetector) findIncludes( if err := json.Unmarshal(d, &includeFolders); err != nil { return err } - if l.verbose { - l.verboseInfoFn("Using cached library discovery: " + librariesResolutionCache.String()) + if l.logger.Verbose() { + l.logger.Info("Using cached library discovery: " + librariesResolutionCache.String()) } return nil } @@ -354,14 +344,14 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( var missingIncludeH string if unchanged && cache.valid { missingIncludeH = cache.Next().Include - if first && l.verbose { - l.verboseInfoFn(tr("Using cached library dependencies for file: %[1]s", sourcePath)) + if first && l.logger.Verbose() { + l.logger.Info(tr("Using cached library dependencies for file: %[1]s", sourcePath)) } } else { var preprocStdout []byte preprocStdout, preprocStderr, preprocErr = preprocessor.GCC(sourcePath, targetFilePath, includeFolders, buildProperties) - if l.verbose { - l.verboseStdoutFn(preprocStdout) + if l.logger.Verbose() { + l.logger.WriteStdout(preprocStdout) } // Unwrap error and see if it is an ExitError. if preprocErr == nil { @@ -372,8 +362,8 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( return errors.WithStack(preprocErr) } else { missingIncludeH = IncludesFinderWithRegExp(string(preprocStderr)) - if missingIncludeH == "" && l.verbose { - l.verboseInfoFn(tr("Error while detecting libraries included by %[1]s", sourcePath)) + if missingIncludeH == "" && l.logger.Verbose() { + l.logger.Info(tr("Error while detecting libraries included by %[1]s", sourcePath)) } } } @@ -391,8 +381,8 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( // Filename came from cache, so run preprocessor to obtain error to show var preprocStdout []byte preprocStdout, preprocStderr, preprocErr = preprocessor.GCC(sourcePath, targetFilePath, includeFolders, buildProperties) - if l.verbose { - l.verboseStdoutFn(preprocStdout) + if l.logger.Verbose() { + l.logger.WriteStdout(preprocStdout) } if preprocErr == nil { // If there is a missing #include in the cache, but running @@ -402,7 +392,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( return errors.New(tr("Internal error in cache")) } } - l.verboseStderrFn(preprocStderr) + l.logger.WriteStderr(preprocStderr) return errors.WithStack(preprocErr) } @@ -414,8 +404,8 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( if library.Precompiled && library.PrecompiledWithSources { // Fully precompiled libraries should have no dependencies to avoid ABI breakage - if l.verbose { - l.verboseInfoFn(tr("Skipping dependencies detection for precompiled library %[1]s", library.Name)) + if l.logger.Verbose() { + l.logger.Info(tr("Skipping dependencies detection for precompiled library %[1]s", library.Name)) } } else { for _, sourceDir := range library.SourceDirs() { diff --git a/legacy/builder/phases/libraries_builder.go b/arduino/builder/libraries.go similarity index 76% rename from legacy/builder/phases/libraries_builder.go rename to arduino/builder/libraries.go index 9bd03c95f0a..af2e899840d 100644 --- a/legacy/builder/phases/libraries_builder.go +++ b/arduino/builder/libraries.go @@ -13,14 +13,14 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package phases +package builder import ( - "io" "strings" - "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/cpp" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/libraries" @@ -31,21 +31,22 @@ import ( "github.com/pkg/errors" ) -var FLOAT_ABI_CFLAG = "float-abi" -var FPU_CFLAG = "fpu" +// nolint +var ( + FloatAbiCflag = "float-abi" + FpuCflag = "fpu" +) +// LibrariesBuilder fixdoc func LibrariesBuilder( librariesBuildPath *paths.Path, buildProperties *properties.Map, includesFolders paths.PathList, importedLibraries libraries.List, - verbose, onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + onlyUpdateCompilationDatabase bool, + compilationDatabase *compilation.Database, jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { includes := f.Map(includesFolders.AsStrings(), cpp.WrapWithHyphenI) @@ -57,13 +58,10 @@ func LibrariesBuilder( librariesObjectFiles, err := compileLibraries( libs, librariesBuildPath, buildProperties, includes, - verbose, onlyUpdateCompilationDatabase, + onlyUpdateCompilationDatabase, compilationDatabase, jobs, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, - verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) if err != nil { @@ -84,7 +82,7 @@ func directoryContainsFile(folder *paths.Path) bool { func findExpectedPrecompiledLibFolder( library *libraries.Library, buildProperties *properties.Map, - verboseInfoFn func(msg string), + builderLogger *logger.BuilderLogger, ) *paths.Path { mcu := buildProperties.Get("build.mcu") // Add fpu specifications if they exist @@ -93,7 +91,7 @@ func findExpectedPrecompiledLibFolder( command, _ := utils.PrepareCommandForRecipe(buildProperties, "recipe.cpp.o.pattern", true) fpuSpecs := "" for _, el := range command.GetArgs() { - if strings.Contains(el, FPU_CFLAG) { + if strings.Contains(el, FpuCflag) { toAdd := strings.Split(el, "=") if len(toAdd) > 1 { fpuSpecs += strings.TrimSpace(toAdd[1]) + "-" @@ -102,7 +100,7 @@ func findExpectedPrecompiledLibFolder( } } for _, el := range command.GetArgs() { - if strings.Contains(el, FLOAT_ABI_CFLAG) { + if strings.Contains(el, FloatAbiCflag) { toAdd := strings.Split(el, "=") if len(toAdd) > 1 { fpuSpecs += strings.TrimSpace(toAdd[1]) + "-" @@ -111,37 +109,34 @@ func findExpectedPrecompiledLibFolder( } } - verboseInfoFn(tr("Library %[1]s has been declared precompiled:", library.Name)) + builderLogger.Info(tr("Library %[1]s has been declared precompiled:", library.Name)) // Try directory with full fpuSpecs first, if available if len(fpuSpecs) > 0 { fpuSpecs = strings.TrimRight(fpuSpecs, "-") fullPrecompDir := library.SourceDir.Join(mcu).Join(fpuSpecs) if fullPrecompDir.Exist() && directoryContainsFile(fullPrecompDir) { - verboseInfoFn(tr("Using precompiled library in %[1]s", fullPrecompDir)) + builderLogger.Info(tr("Using precompiled library in %[1]s", fullPrecompDir)) return fullPrecompDir } - verboseInfoFn(tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir)) + builderLogger.Info(tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir)) } precompDir := library.SourceDir.Join(mcu) if precompDir.Exist() && directoryContainsFile(precompDir) { - verboseInfoFn(tr("Using precompiled library in %[1]s", precompDir)) + builderLogger.Info(tr("Using precompiled library in %[1]s", precompDir)) return precompDir } - verboseInfoFn(tr(`Precompiled library in "%[1]s" not found`, precompDir)) + builderLogger.Info(tr(`Precompiled library in "%[1]s" not found`, precompDir)) return nil } func compileLibraries( libraries libraries.List, buildPath *paths.Path, buildProperties *properties.Map, includes []string, - verbose, onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + onlyUpdateCompilationDatabase bool, + compilationDatabase *compilation.Database, jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { progress.AddSubSteps(len(libraries)) @@ -151,12 +146,10 @@ func compileLibraries( for _, library := range libraries { libraryObjectFiles, err := compileLibrary( library, buildPath, buildProperties, includes, - verbose, onlyUpdateCompilationDatabase, + onlyUpdateCompilationDatabase, compilationDatabase, jobs, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) if err != nil { @@ -179,17 +172,14 @@ func compileLibraries( func compileLibrary( library *libraries.Library, buildPath *paths.Path, buildProperties *properties.Map, includes []string, - verbose, onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + onlyUpdateCompilationDatabase bool, + compilationDatabase *compilation.Database, jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { - if verbose { - verboseInfoFn(tr(`Compiling library "%[1]s"`, library.Name)) + if builderLogger.Verbose() { + builderLogger.Info(tr(`Compiling library "%[1]s"`, library.Name)) } libraryBuildPath := buildPath.Join(library.DirName) @@ -204,11 +194,11 @@ func compileLibrary( precompiledPath := findExpectedPrecompiledLibFolder( library, buildProperties, - verboseInfoFn, + builderLogger, ) if !coreSupportPrecompiled { - verboseInfoFn(tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags")) + builderLogger.Info(tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags")) } else if precompiledPath != nil { // Find all libraries in precompiledPath libs, err := precompiledPath.ReadDir() @@ -253,10 +243,7 @@ func compileLibrary( onlyUpdateCompilationDatabase, compilationDatabase, jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) if err != nil { @@ -265,11 +252,11 @@ func compileLibrary( if library.DotALinkage { archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles( libraryBuildPath, paths.New(library.DirName+".a"), libObjectFiles, buildProperties, - onlyUpdateCompilationDatabase, verbose, - stdoutWriter, stderrWriter, + onlyUpdateCompilationDatabase, builderLogger.Verbose(), + builderLogger.Stdout(), builderLogger.Stderr(), ) - if verbose { - verboseInfoFn(string(verboseInfo)) + if builderLogger.Verbose() { + builderLogger.Info(string(verboseInfo)) } if err != nil { return nil, errors.WithStack(err) @@ -287,10 +274,7 @@ func compileLibrary( onlyUpdateCompilationDatabase, compilationDatabase, jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) if err != nil { @@ -305,10 +289,7 @@ func compileLibrary( onlyUpdateCompilationDatabase, compilationDatabase, jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) if err != nil { diff --git a/legacy/builder/phases/linker.go b/arduino/builder/linker.go similarity index 83% rename from legacy/builder/phases/linker.go rename to arduino/builder/linker.go index f0c1f46e2f9..528e159d0aa 100644 --- a/legacy/builder/phases/linker.go +++ b/arduino/builder/linker.go @@ -13,13 +13,13 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package phases +package builder import ( "bytes" - "io" "strings" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" f "github.com/arduino/arduino-cli/internal/algorithms" "github.com/arduino/go-paths-helper" @@ -27,17 +27,17 @@ import ( "github.com/pkg/errors" ) +// Linker fixdoc func Linker( - onlyUpdateCompilationDatabase, verbose bool, + onlyUpdateCompilationDatabase bool, sketchObjectFiles, librariesObjectFiles, coreObjectsFiles paths.PathList, coreArchiveFilePath, buildPath *paths.Path, buildProperties *properties.Map, - stdoutWriter, stderrWriter io.Writer, - warningsLevel string, + builderLogger *logger.BuilderLogger, ) ([]byte, error) { verboseInfo := &bytes.Buffer{} if onlyUpdateCompilationDatabase { - if verbose { + if builderLogger.Verbose() { verboseInfo.WriteString(tr("Skip linking of final executable.")) } return verboseInfo.Bytes(), nil @@ -57,10 +57,7 @@ func Linker( return nil, errors.WithStack(err) } - verboseInfoOut, err := link( - objectFiles, coreDotARelPath, coreArchiveFilePath, buildProperties, - verbose, stdoutWriter, stderrWriter, warningsLevel, - ) + verboseInfoOut, err := link(objectFiles, coreDotARelPath, coreArchiveFilePath, buildProperties, builderLogger) verboseInfo.Write(verboseInfoOut) if err != nil { return verboseInfo.Bytes(), errors.WithStack(err) @@ -71,9 +68,7 @@ func Linker( func link( objectFiles paths.PathList, coreDotARelPath *paths.Path, coreArchiveFilePath *paths.Path, buildProperties *properties.Map, - verbose bool, - stdoutWriter, stderrWriter io.Writer, - warningsLevel string, + builderLogger *logger.BuilderLogger, ) ([]byte, error) { verboseBuffer := &bytes.Buffer{} wrapWithDoubleQuotes := func(value string) string { return "\"" + value + "\"" } @@ -110,8 +105,8 @@ func link( return nil, errors.WithStack(err) } - if verboseInfo, _, _, err := utils.ExecCommand(verbose, stdoutWriter, stderrWriter, command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */); err != nil { - if verbose { + if verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */); err != nil { + if builderLogger.Verbose() { verboseBuffer.WriteString(string(verboseInfo)) } return verboseBuffer.Bytes(), errors.WithStack(err) @@ -124,7 +119,7 @@ func link( properties := buildProperties.Clone() properties.Set("compiler.c.elf.flags", properties.Get("compiler.c.elf.flags")) - properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+warningsLevel)) + properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+builderLogger.WarningsLevel())) properties.Set("archive_file", coreDotARelPath.String()) properties.Set("archive_file_path", coreArchiveFilePath.String()) properties.Set("object_files", objectFileList) @@ -134,8 +129,8 @@ func link( return verboseBuffer.Bytes(), err } - verboseInfo, _, _, err := utils.ExecCommand(verbose, stdoutWriter, stderrWriter, command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) - if verbose { + verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) + if builderLogger.Verbose() { verboseBuffer.WriteString(string(verboseInfo)) } return verboseBuffer.Bytes(), err diff --git a/arduino/builder/logger/logger.go b/arduino/builder/logger/logger.go new file mode 100644 index 00000000000..992c15a25b2 --- /dev/null +++ b/arduino/builder/logger/logger.go @@ -0,0 +1,100 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package logger + +import ( + "fmt" + "io" + "os" + "sync" +) + +// BuilderLogger fixdoc +type BuilderLogger struct { + stdLock sync.Mutex + stdout io.Writer + stderr io.Writer + + verbose bool + warningsLevel string +} + +// New fixdoc +func New(stdout, stderr io.Writer, verbose bool, warningsLevel string) *BuilderLogger { + if stdout == nil { + stdout = os.Stdout + } + if stderr == nil { + stderr = os.Stderr + } + if warningsLevel == "" { + warningsLevel = "none" + } + return &BuilderLogger{ + stdout: stdout, + stderr: stderr, + verbose: verbose, + warningsLevel: warningsLevel, + } +} + +// Info fixdoc +func (l *BuilderLogger) Info(msg string) { + l.stdLock.Lock() + defer l.stdLock.Unlock() + fmt.Fprintln(l.stdout, msg) +} + +// Warn fixdoc +func (l *BuilderLogger) Warn(msg string) { + l.stdLock.Lock() + defer l.stdLock.Unlock() + fmt.Fprintln(l.stderr, msg) +} + +// WriteStdout fixdoc +func (l *BuilderLogger) WriteStdout(data []byte) (int, error) { + l.stdLock.Lock() + defer l.stdLock.Unlock() + return l.stdout.Write(data) +} + +// WriteStderr fixdoc +func (l *BuilderLogger) WriteStderr(data []byte) (int, error) { + l.stdLock.Lock() + defer l.stdLock.Unlock() + return l.stderr.Write(data) +} + +// Verbose fixdoc +func (l *BuilderLogger) Verbose() bool { + return l.verbose +} + +// WarningsLevel fixdoc +func (l *BuilderLogger) WarningsLevel() string { + return l.warningsLevel +} + +// Stdout fixdoc +func (l *BuilderLogger) Stdout() io.Writer { + return l.stdout +} + +// Stderr fixdoc +func (l *BuilderLogger) Stderr() io.Writer { + return l.stderr +} diff --git a/arduino/builder/progress/progress.go b/arduino/builder/progress/progress.go index 53a64e803bf..2bdfaeb7539 100644 --- a/arduino/builder/progress/progress.go +++ b/arduino/builder/progress/progress.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package progress // Struct fixdoc diff --git a/arduino/builder/sizer.go b/arduino/builder/sizer.go deleted file mode 100644 index 911f261af67..00000000000 --- a/arduino/builder/sizer.go +++ /dev/null @@ -1,26 +0,0 @@ -package builder - -import rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - -// ExecutableSectionSize represents a section of the executable output file -type ExecutableSectionSize struct { - Name string `json:"name"` - Size int `json:"size"` - MaxSize int `json:"max_size"` -} - -// ExecutablesFileSections is an array of ExecutablesFileSection -type ExecutablesFileSections []ExecutableSectionSize - -// ToRPCExecutableSectionSizeArray transforms this array into a []*rpc.ExecutableSectionSize -func (s ExecutablesFileSections) ToRPCExecutableSectionSizeArray() []*rpc.ExecutableSectionSize { - res := []*rpc.ExecutableSectionSize{} - for _, section := range s { - res = append(res, &rpc.ExecutableSectionSize{ - Name: section.Name, - Size: int64(section.Size), - MaxSize: int64(section.MaxSize), - }) - } - return res -} diff --git a/legacy/builder/phases/sizer.go b/arduino/builder/sizer/sizer.go similarity index 62% rename from legacy/builder/phases/sizer.go rename to arduino/builder/sizer/sizer.go index cfc28f987c1..7533a8d740e 100644 --- a/legacy/builder/phases/sizer.go +++ b/arduino/builder/sizer/sizer.go @@ -13,52 +13,73 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package phases +package sizer import ( "encoding/json" "fmt" - "io" "regexp" "strconv" - "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" + "github.com/arduino/arduino-cli/i18n" + rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" ) -func Sizer( - onlyUpdateCompilationDatabase, sketchError, verbose bool, +var tr = i18n.Tr + +// ExecutableSectionSize represents a section of the executable output file +type ExecutableSectionSize struct { + Name string `json:"name"` + Size int `json:"size"` + MaxSize int `json:"max_size"` +} + +// ExecutablesFileSections is an array of ExecutablesFileSection +type ExecutablesFileSections []ExecutableSectionSize + +// ToRPCExecutableSectionSizeArray transforms this array into a []*rpc.ExecutableSectionSize +func (s ExecutablesFileSections) ToRPCExecutableSectionSizeArray() []*rpc.ExecutableSectionSize { + res := []*rpc.ExecutableSectionSize{} + for _, section := range s { + res = append(res, &rpc.ExecutableSectionSize{ + Name: section.Name, + Size: int64(section.Size), + MaxSize: int64(section.MaxSize), + }) + } + return res +} + +// Size fixdoc +func Size( + onlyUpdateCompilationDatabase, sketchError bool, buildProperties *properties.Map, - stdoutWriter, stderrWriter io.Writer, - printInfoFn, printWarnFn func(msg string), - warningsLevel string, -) (builder.ExecutablesFileSections, error) { + builderLogger *logger.BuilderLogger, +) (ExecutablesFileSections, error) { if onlyUpdateCompilationDatabase || sketchError { return nil, nil } if buildProperties.ContainsKey("recipe.advanced_size.pattern") { - return checkSizeAdvanced(buildProperties, verbose, stdoutWriter, stderrWriter, printInfoFn, printWarnFn) + return checkSizeAdvanced(buildProperties, builderLogger) } - return checkSize(buildProperties, verbose, stdoutWriter, stderrWriter, printInfoFn, printWarnFn, warningsLevel) + return checkSize(buildProperties, builderLogger) } -func checkSizeAdvanced(buildProperties *properties.Map, - verbose bool, - stdoutWriter, stderrWriter io.Writer, - printInfoFn, printWarnFn func(msg string), -) (builder.ExecutablesFileSections, error) { +func checkSizeAdvanced(buildProperties *properties.Map, builderLogger *logger.BuilderLogger) (ExecutablesFileSections, error) { command, err := utils.PrepareCommandForRecipe(buildProperties, "recipe.advanced_size.pattern", false) if err != nil { return nil, errors.New(tr("Error while determining sketch size: %s", err)) } - verboseInfo, out, _, err := utils.ExecCommand(verbose, stdoutWriter, stderrWriter, command, utils.Capture /* stdout */, utils.Show /* stderr */) - if verbose { - printInfoFn(string(verboseInfo)) + verboseInfo, out, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) + if builderLogger.Verbose() { + builderLogger.Info(string(verboseInfo)) } if err != nil { return nil, errors.New(tr("Error while determining sketch size: %s", err)) @@ -71,7 +92,7 @@ func checkSizeAdvanced(buildProperties *properties.Map, // likely be printed in red. Errors will stop build/upload. Severity string `json:"severity"` // Sections are the sections sizes for machine readable use - Sections []builder.ExecutableSectionSize `json:"sections"` + Sections []ExecutableSectionSize `json:"sections"` // ErrorMessage is a one line error message like: // "text section exceeds available space in board" // it must be set when Severity is "error" @@ -86,26 +107,21 @@ func checkSizeAdvanced(buildProperties *properties.Map, executableSectionsSize := resp.Sections switch resp.Severity { case "error": - printWarnFn(resp.Output) + builderLogger.Warn(resp.Output) return executableSectionsSize, errors.New(resp.ErrorMessage) case "warning": - printWarnFn(resp.Output) + builderLogger.Warn(resp.Output) case "info": - printInfoFn(resp.Output) + builderLogger.Info(resp.Output) default: return executableSectionsSize, fmt.Errorf("invalid '%s' severity from sketch sizer: it must be 'error', 'warning' or 'info'", resp.Severity) } return executableSectionsSize, nil } -func checkSize(buildProperties *properties.Map, - verbose bool, - stdoutWriter, stderrWriter io.Writer, - printInfoFn, printWarnFn func(msg string), - warningsLevel string, -) (builder.ExecutablesFileSections, error) { +func checkSize(buildProperties *properties.Map, builderLogger *logger.BuilderLogger) (ExecutablesFileSections, error) { properties := buildProperties.Clone() - properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+warningsLevel)) + properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+builderLogger.WarningsLevel())) maxTextSizeString := properties.Get("upload.maximum_size") maxDataSizeString := properties.Get("upload.maximum_data_size") @@ -127,29 +143,29 @@ func checkSize(buildProperties *properties.Map, } } - textSize, dataSize, _, err := execSizeRecipe(properties, verbose, stdoutWriter, stderrWriter, printInfoFn) + textSize, dataSize, _, err := execSizeRecipe(properties, builderLogger) if err != nil { - printWarnFn(tr("Couldn't determine program size")) + builderLogger.Warn(tr("Couldn't determine program size")) return nil, nil } - printInfoFn(tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.", + builderLogger.Info(tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.", strconv.Itoa(textSize), strconv.Itoa(maxTextSize), strconv.Itoa(textSize*100/maxTextSize))) if dataSize >= 0 { if maxDataSize > 0 { - printInfoFn(tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.", + builderLogger.Info(tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.", strconv.Itoa(dataSize), strconv.Itoa(maxDataSize), strconv.Itoa(dataSize*100/maxDataSize), strconv.Itoa(maxDataSize-dataSize))) } else { - printInfoFn(tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize))) + builderLogger.Info(tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize))) } } - executableSectionsSize := []builder.ExecutableSectionSize{ + executableSectionsSize := []ExecutableSectionSize{ { Name: "text", Size: textSize, @@ -157,7 +173,7 @@ func checkSize(buildProperties *properties.Map, }, } if maxDataSize > 0 { - executableSectionsSize = append(executableSectionsSize, builder.ExecutableSectionSize{ + executableSectionsSize = append(executableSectionsSize, ExecutableSectionSize{ Name: "data", Size: dataSize, MaxSize: maxDataSize, @@ -165,12 +181,12 @@ func checkSize(buildProperties *properties.Map, } if textSize > maxTextSize { - printWarnFn(tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) + builderLogger.Warn(tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) return executableSectionsSize, errors.New(tr("text section exceeds available space in board")) } if maxDataSize > 0 && dataSize > maxDataSize { - printWarnFn(tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) + builderLogger.Warn(tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) return executableSectionsSize, errors.New(tr("data section exceeds available space in board")) } @@ -180,27 +196,23 @@ func checkSize(buildProperties *properties.Map, return executableSectionsSize, err } if maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100 { - printWarnFn(tr("Low memory available, stability problems may occur.")) + builderLogger.Warn(tr("Low memory available, stability problems may occur.")) } } return executableSectionsSize, nil } -func execSizeRecipe(properties *properties.Map, - verbose bool, - stdoutWriter, stderrWriter io.Writer, - printInfoFn func(msg string), -) (textSize int, dataSize int, eepromSize int, resErr error) { +func execSizeRecipe(properties *properties.Map, builderLogger *logger.BuilderLogger) (textSize int, dataSize int, eepromSize int, resErr error) { command, err := utils.PrepareCommandForRecipe(properties, "recipe.size.pattern", false) if err != nil { resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err) return } - verboseInfo, out, _, err := utils.ExecCommand(verbose, stdoutWriter, stderrWriter, command, utils.Capture /* stdout */, utils.Show /* stderr */) - if verbose { - printInfoFn(string(verboseInfo)) + verboseInfo, out, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) + if builderLogger.Verbose() { + builderLogger.Info(string(verboseInfo)) } if err != nil { resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err) diff --git a/legacy/builder/phases/sizer_test.go b/arduino/builder/sizer/sizer_test.go similarity index 99% rename from legacy/builder/phases/sizer_test.go rename to arduino/builder/sizer/sizer_test.go index 42e26fdcfa3..42c3b323d42 100644 --- a/legacy/builder/phases/sizer_test.go +++ b/arduino/builder/sizer/sizer_test.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package phases +package sizer import ( "testing" diff --git a/arduino/builder/sketch.go b/arduino/builder/sketch.go index f8eff7caafa..79779d5b4cc 100644 --- a/arduino/builder/sketch.go +++ b/arduino/builder/sketch.go @@ -20,10 +20,17 @@ import ( "fmt" "regexp" + "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/cpp" + "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/builder/progress" + "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/i18n" + f "github.com/arduino/arduino-cli/internal/algorithms" + rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" ) @@ -171,3 +178,52 @@ func writeIfDifferent(source []byte, destPath *paths.Path) error { // Source and destination are the same, don't write anything return nil } + +// SketchBuilder fixdoc +func SketchBuilder( + sketchBuildPath *paths.Path, + buildProperties *properties.Map, + includesFolders paths.PathList, + onlyUpdateCompilationDatabase bool, + compilationDatabase *compilation.Database, + jobs int, + builderLogger *logger.BuilderLogger, + progress *progress.Struct, progressCB rpc.TaskProgressCB, +) (paths.PathList, error) { + includes := f.Map(includesFolders.AsStrings(), cpp.WrapWithHyphenI) + + if err := sketchBuildPath.MkdirAll(); err != nil { + return nil, errors.WithStack(err) + } + + sketchObjectFiles, err := utils.CompileFiles( + sketchBuildPath, sketchBuildPath, buildProperties, includes, + onlyUpdateCompilationDatabase, + compilationDatabase, + jobs, + builderLogger, + progress, progressCB, + ) + if err != nil { + return nil, errors.WithStack(err) + } + + // The "src/" subdirectory of a sketch is compiled recursively + sketchSrcPath := sketchBuildPath.Join("src") + if sketchSrcPath.IsDir() { + srcObjectFiles, err := utils.CompileFilesRecursive( + sketchSrcPath, sketchSrcPath, buildProperties, includes, + onlyUpdateCompilationDatabase, + compilationDatabase, + jobs, + builderLogger, + progress, progressCB, + ) + if err != nil { + return nil, errors.WithStack(err) + } + sketchObjectFiles.AddAll(srcObjectFiles) + } + + return sketchObjectFiles, nil +} diff --git a/arduino/builder/utils/utils.go b/arduino/builder/utils/utils.go index 10902c46ca0..ea3f80c5326 100644 --- a/arduino/builder/utils/utils.go +++ b/arduino/builder/utils/utils.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package utils import ( @@ -11,7 +26,8 @@ import ( "sync" "unicode" - "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/builder/compilation" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/executils" @@ -339,13 +355,9 @@ func CompileFiles( buildProperties *properties.Map, includes []string, onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + compilationDatabase *compilation.Database, jobs int, - verbose bool, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { return compileFiles( @@ -355,10 +367,7 @@ func CompileFiles( sourceDir, false, buildPath, buildProperties, includes, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) } @@ -369,13 +378,9 @@ func CompileFilesRecursive( buildProperties *properties.Map, includes []string, onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + compilationDatabase *compilation.Database, jobs int, - verbose bool, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { return compileFiles( @@ -385,28 +390,21 @@ func CompileFilesRecursive( sourceDir, true, buildPath, buildProperties, includes, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, + builderLogger, progress, progressCB, ) } func compileFiles( onlyUpdateCompilationDatabase bool, - compilationDatabase *builder.CompilationDatabase, + compilationDatabase *compilation.Database, jobs int, sourceDir *paths.Path, recurse bool, buildPath *paths.Path, buildProperties *properties.Map, includes []string, - verbose bool, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), + builderLogger *logger.BuilderLogger, progress *progress.Struct, progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { @@ -438,18 +436,16 @@ func compileFiles( recipe = fmt.Sprintf("recipe%s.o.pattern", globals.SourceFilesValidExtensions[source.Ext()]) } objectFile, verboseInfo, verboseStdout, stderr, err := compileFileWithRecipe( - stdoutWriter, stderrWriter, - warningsLevel, compilationDatabase, - verbose, onlyUpdateCompilationDatabase, sourceDir, source, buildPath, buildProperties, includes, recipe, + builderLogger, ) - if verbose { - verboseStdoutFn(verboseStdout) - verboseInfoFn(string(verboseInfo)) + if builderLogger.Verbose() { + builderLogger.WriteStdout(verboseStdout) + builderLogger.Info(string(verboseInfo)) } - verboseStderrFn(stderr) + builderLogger.WriteStderr(stderr) if err != nil { errorsMux.Lock() errorsList = append(errorsList, err) @@ -506,21 +502,20 @@ func compileFiles( } func compileFileWithRecipe( - stdoutWriter, stderrWriter io.Writer, - warningsLevel string, - compilationDatabase *builder.CompilationDatabase, - verbose, onlyUpdateCompilationDatabase bool, + compilationDatabase *compilation.Database, + onlyUpdateCompilationDatabase bool, sourcePath *paths.Path, source *paths.Path, buildPath *paths.Path, buildProperties *properties.Map, includes []string, recipe string, + builderLogger *logger.BuilderLogger, ) (*paths.Path, []byte, []byte, []byte, error) { verboseStdout, verboseInfo, errOut := &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{} properties := buildProperties.Clone() - properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+warningsLevel)) + properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+builderLogger.WarningsLevel())) properties.Set("includes", strings.Join(includes, " ")) properties.SetPath("source_file", source) relativeSource, err := sourcePath.RelTo(source) @@ -550,9 +545,16 @@ func compileFileWithRecipe( } if !objIsUpToDate && !onlyUpdateCompilationDatabase { // Since this compile could be multithreaded, we first capture the command output - info, stdout, stderr, err := ExecCommand(verbose, stdoutWriter, stderrWriter, command, Capture, Capture) + info, stdout, stderr, err := ExecCommand( + builderLogger.Verbose(), + builderLogger.Stdout(), + builderLogger.Stderr(), + command, + Capture, + Capture, + ) // and transfer all at once at the end... - if verbose { + if builderLogger.Verbose() { verboseInfo.Write(info) verboseStdout.Write(stdout) } @@ -562,7 +564,7 @@ func compileFileWithRecipe( if err != nil { return nil, verboseInfo.Bytes(), verboseStdout.Bytes(), errOut.Bytes(), errors.WithStack(err) } - } else if verbose { + } else if builderLogger.Verbose() { if objIsUpToDate { verboseInfo.WriteString(tr("Using previously compiled file: %[1]s", objectFile)) } else { diff --git a/arduino/builder/utils/utils_test.go b/arduino/builder/utils/utils_test.go index 84cd9d699ec..3dd4c1a2142 100644 --- a/arduino/builder/utils/utils_test.go +++ b/arduino/builder/utils/utils_test.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package utils import ( diff --git a/commands/compile/compile.go b/commands/compile/compile.go index f04a239a870..36bba118f92 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -24,7 +24,9 @@ import ( "github.com/arduino/arduino-cli/arduino" bldr "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/detector" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/arduino/sketch" @@ -213,25 +215,19 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream builderCtx.OtherLibrariesDirs = paths.NewPathList(req.GetLibraries()...) builderCtx.OtherLibrariesDirs.Add(configuration.LibrariesDir(configuration.Settings)) - builderCtx.CompilationDatabase = bldr.NewCompilationDatabase( + builderCtx.CompilationDatabase = compilation.NewDatabase( builderCtx.BuildPath.Join("compile_commands.json"), ) - builderCtx.Verbose = req.GetVerbose() - - builderCtx.WarningsLevel = req.GetWarnings() - if builderCtx.WarningsLevel == "" { - builderCtx.WarningsLevel = builder.DEFAULT_WARNINGS_LEVEL - } - builderCtx.BuiltInLibrariesDirs = configuration.IDEBuiltinLibrariesDir(configuration.Settings) - builderCtx.Stdout = outStream - builderCtx.Stderr = errStream builderCtx.Clean = req.GetClean() builderCtx.OnlyUpdateCompilationDatabase = req.GetCreateCompilationDatabaseOnly() builderCtx.SourceOverride = req.GetSourceOverride() + builderLogger := logger.New(outStream, errStream, req.GetVerbose(), req.GetWarnings()) + builderCtx.BuilderLogger = builderLogger + sketchBuildPath, err := buildPath.Join(constants.FOLDER_SKETCH).Abs() if err != nil { return r, &arduino.CompileFailedError{Message: err.Error()} @@ -269,19 +265,15 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return r, &arduino.CompileFailedError{Message: err.Error()} } - if builderCtx.Verbose { - builderCtx.Warn(string(verboseOut)) + if builderLogger.Verbose() { + builderLogger.Warn(string(verboseOut)) } builderCtx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( libsManager, libsResolver, - builderCtx.Verbose, useCachedLibrariesResolution, req.GetCreateCompilationDatabaseOnly(), - func(msg string) { builderCtx.Info(msg) }, - func(msg string) { builderCtx.Warn(msg) }, - func(data []byte) { builderCtx.WriteStdout(data) }, - func(data []byte) { builderCtx.WriteStderr(data) }, + builderLogger, ) defer func() { @@ -372,9 +364,9 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream if exportBinaries { err := builder.RecipeByPrefixSuffixRunner( "recipe.hooks.savehex.presavehex", ".pattern", false, - builderCtx.OnlyUpdateCompilationDatabase, builderCtx.Verbose, - builderCtx.BuildProperties, builderCtx.Stdout, builderCtx.Stderr, - func(msg string) { builderCtx.Info(msg) }, + builderCtx.OnlyUpdateCompilationDatabase, + builderCtx.BuildProperties, + builderLogger, ) if err != nil { return r, err @@ -416,9 +408,8 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream err = builder.RecipeByPrefixSuffixRunner( "recipe.hooks.savehex.postsavehex", ".pattern", false, - builderCtx.OnlyUpdateCompilationDatabase, builderCtx.Verbose, - builderCtx.BuildProperties, builderCtx.Stdout, builderCtx.Stderr, - func(msg string) { builderCtx.Info(msg) }, + builderCtx.OnlyUpdateCompilationDatabase, + builderCtx.BuildProperties, builderLogger, ) if err != nil { return r, err diff --git a/legacy/builder/builder.go b/legacy/builder/builder.go index 0e1156666e6..c36335aa799 100644 --- a/legacy/builder/builder.go +++ b/legacy/builder/builder.go @@ -19,10 +19,11 @@ import ( "reflect" "time" + "github.com/arduino/arduino-cli/arduino/builder" "github.com/arduino/arduino-cli/arduino/builder/preprocessor" + "github.com/arduino/arduino-cli/arduino/builder/sizer" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/i18n" - "github.com/arduino/arduino-cli/legacy/builder/phases" "github.com/arduino/arduino-cli/legacy/builder/types" "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -33,7 +34,6 @@ import ( var tr = i18n.Tr const DEFAULT_DEBUG_LEVEL = 5 -const DEFAULT_WARNINGS_LEVEL = "none" type Builder struct{} @@ -70,19 +70,14 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - sketchObjectFiles, err := phases.SketchBuilder( + sketchObjectFiles, err := builder.SketchBuilder( ctx.SketchBuildPath, ctx.BuildProperties, ctx.SketchLibrariesDetector.IncludeFolders(), ctx.OnlyUpdateCompilationDatabase, - ctx.Verbose, ctx.CompilationDatabase, ctx.Builder.Jobs(), - ctx.WarningsLevel, - ctx.Stdout, ctx.Stderr, - func(msg string) { ctx.Info(msg) }, - func(data []byte) { ctx.WriteStdout(data) }, - func(data []byte) { ctx.WriteStderr(data) }, + ctx.BuilderLogger, &ctx.Progress, ctx.ProgressCB, ) if err != nil { @@ -109,21 +104,15 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - librariesObjectFiles, err := phases.LibrariesBuilder( + librariesObjectFiles, err := builder.LibrariesBuilder( ctx.LibrariesBuildPath, ctx.BuildProperties, ctx.SketchLibrariesDetector.IncludeFolders(), ctx.SketchLibrariesDetector.ImportedLibraries(), - ctx.Verbose, ctx.OnlyUpdateCompilationDatabase, ctx.CompilationDatabase, ctx.Builder.Jobs(), - ctx.WarningsLevel, - ctx.Stdout, - ctx.Stderr, - func(msg string) { ctx.Info(msg) }, - func(data []byte) { ctx.WriteStdout(data) }, - func(data []byte) { ctx.WriteStderr(data) }, + ctx.BuilderLogger, &ctx.Progress, ctx.ProgressCB, ) if err != nil { @@ -143,18 +132,14 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - objectFiles, archiveFile, err := phases.CoreBuilder( + objectFiles, archiveFile, err := builder.CoreBuilder( ctx.BuildPath, ctx.CoreBuildPath, ctx.Builder.CoreBuildCachePath(), ctx.BuildProperties, ctx.ActualPlatform, - ctx.Verbose, ctx.OnlyUpdateCompilationDatabase, ctx.Clean, + ctx.OnlyUpdateCompilationDatabase, ctx.Clean, ctx.CompilationDatabase, ctx.Builder.Jobs(), - ctx.WarningsLevel, - ctx.Stdout, ctx.Stderr, - func(msg string) { ctx.Info(msg) }, - func(data []byte) { ctx.WriteStdout(data) }, - func(data []byte) { ctx.WriteStderr(data) }, + ctx.BuilderLogger, &ctx.Progress, ctx.ProgressCB, ) @@ -174,21 +159,18 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - verboseInfoOut, err := phases.Linker( + verboseInfoOut, err := builder.Linker( ctx.OnlyUpdateCompilationDatabase, - ctx.Verbose, ctx.SketchObjectFiles, ctx.LibrariesObjectFiles, ctx.CoreObjectsFiles, ctx.CoreArchiveFilePath, ctx.BuildPath, ctx.BuildProperties, - ctx.Stdout, - ctx.Stderr, - ctx.WarningsLevel, + ctx.BuilderLogger, ) - if ctx.Verbose { - ctx.Info(string(verboseInfoOut)) + if ctx.BuilderLogger.Verbose() { + ctx.BuilderLogger.Info(string(verboseInfoOut)) } return err }), @@ -209,10 +191,9 @@ func (s *Builder) Run(ctx *types.Context) error { types.BareCommand(func(ctx *types.Context) error { return MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, + ctx.OnlyUpdateCompilationDatabase, ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - func(s string) { ctx.Info(s) }, - func(s string) { ctx.Warn(s) }, + ctx.BuilderLogger, ) }), @@ -247,8 +228,8 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - infoOut, _ := PrintUsedLibrariesIfVerbose(ctx.Verbose, ctx.SketchLibrariesDetector.ImportedLibraries()) - ctx.Info(string(infoOut)) + infoOut, _ := PrintUsedLibrariesIfVerbose(ctx.BuilderLogger.Verbose(), ctx.SketchLibrariesDetector.ImportedLibraries()) + ctx.BuilderLogger.Info(string(infoOut)) return nil }), @@ -263,22 +244,19 @@ func (s *Builder) Run(ctx *types.Context) error { ctx.LineOffset, ctx.OnlyUpdateCompilationDatabase, ) - if ctx.Verbose { - ctx.WriteStdout(verboseOutput) + if ctx.BuilderLogger.Verbose() { + ctx.BuilderLogger.WriteStdout(verboseOutput) } else { - ctx.WriteStdout(normalOutput) + ctx.BuilderLogger.WriteStdout(normalOutput) } return err }), types.BareCommand(func(ctx *types.Context) error { - executableSectionsSize, err := phases.Sizer( - ctx.OnlyUpdateCompilationDatabase, mainErr != nil, ctx.Verbose, + executableSectionsSize, err := sizer.Size( + ctx.OnlyUpdateCompilationDatabase, mainErr != nil, ctx.BuildProperties, - ctx.Stdout, ctx.Stderr, - func(msg string) { ctx.Info(msg) }, - func(msg string) { ctx.Warn(msg) }, - ctx.WarningsLevel, + ctx.BuilderLogger, ) ctx.ExecutableSectionsSize = executableSectionsSize return err @@ -307,10 +285,10 @@ func preprocessSketchCommand(ctx *types.Context) types.BareCommand { normalOutput, verboseOutput, err := PreprocessSketch( ctx.Builder.Sketch(), ctx.BuildPath, ctx.SketchLibrariesDetector.IncludeFolders(), ctx.LineOffset, ctx.BuildProperties, ctx.OnlyUpdateCompilationDatabase) - if ctx.Verbose { - ctx.WriteStdout(verboseOutput) + if ctx.BuilderLogger.Verbose() { + ctx.BuilderLogger.WriteStdout(verboseOutput) } else { - ctx.WriteStdout(normalOutput) + ctx.BuilderLogger.WriteStdout(normalOutput) } return err } @@ -361,7 +339,7 @@ func (s *Preprocess) Run(ctx *types.Context) error { if err != nil { return err } - ctx.WriteStdout(preprocessedSketch) + ctx.BuilderLogger.WriteStdout(preprocessedSketch) return nil } @@ -411,13 +389,13 @@ func findIncludes(ctx *types.Context) types.BareCommand { func logIfVerbose(warn bool, msg string) types.BareCommand { return types.BareCommand(func(ctx *types.Context) error { - if !ctx.Verbose { + if !ctx.BuilderLogger.Verbose() { return nil } if warn { - ctx.Warn(msg) + ctx.BuilderLogger.Warn(msg) } else { - ctx.Info(msg) + ctx.BuilderLogger.Info(msg) } return nil }) @@ -426,9 +404,9 @@ func logIfVerbose(warn bool, msg string) types.BareCommand { func recipeByPrefixSuffixRunner(ctx *types.Context, prefix, suffix string, skipIfOnlyUpdatingCompilationDatabase bool) error { return RecipeByPrefixSuffixRunner( prefix, suffix, skipIfOnlyUpdatingCompilationDatabase, - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, - ctx.BuildProperties, ctx.Stdout, ctx.Stderr, - func(msg string) { ctx.Info(msg) }, + ctx.OnlyUpdateCompilationDatabase, + ctx.BuildProperties, + ctx.BuilderLogger, ) } @@ -442,7 +420,7 @@ func containerBuildOptions(ctx *types.Context) types.BareCommand { ctx.FQBN.String(), ctx.Clean, ctx.BuildProperties, ) if infoMessage != "" { - ctx.Info(infoMessage) + ctx.BuilderLogger.Info(infoMessage) } if err != nil { return err @@ -462,7 +440,7 @@ func warnAboutArchIncompatibleLibraries(ctx *types.Context) types.BareCommand { ctx.TargetPlatform, overrides, ctx.SketchLibrariesDetector.ImportedLibraries(), - func(s string) { ctx.Info(s) }, + func(s string) { ctx.BuilderLogger.Info(s) }, ) return nil }) diff --git a/legacy/builder/merge_sketch_with_bootloader.go b/legacy/builder/merge_sketch_with_bootloader.go index a397ac102f4..7d77204de33 100644 --- a/legacy/builder/merge_sketch_with_bootloader.go +++ b/legacy/builder/merge_sketch_with_bootloader.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/go-paths-helper" @@ -29,11 +30,11 @@ import ( ) func MergeSketchWithBootloader( - onlyUpdateCompilationDatabase, verbose bool, + onlyUpdateCompilationDatabase bool, buildPath *paths.Path, sketch *sketch.Sketch, buildProperties *properties.Map, - printInfoFn, printWarnFn func(string), + builderLogger *logger.BuilderLogger, ) error { if onlyUpdateCompilationDatabase { return nil @@ -66,8 +67,8 @@ func MergeSketchWithBootloader( bootloaderPath := buildProperties.GetPath("runtime.platform.path").Join(constants.FOLDER_BOOTLOADERS, bootloader) if bootloaderPath.NotExist() { - if verbose { - printWarnFn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath)) + if builderLogger.Verbose() { + builderLogger.Warn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath)) } return nil } @@ -81,8 +82,8 @@ func MergeSketchWithBootloader( maximumBinSize *= 2 } err := merge(builtSketchPath, bootloaderPath, mergedSketchPath, maximumBinSize) - if err != nil && verbose { - printInfoFn(err.Error()) + if err != nil && builderLogger.Verbose() { + builderLogger.Info(err.Error()) } return nil diff --git a/legacy/builder/phases/core_builder.go b/legacy/builder/phases/core_builder.go deleted file mode 100644 index 9c49fe6d787..00000000000 --- a/legacy/builder/phases/core_builder.go +++ /dev/null @@ -1,234 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package phases - -import ( - "crypto/md5" - "encoding/hex" - "fmt" - "io" - "os" - "strings" - - "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/builder/cpp" - "github.com/arduino/arduino-cli/arduino/builder/progress" - "github.com/arduino/arduino-cli/arduino/builder/utils" - "github.com/arduino/arduino-cli/arduino/cores" - "github.com/arduino/arduino-cli/buildcache" - "github.com/arduino/arduino-cli/i18n" - f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" - "github.com/pkg/errors" -) - -var tr = i18n.Tr - -func CoreBuilder( - buildPath, coreBuildPath, coreBuildCachePath *paths.Path, - buildProperties *properties.Map, - actualPlatform *cores.PlatformRelease, - verbose, onlyUpdateCompilationDatabase, clean bool, - compilationDatabase *builder.CompilationDatabase, - jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, *paths.Path, error) { - if err := coreBuildPath.MkdirAll(); err != nil { - return nil, nil, errors.WithStack(err) - } - - if coreBuildCachePath != nil { - if _, err := coreBuildCachePath.RelTo(buildPath); err != nil { - verboseInfoFn(tr("Couldn't deeply cache core build: %[1]s", err)) - verboseInfoFn(tr("Running normal build of the core...")) - coreBuildCachePath = nil - } else if err := coreBuildCachePath.MkdirAll(); err != nil { - return nil, nil, errors.WithStack(err) - } - } - - archiveFile, objectFiles, err := compileCore( - verbose, onlyUpdateCompilationDatabase, clean, - actualPlatform, - coreBuildPath, coreBuildCachePath, - buildProperties, - compilationDatabase, - jobs, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, - verboseStdoutFn, verboseStderrFn, - progress, progressCB, - ) - if err != nil { - return nil, nil, errors.WithStack(err) - } - - return objectFiles, archiveFile, nil -} - -func compileCore( - verbose, onlyUpdateCompilationDatabase, clean bool, - actualPlatform *cores.PlatformRelease, - buildPath, buildCachePath *paths.Path, - buildProperties *properties.Map, - compilationDatabase *builder.CompilationDatabase, - jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (*paths.Path, paths.PathList, error) { - coreFolder := buildProperties.GetPath("build.core.path") - variantFolder := buildProperties.GetPath("build.variant.path") - targetCoreFolder := buildProperties.GetPath("runtime.platform.path") - - includes := []string{coreFolder.String()} - if variantFolder != nil && variantFolder.IsDir() { - includes = append(includes, variantFolder.String()) - } - includes = f.Map(includes, cpp.WrapWithHyphenI) - - var err error - variantObjectFiles := paths.NewPathList() - if variantFolder != nil && variantFolder.IsDir() { - variantObjectFiles, err = utils.CompileFilesRecursive( - variantFolder, buildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, - progress, progressCB, - ) - if err != nil { - return nil, nil, errors.WithStack(err) - } - } - - var targetArchivedCore *paths.Path - if buildCachePath != nil { - realCoreFolder := coreFolder.Parent().Parent() - archivedCoreName := GetCachedCoreArchiveDirName( - buildProperties.Get("build.fqbn"), - buildProperties.Get("compiler.optimization_flags"), - realCoreFolder, - ) - targetArchivedCore = buildCachePath.Join(archivedCoreName, "core.a") - - if _, err := buildcache.New(buildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) { - return nil, nil, fmt.Errorf(tr("creating core cache folder: %s", err)) - } - - var canUseArchivedCore bool - if onlyUpdateCompilationDatabase || clean { - canUseArchivedCore = false - } else if isOlder, err := utils.DirContentIsOlderThan(realCoreFolder, targetArchivedCore); err != nil || !isOlder { - // Recreate the archive if ANY of the core files (including platform.txt) has changed - canUseArchivedCore = false - } else if targetCoreFolder == nil || realCoreFolder.EquivalentTo(targetCoreFolder) { - canUseArchivedCore = true - } else if isOlder, err := utils.DirContentIsOlderThan(targetCoreFolder, targetArchivedCore); err != nil || !isOlder { - // Recreate the archive if ANY of the build core files (including platform.txt) has changed - canUseArchivedCore = false - } else { - canUseArchivedCore = true - } - - if canUseArchivedCore { - // use archived core - if verbose { - verboseInfoFn(tr("Using precompiled core: %[1]s", targetArchivedCore)) - } - return targetArchivedCore, variantObjectFiles, nil - } - } - - coreObjectFiles, err := utils.CompileFilesRecursive( - coreFolder, buildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, verboseStdoutFn, verboseStderrFn, - progress, progressCB, - ) - if err != nil { - return nil, nil, errors.WithStack(err) - } - - archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles( - buildPath, paths.New("core.a"), coreObjectFiles, buildProperties, - onlyUpdateCompilationDatabase, verbose, stdoutWriter, stderrWriter, - ) - if verbose { - verboseInfoFn(string(verboseInfo)) - } - if err != nil { - return nil, nil, errors.WithStack(err) - } - - // archive core.a - if targetArchivedCore != nil && !onlyUpdateCompilationDatabase { - err := archiveFile.CopyTo(targetArchivedCore) - if verbose { - if err == nil { - verboseInfoFn(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore)) - } else if os.IsNotExist(err) { - verboseInfoFn(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s", - actualPlatform, - "https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-build-the-corea-archive-file")) - } else { - verboseInfoFn(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err)) - } - } - } - - return archiveFile, variantObjectFiles, nil -} - -// GetCachedCoreArchiveDirName returns the directory name to be used to store -// the global cached core.a. -func GetCachedCoreArchiveDirName(fqbn string, optimizationFlags string, coreFolder *paths.Path) string { - fqbnToUnderscore := strings.ReplaceAll(fqbn, ":", "_") - fqbnToUnderscore = strings.ReplaceAll(fqbnToUnderscore, "=", "_") - if absCoreFolder, err := coreFolder.Abs(); err == nil { - coreFolder = absCoreFolder - } // silently continue if absolute path can't be detected - - md5Sum := func(data []byte) string { - md5sumBytes := md5.Sum(data) - return hex.EncodeToString(md5sumBytes[:]) - } - hash := md5Sum([]byte(coreFolder.String() + optimizationFlags)) - realName := fqbnToUnderscore + "_" + hash - if len(realName) > 100 { - // avoid really long names, simply hash the name again - realName = md5Sum([]byte(realName)) - } - return realName -} diff --git a/legacy/builder/phases/sketch_builder.go b/legacy/builder/phases/sketch_builder.go deleted file mode 100644 index 190604ddc0a..00000000000 --- a/legacy/builder/phases/sketch_builder.go +++ /dev/null @@ -1,91 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package phases - -import ( - "io" - - "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/builder/cpp" - "github.com/arduino/arduino-cli/arduino/builder/progress" - "github.com/arduino/arduino-cli/arduino/builder/utils" - f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" - "github.com/pkg/errors" -) - -func SketchBuilder( - sketchBuildPath *paths.Path, - buildProperties *properties.Map, - includesFolders paths.PathList, - onlyUpdateCompilationDatabase, verbose bool, - compilationDatabase *builder.CompilationDatabase, - jobs int, - warningsLevel string, - stdoutWriter, stderrWriter io.Writer, - verboseInfoFn func(msg string), - verboseStdoutFn, verboseStderrFn func(data []byte), - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, error) { - includes := f.Map(includesFolders.AsStrings(), cpp.WrapWithHyphenI) - - if err := sketchBuildPath.MkdirAll(); err != nil { - return nil, errors.WithStack(err) - } - - sketchObjectFiles, err := utils.CompileFiles( - sketchBuildPath, sketchBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, - verboseStdoutFn, - verboseStderrFn, - progress, progressCB, - ) - if err != nil { - return nil, errors.WithStack(err) - } - - // The "src/" subdirectory of a sketch is compiled recursively - sketchSrcPath := sketchBuildPath.Join("src") - if sketchSrcPath.IsDir() { - srcObjectFiles, err := utils.CompileFilesRecursive( - sketchSrcPath, sketchSrcPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - verbose, - warningsLevel, - stdoutWriter, stderrWriter, - verboseInfoFn, - verboseStdoutFn, - verboseStderrFn, - progress, progressCB, - ) - if err != nil { - return nil, errors.WithStack(err) - } - sketchObjectFiles.AddAll(srcObjectFiles) - } - - return sketchObjectFiles, nil -} diff --git a/legacy/builder/recipe_runner.go b/legacy/builder/recipe_runner.go index 78215bd211c..8af310bd4d3 100644 --- a/legacy/builder/recipe_runner.go +++ b/legacy/builder/recipe_runner.go @@ -17,10 +17,10 @@ package builder import ( "fmt" - "io" "sort" "strings" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" properties "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" @@ -29,10 +29,9 @@ import ( func RecipeByPrefixSuffixRunner( prefix, suffix string, - skipIfOnlyUpdatingCompilationDatabase, onlyUpdateCompilationDatabase, verbose bool, + skipIfOnlyUpdatingCompilationDatabase, onlyUpdateCompilationDatabase bool, buildProps *properties.Map, - stdoutWriter, stderrWriter io.Writer, - printInfoFn func(string), + builderLogger *logger.BuilderLogger, ) error { logrus.Debugf(fmt.Sprintf("Looking for recipes like %s", prefix+"*"+suffix)) @@ -51,15 +50,15 @@ func RecipeByPrefixSuffixRunner( } if onlyUpdateCompilationDatabase && skipIfOnlyUpdatingCompilationDatabase { - if verbose { - printInfoFn(tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " "))) + if builderLogger.Verbose() { + builderLogger.Info(tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " "))) } return nil } - verboseInfo, _, _, err := utils.ExecCommand(verbose, stdoutWriter, stderrWriter, command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) - if verbose { - printInfoFn(string(verboseInfo)) + verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) + if builderLogger.Verbose() { + builderLogger.Info(string(verboseInfo)) } if err != nil { return errors.WithStack(err) diff --git a/legacy/builder/test/builder_test.go b/legacy/builder/test/builder_test.go index 4ec13627315..e6af9105ebc 100644 --- a/legacy/builder/test/builder_test.go +++ b/legacy/builder/test/builder_test.go @@ -22,6 +22,7 @@ import ( bldr "github.com/arduino/arduino-cli/arduino/builder" "github.com/arduino/arduino-cli/arduino/builder/detector" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/constants" @@ -98,6 +99,8 @@ func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *pat sk = s } + builderLogger := logger.New(nil, nil, false, "") + ctx.BuilderLogger = builderLogger ctx.Builder = bldr.NewBuilder(sk, nil, nil, false, nil, 0) if fqbn != "" { ctx.FQBN = parseFQBN(t, fqbn) @@ -130,13 +133,9 @@ func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *pat ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( lm, libsResolver, - ctx.Verbose, false, false, - func(msg string) { ctx.Info(msg) }, - func(msg string) { ctx.Warn(msg) }, - func(data []byte) { ctx.WriteStdout(data) }, - func(data []byte) { ctx.WriteStderr(data) }, + builderLogger, ) } diff --git a/legacy/builder/test/create_build_options_map_test.go b/legacy/builder/test/create_build_options_map_test.go index b2d90ffa253..d3c5ce42580 100644 --- a/legacy/builder/test/create_build_options_map_test.go +++ b/legacy/builder/test/create_build_options_map_test.go @@ -32,7 +32,6 @@ func TestCreateBuildOptionsMap(t *testing.T) { BuiltInToolsDirs: paths.NewPathList("tools"), OtherLibrariesDirs: paths.NewPathList("libraries"), FQBN: parseFQBN(t, "my:nice:fqbn"), - Verbose: true, BuildPath: paths.New("buildPath"), BuildProperties: properties.NewFromHashmap(map[string]string{"compiler.optimization_flags": "-Os"}), } diff --git a/legacy/builder/test/merge_sketch_with_bootloader_test.go b/legacy/builder/test/merge_sketch_with_bootloader_test.go index 6305a174928..f1d9224b840 100644 --- a/legacy/builder/test/merge_sketch_with_bootloader_test.go +++ b/legacy/builder/test/merge_sketch_with_bootloader_test.go @@ -21,6 +21,7 @@ import ( "strings" "testing" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/legacy/builder" "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/arduino-cli/legacy/builder/types" @@ -69,11 +70,11 @@ func TestMergeSketchWithBootloader(t *testing.T) { err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) + builderLogger := logger.New(nil, nil, false, "") err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, + ctx.OnlyUpdateCompilationDatabase, ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - func(s string) { ctx.Info(s) }, - func(s string) { ctx.Warn(s) }, + builderLogger, ) require.NoError(t, err) @@ -126,11 +127,11 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) { err = buildPath.Join("sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) + builderLogger := logger.New(nil, nil, false, "") err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, + ctx.OnlyUpdateCompilationDatabase, ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - func(s string) { ctx.Info(s) }, - func(s string) { ctx.Warn(s) }, + builderLogger, ) require.NoError(t, err) @@ -152,11 +153,11 @@ func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) { buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_NOBLINK) buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_FILE) + builderLogger := logger.New(nil, nil, false, "") err := builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, + ctx.OnlyUpdateCompilationDatabase, ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - func(s string) { ctx.Info(s) }, - func(s string) { ctx.Warn(s) }, + builderLogger, ) require.NoError(t, err) @@ -212,11 +213,11 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) { err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) + builderLogger := logger.New(nil, nil, false, "") err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, ctx.Verbose, + ctx.OnlyUpdateCompilationDatabase, ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - func(s string) { ctx.Info(s) }, - func(s string) { ctx.Warn(s) }, + builderLogger, ) require.NoError(t, err) diff --git a/legacy/builder/test/store_build_options_map_test.go b/legacy/builder/test/store_build_options_map_test.go index a532ac5007a..c9782e4dc40 100644 --- a/legacy/builder/test/store_build_options_map_test.go +++ b/legacy/builder/test/store_build_options_map_test.go @@ -35,7 +35,6 @@ func TestStoreBuildOptionsMap(t *testing.T) { OtherLibrariesDirs: paths.NewPathList("libraries"), FQBN: parseFQBN(t, "my:nice:fqbn"), CustomBuildProperties: []string{"custom=prop"}, - Verbose: true, BuildProperties: properties.NewFromHashmap(map[string]string{"compiler.optimization_flags": "-Os"}), } diff --git a/legacy/builder/test/try_build_of_problematic_sketch_test.go b/legacy/builder/test/try_build_of_problematic_sketch_test.go index 9a5b43a0e9f..ab40de05714 100644 --- a/legacy/builder/test/try_build_of_problematic_sketch_test.go +++ b/legacy/builder/test/try_build_of_problematic_sketch_test.go @@ -81,7 +81,6 @@ func makeDefaultContext() *types.Context { BuiltInToolsDirs: paths.NewPathList("downloaded_tools"), BuiltInLibrariesDirs: paths.New("downloaded_libraries"), OtherLibrariesDirs: paths.NewPathList("libraries"), - Verbose: true, } } diff --git a/legacy/builder/test/unused_compiled_libraries_remover_test.go b/legacy/builder/test/unused_compiled_libraries_remover_test.go index 6f3217d505b..6e7ab70df1b 100644 --- a/legacy/builder/test/unused_compiled_libraries_remover_test.go +++ b/legacy/builder/test/unused_compiled_libraries_remover_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/arduino/arduino-cli/arduino/builder/detector" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/libraries" "github.com/arduino/arduino-cli/legacy/builder" "github.com/arduino/arduino-cli/legacy/builder/types" @@ -38,7 +39,7 @@ func TestUnusedCompiledLibrariesRemover(t *testing.T) { ctx := &types.Context{} ctx.LibrariesBuildPath = temp ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, false, nil, nil, nil, nil, + nil, nil, false, false, logger.New(nil, nil, false, ""), ) ctx.SketchLibrariesDetector.AppendImportedLibraries(&libraries.Library{Name: "Bridge"}) @@ -63,7 +64,7 @@ func TestUnusedCompiledLibrariesRemoverLibDoesNotExist(t *testing.T) { ctx := &types.Context{} ctx.LibrariesBuildPath = paths.TempDir().Join("test") ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, false, nil, nil, nil, nil, + nil, nil, false, false, logger.New(nil, nil, false, ""), ) ctx.SketchLibrariesDetector.AppendImportedLibraries(&libraries.Library{Name: "Bridge"}) @@ -85,7 +86,7 @@ func TestUnusedCompiledLibrariesRemoverNoUsedLibraries(t *testing.T) { ctx := &types.Context{} ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, false, nil, nil, nil, nil, + nil, nil, false, false, logger.New(nil, nil, false, ""), ) ctx.LibrariesBuildPath = temp diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index 6d7ac15952f..61eff082d7a 100644 --- a/legacy/builder/types/context.go +++ b/legacy/builder/types/context.go @@ -16,14 +16,12 @@ package types import ( - "fmt" - "io" - "os" - "sync" - "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/detector" + "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/progress" + "github.com/arduino/arduino-cli/arduino/builder/sizer" "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" @@ -35,6 +33,7 @@ import ( type Context struct { Builder *builder.Builder SketchLibrariesDetector *detector.SketchLibrariesDetector + BuilderLogger *logger.BuilderLogger // Build options HardwareDirs paths.PathList @@ -65,14 +64,9 @@ type Context struct { LibrariesObjectFiles paths.PathList SketchObjectFiles paths.PathList - WarningsLevel string - // C++ Parsing LineOffset int - // Verbosity settings - Verbose bool - // Dry run, only create progress map Progress progress.Struct // Send progress events to this callback @@ -81,16 +75,11 @@ type Context struct { // Custom build properties defined by user (line by line as "key=value" pairs) CustomBuildProperties []string - // Out and Err stream to redirect all output - Stdout io.Writer - Stderr io.Writer - stdLock sync.Mutex - // Sizer results - ExecutableSectionsSize builder.ExecutablesFileSections + ExecutableSectionsSize sizer.ExecutablesFileSections // Compilation Database to build/update - CompilationDatabase *builder.CompilationDatabase + CompilationDatabase *compilation.Database // Set to true to skip build and produce only Compilation Database OnlyUpdateCompilationDatabase bool @@ -108,41 +97,3 @@ func (ctx *Context) PushProgress() { }) } } - -func (ctx *Context) Info(msg string) { - ctx.stdLock.Lock() - if ctx.Stdout == nil { - fmt.Fprintln(os.Stdout, msg) - } else { - fmt.Fprintln(ctx.Stdout, msg) - } - ctx.stdLock.Unlock() -} - -func (ctx *Context) Warn(msg string) { - ctx.stdLock.Lock() - if ctx.Stderr == nil { - fmt.Fprintln(os.Stderr, msg) - } else { - fmt.Fprintln(ctx.Stderr, msg) - } - ctx.stdLock.Unlock() -} - -func (ctx *Context) WriteStdout(data []byte) (int, error) { - ctx.stdLock.Lock() - defer ctx.stdLock.Unlock() - if ctx.Stdout == nil { - return os.Stdout.Write(data) - } - return ctx.Stdout.Write(data) -} - -func (ctx *Context) WriteStderr(data []byte) (int, error) { - ctx.stdLock.Lock() - defer ctx.stdLock.Unlock() - if ctx.Stderr == nil { - return os.Stderr.Write(data) - } - return ctx.Stderr.Write(data) -}