diff --git a/commands/instances.go b/commands/instances.go index 0145f3639b5..0b5127f0b8b 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -380,7 +380,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor } lmb.AddLibrariesDir(librariesmanager.LibrariesDir{ Path: libDir, - Location: libraries.Unmanaged, + Location: libraries.Profile, IsSingleLibrary: true, }) continue @@ -428,7 +428,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor lmb.AddLibrariesDir(librariesmanager.LibrariesDir{ Path: libRoot, - Location: libraries.User, + Location: libraries.Profile, }) } } diff --git a/commands/service_compile.go b/commands/service_compile.go index ea36641c5e3..1586ef6f953 100644 --- a/commands/service_compile.go +++ b/commands/service_compile.go @@ -105,10 +105,11 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu return &cmderrors.CantOpenSketchError{Cause: err} } + profile := pme.GetProfile() fqbnIn := req.GetFqbn() if fqbnIn == "" && sk != nil { - if pme.GetProfile() != nil { - fqbnIn = pme.GetProfile().FQBN + if profile != nil { + fqbnIn = profile.FQBN } else { fqbnIn = sk.GetDefaultFQBN() } @@ -224,7 +225,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu otherLibrariesDirs.Add(s.settings.LibrariesDir()) var libsManager *librariesmanager.LibrariesManager - if pme.GetProfile() != nil { + if profile != nil { libsManager = lm } diff --git a/internal/arduino/builder/internal/detector/cache.go b/internal/arduino/builder/internal/detector/cache.go new file mode 100644 index 00000000000..247a1e8de30 --- /dev/null +++ b/internal/arduino/builder/internal/detector/cache.go @@ -0,0 +1,122 @@ +// This file is part of arduino-cli. +// +// Copyright 2024 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 detector + +import ( + "encoding/json" + "fmt" + + "github.com/arduino/go-paths-helper" +) + +type detectorCache struct { + curr int + entries []*detectorCacheEntry +} + +type detectorCacheEntry struct { + AddedIncludePath *paths.Path `json:"added_include_path,omitempty"` + CompilingSourcePath *paths.Path `json:"compiling_source_path,omitempty"` + MissingIncludeH *string `json:"missing_include_h,omitempty"` +} + +func (e *detectorCacheEntry) String() string { + if e.AddedIncludePath != nil { + return "Added include path: " + e.AddedIncludePath.String() + } + if e.CompilingSourcePath != nil { + return "Compiling source path: " + e.CompilingSourcePath.String() + } + if e.MissingIncludeH != nil { + if *e.MissingIncludeH == "" { + return "No missing include files detected" + } + return "Missing include file: " + *e.MissingIncludeH + } + return "No operation" +} + +func (e *detectorCacheEntry) Equals(entry *detectorCacheEntry) bool { + return e.String() == entry.String() +} + +func newDetectorCache() *detectorCache { + return &detectorCache{} +} + +func (c *detectorCache) String() string { + res := "" + for _, entry := range c.entries { + res += fmt.Sprintln(entry) + } + return res +} + +// Load reads a saved cache from the given file. +// If the file do not exists, it does nothing. +func (c *detectorCache) Load(cacheFile *paths.Path) error { + if exist, err := cacheFile.ExistCheck(); err != nil { + return err + } else if !exist { + return nil + } + data, err := cacheFile.ReadFile() + if err != nil { + return err + } + var entries []*detectorCacheEntry + if err := json.Unmarshal(data, &entries); err != nil { + return err + } + c.curr = 0 + c.entries = entries + return nil +} + +// Expect adds an entry to the cache and checks if it matches the next expected entry. +func (c *detectorCache) Expect(entry *detectorCacheEntry) { + if c.curr < len(c.entries) { + if c.entries[c.curr].Equals(entry) { + // Cache hit, move to the next entry + c.curr++ + return + } + // Cache mismatch, invalidate and cut the remainder of the cache + c.entries = c.entries[:c.curr] + } + c.curr++ + c.entries = append(c.entries, entry) +} + +// Peek returns the next cache entry to be expected or nil if the cache is fully consumed. +func (c *detectorCache) Peek() *detectorCacheEntry { + if c.curr < len(c.entries) { + return c.entries[c.curr] + } + return nil +} + +// Save writes the current cache to the given file. +func (c *detectorCache) Save(cacheFile *paths.Path) error { + // Cut off the cache if it is not fully consumed + c.entries = c.entries[:c.curr] + + data, err := json.MarshalIndent(c.entries, "", " ") + if err != nil { + return err + } + return cacheFile.WriteFile(data) +} diff --git a/internal/arduino/builder/internal/detector/detector.go b/internal/arduino/builder/internal/detector/detector.go index a983370b075..b6fd97a2a80 100644 --- a/internal/arduino/builder/internal/detector/detector.go +++ b/internal/arduino/builder/internal/detector/detector.go @@ -23,12 +23,12 @@ import ( "fmt" "os/exec" "regexp" - "slices" "strings" "time" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/diagnostics" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/preprocessor" + "github.com/arduino/arduino-cli/internal/arduino/builder/internal/runner" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils" "github.com/arduino/arduino-cli/internal/arduino/builder/logger" "github.com/arduino/arduino-cli/internal/arduino/cores" @@ -52,6 +52,7 @@ type SketchLibrariesDetector struct { librariesManager *librariesmanager.LibrariesManager librariesResolver *librariesresolver.Cpp useCachedLibrariesResolution bool + cache *detectorCache onlyUpdateCompilationDatabase bool importedLibraries libraries.List librariesResolutionResults map[string]libraryResolutionResult @@ -73,6 +74,7 @@ func NewSketchLibrariesDetector( librariesManager: lm, librariesResolver: libsResolver, useCachedLibrariesResolution: useCachedLibrariesResolution, + cache: newDetectorCache(), librariesResolutionResults: map[string]libraryResolutionResult{}, importedLibraries: libraries.List{}, includeFolders: paths.PathList{}, @@ -132,10 +134,25 @@ func (l *SketchLibrariesDetector) ImportedLibraries() libraries.List { return l.importedLibraries } -// AppendImportedLibraries todo should rename this, probably after refactoring the -// container_find_includes command. -func (l *SketchLibrariesDetector) AppendImportedLibraries(library *libraries.Library) { +// addAndBuildLibrary adds the given library to the imported libraries list and queues its source files +// for further processing. +func (l *SketchLibrariesDetector) addAndBuildLibrary(sourceFileQueue *uniqueSourceFileQueue, librariesBuildPath *paths.Path, library *libraries.Library) { l.importedLibraries = append(l.importedLibraries, library) + if library.Precompiled && library.PrecompiledWithSources { + // Fully precompiled libraries should have no dependencies to avoid ABI breakage + if l.logger.VerbosityLevel() == logger.VerbosityVerbose { + l.logger.Info(i18n.Tr("Skipping dependencies detection for precompiled library %[1]s", library.Name)) + } + } else { + for _, sourceDir := range library.SourceDirs() { + l.queueSourceFilesFromFolder( + sourceFileQueue, + sourceDir.Dir, sourceDir.Recurse, + library.SourceDir, + librariesBuildPath.Join(library.DirName), + library.UtilityDir) + } + } } // PrintUsedAndNotUsedLibraries todo @@ -169,28 +186,15 @@ func (l *SketchLibrariesDetector) PrintUsedAndNotUsedLibraries(sketchError bool) time.Sleep(100 * time.Millisecond) } -// IncludeFolders fixdoc +// IncludeFolders returns the list of include folders detected as needed. func (l *SketchLibrariesDetector) IncludeFolders() paths.PathList { - // TODO should we do a deep copy? return l.includeFolders } -// appendIncludeFolder todo should rename this, probably after refactoring the -// container_find_includes command. -// Original comment: -// Append the given folder to the include path and match or append it to -// the cache. sourceFilePath and include indicate the source of this -// include (e.g. what #include line in what file it was resolved from) -// and should be the empty string for the default include folders, like -// the core or variant. -func (l *SketchLibrariesDetector) appendIncludeFolder( - cache *includeCache, - sourceFilePath *paths.Path, - include string, - folder *paths.Path, -) { +// addIncludeFolder add the given folder to the include path. +func (l *SketchLibrariesDetector) addIncludeFolder(folder *paths.Path) { l.includeFolders = append(l.includeFolders, folder) - cache.ExpectEntry(sourceFilePath, include, folder) + l.cache.Expect(&detectorCacheEntry{AddedIncludePath: folder}) } // FindIncludes todo @@ -246,11 +250,13 @@ func (l *SketchLibrariesDetector) findIncludes( } cachePath := buildPath.Join("includes.cache") - cache := readCache(cachePath) + if err := l.cache.Load(cachePath); err != nil { + l.logger.Warn(i18n.Tr("Failed to load library discovery cache: %[1]s", err)) + } - l.appendIncludeFolder(cache, nil, "", buildCorePath) + l.addIncludeFolder(buildCorePath) if buildVariantPath != nil { - l.appendIncludeFolder(cache, nil, "", buildVariantPath) + l.addIncludeFolder(buildVariantPath) } sourceFileQueue := &uniqueSourceFileQueue{} @@ -261,7 +267,7 @@ func (l *SketchLibrariesDetector) findIncludes( if err != nil { return err } - sourceFileQueue.push(mergedfile) + sourceFileQueue.Push(mergedfile) l.queueSourceFilesFromFolder(sourceFileQueue, sketchBuildPath, false /* recurse */, sketchBuildPath, sketchBuildPath) srcSubfolderPath := sketchBuildPath.Join("src") @@ -269,8 +275,18 @@ func (l *SketchLibrariesDetector) findIncludes( l.queueSourceFilesFromFolder(sourceFileQueue, srcSubfolderPath, true /* recurse */, sketchBuildPath, sketchBuildPath) } - for !sourceFileQueue.empty() { - err := l.findIncludesUntilDone(ctx, cache, sourceFileQueue, buildProperties, librariesBuildPath, platformArch) + allInstalledSorted := l.librariesManager.FindAllInstalled() + allInstalledSorted.SortByName() // Sort libraries to ensure consistent ordering + for _, library := range allInstalledSorted { + if library.Location == libraries.Profile { + l.logger.Info(i18n.Tr("The library %[1]s has been automatically added from sketch project.", library.Name)) + l.addAndBuildLibrary(sourceFileQueue, librariesBuildPath, library) + l.addIncludeFolder(library.SourceDir) + } + } + + for !sourceFileQueue.Empty() { + err := l.findMissingIncludesInCompilationUnit(ctx, sourceFileQueue, buildProperties, librariesBuildPath, platformArch) if err != nil { cachePath.Remove() return err @@ -278,8 +294,7 @@ func (l *SketchLibrariesDetector) findIncludes( } // Finalize the cache - cache.ExpectEnd() - if err := writeCache(cache, cachePath); err != nil { + if err := l.cache.Save(cachePath); err != nil { return err } } @@ -297,15 +312,14 @@ func (l *SketchLibrariesDetector) findIncludes( return nil } -func (l *SketchLibrariesDetector) findIncludesUntilDone( +func (l *SketchLibrariesDetector) findMissingIncludesInCompilationUnit( ctx context.Context, - cache *includeCache, sourceFileQueue *uniqueSourceFileQueue, buildProperties *properties.Map, librariesBuildPath *paths.Path, platformArch string, ) error { - sourceFile := sourceFileQueue.pop() + sourceFile := sourceFileQueue.Pop() sourcePath := sourceFile.SourcePath() targetFilePath := paths.NullPath() depPath := sourceFile.DepfilePath() @@ -330,7 +344,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( first := true for { - cache.ExpectFile(sourcePath) + l.cache.Expect(&detectorCacheEntry{CompilingSourcePath: 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 @@ -342,49 +356,51 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( } var preprocErr error - var preprocFirstResult preprocessor.Result + var preprocFirstResult *runner.Result var missingIncludeH string - if unchanged && cache.valid { - missingIncludeH = cache.Next().Include + if entry := l.cache.Peek(); unchanged && entry != nil && entry.MissingIncludeH != nil { + missingIncludeH = *entry.MissingIncludeH if first && l.logger.VerbosityLevel() == logger.VerbosityVerbose { l.logger.Info(i18n.Tr("Using cached library dependencies for file: %[1]s", sourcePath)) } + first = false } else { preprocFirstResult, preprocErr = preprocessor.GCC(ctx, sourcePath, targetFilePath, includeFolders, buildProperties) if l.logger.VerbosityLevel() == logger.VerbosityVerbose { - l.logger.WriteStdout(preprocFirstResult.Stdout()) + l.logger.WriteStdout(preprocFirstResult.Stdout) } // Unwrap error and see if it is an ExitError. var exitErr *exec.ExitError if preprocErr == nil { // Preprocessor successful, done missingIncludeH = "" - } else if isExitErr := errors.As(preprocErr, &exitErr); !isExitErr || preprocFirstResult.Stderr() == nil { + } else if isExitErr := errors.As(preprocErr, &exitErr); !isExitErr || len(preprocFirstResult.Stderr) == 0 { // Ignore ExitErrors (e.g. gcc returning non-zero status), but bail out on other errors return preprocErr } else { - missingIncludeH = IncludesFinderWithRegExp(string(preprocFirstResult.Stderr())) + missingIncludeH = IncludesFinderWithRegExp(string(preprocFirstResult.Stderr)) if missingIncludeH == "" && l.logger.VerbosityLevel() == logger.VerbosityVerbose { l.logger.Info(i18n.Tr("Error while detecting libraries included by %[1]s", sourcePath)) } } } + l.cache.Expect(&detectorCacheEntry{MissingIncludeH: &missingIncludeH}) + if missingIncludeH == "" { // No missing includes found, we're done - cache.ExpectEntry(sourcePath, "", nil) return nil } library := l.resolveLibrary(missingIncludeH, platformArch) if library == nil { // Library could not be resolved, show error - if preprocErr == nil || preprocFirstResult.Stderr() == nil { + if preprocErr == nil || len(preprocFirstResult.Stderr) == 0 { // Filename came from cache, so run preprocessor to obtain error to show result, err := preprocessor.GCC(ctx, sourcePath, targetFilePath, includeFolders, buildProperties) if l.logger.VerbosityLevel() == logger.VerbosityVerbose { - l.logger.WriteStdout(result.Stdout()) + l.logger.WriteStdout(result.Stdout) } if err == nil { // If there is a missing #include in the cache, but running @@ -393,33 +409,20 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone( // deleted, so hopefully the next compilation will succeed. return errors.New(i18n.Tr("Internal error in cache")) } - l.diagnosticStore.Parse(result.Args(), result.Stderr()) - l.logger.WriteStderr(result.Stderr()) + l.diagnosticStore.Parse(result.Args, result.Stderr) + l.logger.WriteStderr(result.Stderr) return err } - l.diagnosticStore.Parse(preprocFirstResult.Args(), preprocFirstResult.Stderr()) - l.logger.WriteStderr(preprocFirstResult.Stderr()) + l.diagnosticStore.Parse(preprocFirstResult.Args, preprocFirstResult.Stderr) + l.logger.WriteStderr(preprocFirstResult.Stderr) return preprocErr } // Add this library to the list of libraries, the // include path and queue its source files for further // include scanning - l.AppendImportedLibraries(library) - l.appendIncludeFolder(cache, sourcePath, missingIncludeH, library.SourceDir) - - if library.Precompiled && library.PrecompiledWithSources { - // Fully precompiled libraries should have no dependencies to avoid ABI breakage - if l.logger.VerbosityLevel() == logger.VerbosityVerbose { - l.logger.Info(i18n.Tr("Skipping dependencies detection for precompiled library %[1]s", library.Name)) - } - } else { - for _, sourceDir := range library.SourceDirs() { - l.queueSourceFilesFromFolder(sourceFileQueue, sourceDir.Dir, sourceDir.Recurse, - library.SourceDir, librariesBuildPath.Join(library.DirName), library.UtilityDir) - } - } - first = false + l.addAndBuildLibrary(sourceFileQueue, librariesBuildPath, library) + l.addIncludeFolder(library.SourceDir) } } @@ -445,7 +448,7 @@ func (l *SketchLibrariesDetector) queueSourceFilesFromFolder( if err != nil { return err } - sourceFileQueue.push(sourceFile) + sourceFileQueue.Push(sourceFile) } return nil @@ -501,97 +504,6 @@ func findIncludeForOldCompilers(source string) string { return "" } -type sourceFile struct { - // Path to the source file within the sketch/library root folder - 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 -} - -// Equals fixdoc -func (f *sourceFile) Equals(g *sourceFile) bool { - return f.relativePath.EqualsTo(g.relativePath) && - f.buildRoot.EqualsTo(g.buildRoot) && - f.sourceRoot.EqualsTo(g.sourceRoot) -} - -// makeSourceFile 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( - sourceDir *paths.Path, - buildDir *paths.Path, - sourceFilePath *paths.Path, - extraIncludePath ...*paths.Path, -) (*sourceFile, error) { - res := &sourceFile{ - buildRoot: buildDir, - sourceRoot: sourceDir, - } - - if len(extraIncludePath) > 1 { - panic("only one extra include path allowed") - } - if len(extraIncludePath) > 0 { - res.extraIncludePath = extraIncludePath[0] - } - // switch o := origin.(type) { - // case *sketch.Sketch: - // res.buildRoot = sketchBuildPath - // res.sourceRoot = sketchBuildPath - // case *libraries.Library: - // res.buildRoot = librariesBuildPath.Join(o.DirName) - // res.sourceRoot = o.SourceDir - // res.extraIncludePath = o.UtilityDir - // default: - // panic("Unexpected origin for SourceFile: " + fmt.Sprint(origin)) - // } - - if sourceFilePath.IsAbs() { - var err error - sourceFilePath, err = res.sourceRoot.RelTo(sourceFilePath) - if err != nil { - return nil, err - } - } - res.relativePath = sourceFilePath - return res, nil -} - -// ExtraIncludePath fixdoc -func (f *sourceFile) ExtraIncludePath() *paths.Path { - return f.extraIncludePath -} - -// SourcePath fixdoc -func (f *sourceFile) SourcePath() *paths.Path { - return f.sourceRoot.JoinPath(f.relativePath) -} - -// ObjectPath fixdoc -func (f *sourceFile) ObjectPath() *paths.Path { - return f.buildRoot.Join(f.relativePath.String() + ".o") -} - -// DepfilePath fixdoc -func (f *sourceFile) DepfilePath() *paths.Path { - return f.buildRoot.Join(f.relativePath.String() + ".d") -} - // LibrariesLoader todo func LibrariesLoader( useCachedLibrariesResolution bool, @@ -669,137 +581,3 @@ func LibrariesLoader( resolver := librariesresolver.NewCppResolver(allLibs, targetPlatform, actualPlatform) return lm, resolver, verboseOut.Bytes(), nil } - -type includeCacheEntry struct { - Sourcefile *paths.Path - Include string - Includepath *paths.Path -} - -// String fixdoc -func (entry *includeCacheEntry) String() string { - return fmt.Sprintf("SourceFile: %s; Include: %s; IncludePath: %s", - entry.Sourcefile, entry.Include, entry.Includepath) -} - -// Equals fixdoc -func (entry *includeCacheEntry) Equals(other *includeCacheEntry) bool { - return entry.String() == other.String() -} - -type includeCache struct { - // Are the cache contents valid so far? - valid bool - // Index into entries of the next entry to be processed. Unused - // when the cache is invalid. - next int - entries []*includeCacheEntry -} - -// Next Return the next cache entry. Should only be called when the cache is -// valid and a next entry is available (the latter can be checked with -// ExpectFile). Does not advance the cache. -func (cache *includeCache) Next() *includeCacheEntry { - return cache.entries[cache.next] -} - -// ExpectFile check that the next cache entry is about the given file. If it is -// not, or no entry is available, the cache is invalidated. Does not -// advance the cache. -func (cache *includeCache) ExpectFile(sourcefile *paths.Path) { - if cache.valid && (cache.next >= len(cache.entries) || !cache.Next().Sourcefile.EqualsTo(sourcefile)) { - cache.valid = false - cache.entries = cache.entries[:cache.next] - } -} - -// ExpectEntry check that the next entry matches the given values. If so, advance -// the cache. If not, the cache is invalidated. If the cache is -// invalidated, or was already invalid, an entry with the given values -// is appended. -func (cache *includeCache) ExpectEntry(sourcefile *paths.Path, include string, librarypath *paths.Path) { - entry := &includeCacheEntry{Sourcefile: sourcefile, Include: include, Includepath: librarypath} - if cache.valid { - if cache.next < len(cache.entries) && cache.Next().Equals(entry) { - cache.next++ - } else { - cache.valid = false - cache.entries = cache.entries[:cache.next] - } - } - - if !cache.valid { - cache.entries = append(cache.entries, entry) - } -} - -// ExpectEnd check that the cache is completely consumed. If not, the cache is -// invalidated. -func (cache *includeCache) ExpectEnd() { - if cache.valid && cache.next < len(cache.entries) { - cache.valid = false - cache.entries = cache.entries[:cache.next] - } -} - -// Read the cache from the given file -func readCache(path *paths.Path) *includeCache { - bytes, err := path.ReadFile() - if err != nil { - // Return an empty, invalid cache - return &includeCache{} - } - result := &includeCache{} - err = json.Unmarshal(bytes, &result.entries) - if err != nil { - // Return an empty, invalid cache - return &includeCache{} - } - result.valid = true - return result -} - -// Write the given cache to the given file if it is invalidated. If the -// cache is still valid, just update the timestamps of the file. -func writeCache(cache *includeCache, path *paths.Path) error { - // If the cache was still valid all the way, just touch its file - // (in case any source file changed without influencing the - // includes). If it was invalidated, overwrite the cache with - // the new contents. - if cache.valid { - path.Chtimes(time.Now(), time.Now()) - } else { - bytes, err := json.MarshalIndent(cache.entries, "", " ") - if err != nil { - return err - } - err = path.WriteFile(bytes) - if err != nil { - return err - } - } - return nil -} - -type uniqueSourceFileQueue []*sourceFile - -func (queue *uniqueSourceFileQueue) push(value *sourceFile) { - if !queue.contains(value) { - *queue = append(*queue, value) - } -} - -func (queue uniqueSourceFileQueue) contains(target *sourceFile) bool { - return slices.ContainsFunc(queue, target.Equals) -} - -func (queue *uniqueSourceFileQueue) pop() *sourceFile { - old := *queue - x := old[0] - *queue = old[1:] - return x -} - -func (queue uniqueSourceFileQueue) empty() bool { - return len(queue) == 0 -} diff --git a/internal/arduino/builder/internal/detector/source_file.go b/internal/arduino/builder/internal/detector/source_file.go new file mode 100644 index 00000000000..3ebb52d0387 --- /dev/null +++ b/internal/arduino/builder/internal/detector/source_file.go @@ -0,0 +1,124 @@ +// This file is part of arduino-cli. +// +// Copyright 2024 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 detector + +import ( + "slices" + + "github.com/arduino/go-paths-helper" +) + +type sourceFile struct { + // Path to the source file within the sketch/library root folder + 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 +} + +// Equals fixdoc +func (f *sourceFile) Equals(g *sourceFile) bool { + return f.relativePath.EqualsTo(g.relativePath) && + f.buildRoot.EqualsTo(g.buildRoot) && + f.sourceRoot.EqualsTo(g.sourceRoot) +} + +// makeSourceFile create a sourceFile object for the given source file path. +// The given sourceFilePath can be absolute, or relative within the sourceRoot root folder. +func makeSourceFile(sourceRoot, buildRoot, sourceFilePath *paths.Path, extraIncludePath ...*paths.Path) (*sourceFile, error) { + res := &sourceFile{ + buildRoot: buildRoot, + sourceRoot: sourceRoot, + } + + if len(extraIncludePath) > 1 { + panic("only one extra include path allowed") + } + if len(extraIncludePath) > 0 { + res.extraIncludePath = extraIncludePath[0] + } + + if sourceFilePath.IsAbs() { + var err error + sourceFilePath, err = res.sourceRoot.RelTo(sourceFilePath) + if err != nil { + return nil, err + } + } + res.relativePath = sourceFilePath + return res, nil +} + +// ExtraIncludePath returns the extra include path required to build the source file. +func (f *sourceFile) ExtraIncludePath() *paths.Path { + return f.extraIncludePath +} + +// SourcePath return the full path to the source file. +func (f *sourceFile) SourcePath() *paths.Path { + return f.sourceRoot.JoinPath(f.relativePath) +} + +// ObjectPath return the full path to the object file. +func (f *sourceFile) ObjectPath() *paths.Path { + return f.buildRoot.Join(f.relativePath.String() + ".o") +} + +// DepfilePath return the full path to the dependency file. +func (f *sourceFile) DepfilePath() *paths.Path { + return f.buildRoot.Join(f.relativePath.String() + ".d") +} + +// uniqueSourceFileQueue is a queue of source files that does not allow duplicates. +type uniqueSourceFileQueue []*sourceFile + +// Push adds a source file to the queue if it is not already present. +func (queue *uniqueSourceFileQueue) Push(value *sourceFile) { + if !queue.Contains(value) { + *queue = append(*queue, value) + } +} + +// Contains checks if the queue Contains a source file. +func (queue uniqueSourceFileQueue) Contains(target *sourceFile) bool { + return slices.ContainsFunc(queue, target.Equals) +} + +// Pop removes and returns the first element of the queue. +func (queue *uniqueSourceFileQueue) Pop() *sourceFile { + old := *queue + x := old[0] + *queue = old[1:] + return x +} + +// Empty returns true if the queue is Empty. +func (queue uniqueSourceFileQueue) Empty() bool { + return len(queue) == 0 +} diff --git a/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go b/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go index deabc04c4f0..e69adeae154 100644 --- a/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go +++ b/internal/arduino/builder/internal/preprocessor/arduino_preprocessor.go @@ -22,6 +22,7 @@ import ( "path/filepath" "runtime" + "github.com/arduino/arduino-cli/internal/arduino/builder/internal/runner" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" @@ -35,7 +36,7 @@ func PreprocessSketchWithArduinoPreprocessor( ctx context.Context, sk *sketch.Sketch, buildPath *paths.Path, includeFolders paths.PathList, lineOffset int, buildProperties *properties.Map, onlyUpdateCompilationDatabase bool, -) (*Result, error) { +) (*runner.Result, error) { verboseOut := &bytes.Buffer{} normalOut := &bytes.Buffer{} if err := buildPath.Join("preproc").MkdirAll(); err != nil { @@ -45,26 +46,26 @@ func PreprocessSketchWithArduinoPreprocessor( sourceFile := buildPath.Join("sketch", sk.MainFile.Base()+".cpp") targetFile := buildPath.Join("preproc", "sketch_merged.cpp") gccResult, err := GCC(ctx, sourceFile, targetFile, includeFolders, buildProperties) - verboseOut.Write(gccResult.Stdout()) - verboseOut.Write(gccResult.Stderr()) + verboseOut.Write(gccResult.Stdout) + verboseOut.Write(gccResult.Stderr) if err != nil { return nil, err } - arduiniPreprocessorProperties := properties.NewMap() - arduiniPreprocessorProperties.Set("tools.arduino-preprocessor.path", "{runtime.tools.arduino-preprocessor.path}") - arduiniPreprocessorProperties.Set("tools.arduino-preprocessor.cmd.path", "{path}/arduino-preprocessor") - arduiniPreprocessorProperties.Set("tools.arduino-preprocessor.pattern", `"{cmd.path}" "{source_file}" -- -std=gnu++11`) - arduiniPreprocessorProperties.Set("preproc.macros.flags", "-w -x c++ -E -CC") - arduiniPreprocessorProperties.Merge(buildProperties) - arduiniPreprocessorProperties.Merge(arduiniPreprocessorProperties.SubTree("tools").SubTree("arduino-preprocessor")) - arduiniPreprocessorProperties.SetPath("source_file", targetFile) - pattern := arduiniPreprocessorProperties.Get("pattern") + arduinoPreprocessorProperties := properties.NewMap() + arduinoPreprocessorProperties.Set("tools.arduino-preprocessor.path", "{runtime.tools.arduino-preprocessor.path}") + arduinoPreprocessorProperties.Set("tools.arduino-preprocessor.cmd.path", "{path}/arduino-preprocessor") + arduinoPreprocessorProperties.Set("tools.arduino-preprocessor.pattern", `"{cmd.path}" "{source_file}" -- -std=gnu++11`) + arduinoPreprocessorProperties.Set("preproc.macros.flags", "-w -x c++ -E -CC") + arduinoPreprocessorProperties.Merge(buildProperties) + arduinoPreprocessorProperties.Merge(arduinoPreprocessorProperties.SubTree("tools").SubTree("arduino-preprocessor")) + arduinoPreprocessorProperties.SetPath("source_file", targetFile) + pattern := arduinoPreprocessorProperties.Get("pattern") if pattern == "" { return nil, errors.New(i18n.Tr("arduino-preprocessor pattern is missing")) } - commandLine := arduiniPreprocessorProperties.ExpandPropsInString(pattern) + commandLine := arduinoPreprocessorProperties.ExpandPropsInString(pattern) parts, err := properties.SplitQuotedString(commandLine, `"'`, false) if err != nil { return nil, err @@ -83,13 +84,13 @@ func PreprocessSketchWithArduinoPreprocessor( commandStdOut, commandStdErr, err := command.RunAndCaptureOutput(ctx) verboseOut.Write(commandStdErr) if err != nil { - return &Result{args: gccResult.Args(), stdout: verboseOut.Bytes(), stderr: normalOut.Bytes()}, err + return &runner.Result{Args: gccResult.Args, Stdout: verboseOut.Bytes(), Stderr: normalOut.Bytes()}, err } result := utils.NormalizeUTF8(commandStdOut) destFile := buildPath.Join(sk.MainFile.Base() + ".cpp") if err := destFile.WriteFile(result); err != nil { - return &Result{args: gccResult.Args(), stdout: verboseOut.Bytes(), stderr: normalOut.Bytes()}, err + return &runner.Result{Args: gccResult.Args, Stdout: verboseOut.Bytes(), Stderr: normalOut.Bytes()}, err } - return &Result{args: gccResult.Args(), stdout: verboseOut.Bytes(), stderr: normalOut.Bytes()}, err + return &runner.Result{Args: gccResult.Args, Stdout: verboseOut.Bytes(), Stderr: normalOut.Bytes()}, err } diff --git a/internal/arduino/builder/internal/preprocessor/ctags.go b/internal/arduino/builder/internal/preprocessor/ctags.go index bfe24408b25..c09e24aeecd 100644 --- a/internal/arduino/builder/internal/preprocessor/ctags.go +++ b/internal/arduino/builder/internal/preprocessor/ctags.go @@ -27,6 +27,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/builder/cpp" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/preprocessor/internal/ctags" + "github.com/arduino/arduino-cli/internal/arduino/builder/internal/runner" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" "github.com/arduino/go-paths-helper" @@ -43,7 +44,7 @@ func PreprocessSketchWithCtags( sketch *sketch.Sketch, buildPath *paths.Path, includes paths.PathList, lineOffset int, buildProperties *properties.Map, onlyUpdateCompilationDatabase, verbose bool, -) (*Result, error) { +) (*runner.Result, error) { // Create a temporary working directory tmpDir, err := paths.MkTempDir("", "") if err != nil { @@ -57,11 +58,11 @@ func PreprocessSketchWithCtags( // Run GCC preprocessor sourceFile := buildPath.Join("sketch", sketch.MainFile.Base()+".cpp") result, err := GCC(ctx, sourceFile, ctagsTarget, includes, buildProperties) - stdout.Write(result.Stdout()) - stderr.Write(result.Stderr()) + stdout.Write(result.Stdout) + stderr.Write(result.Stderr) if err != nil { if !onlyUpdateCompilationDatabase { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } // Do not bail out if we are generating the compile commands database @@ -69,17 +70,17 @@ func PreprocessSketchWithCtags( i18n.Tr("An error occurred adding prototypes"), i18n.Tr("the compilation database may be incomplete or inaccurate")) if err := sourceFile.CopyTo(ctagsTarget); err != nil { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } } if src, err := ctagsTarget.ReadFile(); err == nil { filteredSource := filterSketchSource(sketch, bytes.NewReader(src), false, stderr) if err := ctagsTarget.WriteFile([]byte(filteredSource)); err != nil { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } } else { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } // Run CTags on gcc-preprocessed source @@ -89,7 +90,7 @@ func PreprocessSketchWithCtags( stderr.Write(ctagsStdErr) } if err != nil { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } // Parse CTags output @@ -104,13 +105,13 @@ func PreprocessSketchWithCtags( if sourceData, err := sourceFile.ReadFile(); err == nil { source = string(sourceData) } else { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } source = strings.ReplaceAll(source, "\r\n", "\n") source = strings.ReplaceAll(source, "\r", "\n") sourceRows := strings.Split(source, "\n") if isFirstFunctionOutsideOfSource(firstFunctionLine, sourceRows) { - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, nil + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, nil } insertionLine := firstFunctionLine + lineOffset - 1 @@ -136,7 +137,7 @@ func PreprocessSketchWithCtags( // Write back arduino-preprocess output to the sourceFile err = sourceFile.WriteFile([]byte(preprocessedSource)) - return &Result{args: result.Args(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: result.Args, Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } func composePrototypeSection(line int, prototypes []*ctags.Prototype) string { diff --git a/internal/arduino/builder/internal/preprocessor/gcc.go b/internal/arduino/builder/internal/preprocessor/gcc.go index f8d6100d10d..24364482a95 100644 --- a/internal/arduino/builder/internal/preprocessor/gcc.go +++ b/internal/arduino/builder/internal/preprocessor/gcc.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/arduino/arduino-cli/internal/arduino/builder/cpp" + "github.com/arduino/arduino-cli/internal/arduino/builder/internal/runner" "github.com/arduino/arduino-cli/internal/i18n" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" @@ -35,7 +36,7 @@ func GCC( ctx context.Context, sourceFilePath, targetFilePath *paths.Path, includes paths.PathList, buildProperties *properties.Map, -) (Result, error) { +) (*runner.Result, error) { gccBuildProperties := properties.NewMap() gccBuildProperties.Set("preproc.macros.flags", "-w -x c++ -E -CC") gccBuildProperties.Merge(buildProperties) @@ -60,14 +61,14 @@ func GCC( pattern := gccBuildProperties.Get(gccPreprocRecipeProperty) if pattern == "" { - return Result{}, errors.New(i18n.Tr("%s pattern is missing", gccPreprocRecipeProperty)) + return nil, errors.New(i18n.Tr("%s pattern is missing", gccPreprocRecipeProperty)) } commandLine := gccBuildProperties.ExpandPropsInString(pattern) commandLine = properties.DeleteUnexpandedPropsFromString(commandLine) args, err := properties.SplitQuotedString(commandLine, `"'`, false) if err != nil { - return Result{}, err + return nil, err } // Remove -MMD argument if present. Leaving it will make gcc try @@ -76,7 +77,7 @@ func GCC( proc, err := paths.NewProcess(nil, args...) if err != nil { - return Result{}, err + return nil, err } stdout := bytes.NewBuffer(nil) @@ -103,13 +104,13 @@ func GCC( fmt.Fprintln(stdout, strings.Join(args, " ")) if err := proc.Start(); err != nil { - return Result{}, err + return &runner.Result{}, err } // Wait for the process to finish err = proc.WaitWithinContext(ctx) - return Result{args: proc.GetArgs(), stdout: stdout.Bytes(), stderr: stderr.Bytes()}, err + return &runner.Result{Args: proc.GetArgs(), Stdout: stdout.Bytes(), Stderr: stderr.Bytes()}, err } type writerFunc func(p []byte) (n int, err error) diff --git a/internal/arduino/builder/internal/preprocessor/result.go b/internal/arduino/builder/internal/runner/task.go similarity index 76% rename from internal/arduino/builder/internal/preprocessor/result.go rename to internal/arduino/builder/internal/runner/task.go index 3fa45e40974..05d5f63105a 100644 --- a/internal/arduino/builder/internal/preprocessor/result.go +++ b/internal/arduino/builder/internal/runner/task.go @@ -13,22 +13,11 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package preprocessor +package runner +// Result contains the output of a command execution type Result struct { - args []string - stdout []byte - stderr []byte -} - -func (r Result) Args() []string { - return r.args -} - -func (r Result) Stdout() []byte { - return r.stdout -} - -func (r Result) Stderr() []byte { - return r.stderr + Args []string + Stdout []byte + Stderr []byte } diff --git a/internal/arduino/builder/preprocess_sketch.go b/internal/arduino/builder/preprocess_sketch.go index 290b2963664..b3b9a3d89f1 100644 --- a/internal/arduino/builder/preprocess_sketch.go +++ b/internal/arduino/builder/preprocess_sketch.go @@ -32,10 +32,10 @@ func (b *Builder) preprocessSketch(includes paths.PathList) error { ) if result != nil { if b.logger.VerbosityLevel() == logger.VerbosityVerbose { - b.logger.WriteStdout(result.Stdout()) + b.logger.WriteStdout(result.Stdout) } - b.logger.WriteStderr(result.Stderr()) - b.diagnosticStore.Parse(result.Args(), result.Stderr()) + b.logger.WriteStderr(result.Stderr) + b.diagnosticStore.Parse(result.Args, result.Stderr) } return err diff --git a/internal/arduino/libraries/libraries_location.go b/internal/arduino/libraries/libraries_location.go index a2a4423a54d..d815157bef3 100644 --- a/internal/arduino/libraries/libraries_location.go +++ b/internal/arduino/libraries/libraries_location.go @@ -40,6 +40,8 @@ const ( // Unmanaged is for libraries set manually by the user in the CLI command or from the gRPC function. // Ideally it's used for `libraries` outside folders managed by the CLI. Unmanaged + // Profile is for libraries that are part of a sketch profile + Profile ) func (d *LibraryLocation) String() string { @@ -54,6 +56,8 @@ func (d *LibraryLocation) String() string { return "user" case Unmanaged: return "unmanaged" + case Profile: + return "profile" default: panic(fmt.Sprintf("invalid LibraryLocation value %d", *d)) } @@ -86,6 +90,9 @@ func (d *LibraryLocation) UnmarshalJSON(b []byte) error { case "unmanaged": *d = Unmanaged return nil + case "profile": + *d = Profile + return nil default: return errors.New(i18n.Tr("invalid library location: %s", s)) } @@ -104,6 +111,8 @@ func (d *LibraryLocation) ToRPCLibraryLocation() rpc.LibraryLocation { return rpc.LibraryLocation_LIBRARY_LOCATION_USER case Unmanaged: return rpc.LibraryLocation_LIBRARY_LOCATION_UNMANAGED + case Profile: + return rpc.LibraryLocation_LIBRARY_LOCATION_PROFILE default: panic(fmt.Sprintf("invalid LibraryLocation value %d", *d)) } @@ -122,6 +131,8 @@ func FromRPCLibraryLocation(l rpc.LibraryLocation) LibraryLocation { return User case rpc.LibraryLocation_LIBRARY_LOCATION_UNMANAGED: return Unmanaged + case rpc.LibraryLocation_LIBRARY_LOCATION_PROFILE: + return Profile default: panic(fmt.Sprintf("invalid rpc.LibraryLocation value %d", l)) } diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go index 9798e59584a..e27b77c9235 100644 --- a/internal/cli/feedback/result/rpc.go +++ b/internal/cli/feedback/result/rpc.go @@ -172,6 +172,7 @@ const ( LibraryLocationPlatformBuiltin LibraryLocation = "platform" LibraryLocationReferencedPlatformBuiltin LibraryLocation = "ref-platform" LibraryLocationUnmanged LibraryLocation = "unmanaged" + LibraryLocationProfile LibraryLocation = "profile" ) func NewLibraryLocation(r rpc.LibraryLocation) LibraryLocation { @@ -186,6 +187,8 @@ func NewLibraryLocation(r rpc.LibraryLocation) LibraryLocation { return LibraryLocationUser case rpc.LibraryLocation_LIBRARY_LOCATION_UNMANAGED: return LibraryLocationUnmanged + case rpc.LibraryLocation_LIBRARY_LOCATION_PROFILE: + return LibraryLocationProfile } return LibraryLocationIDEBuiltin } diff --git a/rpc/cc/arduino/cli/commands/v1/lib.pb.go b/rpc/cc/arduino/cli/commands/v1/lib.pb.go index 0910be91d8a..cff75c6a941 100644 --- a/rpc/cc/arduino/cli/commands/v1/lib.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/lib.pb.go @@ -200,6 +200,8 @@ const ( LibraryLocation_LIBRARY_LOCATION_REFERENCED_PLATFORM_BUILTIN LibraryLocation = 3 // Outside the `libraries` folders managed by the CLI. LibraryLocation_LIBRARY_LOCATION_UNMANAGED LibraryLocation = 4 + // Library is part of the sketch profile. + LibraryLocation_LIBRARY_LOCATION_PROFILE LibraryLocation = 5 ) // Enum value maps for LibraryLocation. @@ -210,6 +212,7 @@ var ( 2: "LIBRARY_LOCATION_PLATFORM_BUILTIN", 3: "LIBRARY_LOCATION_REFERENCED_PLATFORM_BUILTIN", 4: "LIBRARY_LOCATION_UNMANAGED", + 5: "LIBRARY_LOCATION_PROFILE", } LibraryLocation_value = map[string]int32{ "LIBRARY_LOCATION_BUILTIN": 0, @@ -217,6 +220,7 @@ var ( "LIBRARY_LOCATION_PLATFORM_BUILTIN": 2, "LIBRARY_LOCATION_REFERENCED_PLATFORM_BUILTIN": 3, "LIBRARY_LOCATION_UNMANAGED": 4, + "LIBRARY_LOCATION_PROFILE": 5, } ) @@ -3206,7 +3210,7 @@ var file_cc_arduino_cli_commands_v1_lib_proto_rawDesc = []byte{ 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x46, 0x4c, 0x41, 0x54, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, - 0x10, 0x01, 0x2a, 0xc3, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4c, 0x6f, + 0x10, 0x01, 0x2a, 0xe1, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, @@ -3218,12 +3222,14 @@ var file_cc_arduino_cli_commands_v1_lib_proto_rawDesc = []byte{ 0x45, 0x4e, 0x43, 0x45, 0x44, 0x5f, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4d, - 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44, 0x10, 0x04, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, - 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x4c, 0x49, 0x42, 0x52, + 0x41, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x4f, + 0x46, 0x49, 0x4c, 0x45, 0x10, 0x05, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, + 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/cc/arduino/cli/commands/v1/lib.proto b/rpc/cc/arduino/cli/commands/v1/lib.proto index 1878b07ec53..9350440bb37 100644 --- a/rpc/cc/arduino/cli/commands/v1/lib.proto +++ b/rpc/cc/arduino/cli/commands/v1/lib.proto @@ -379,6 +379,8 @@ enum LibraryLocation { LIBRARY_LOCATION_REFERENCED_PLATFORM_BUILTIN = 3; // Outside the `libraries` folders managed by the CLI. LIBRARY_LOCATION_UNMANAGED = 4; + // Library is part of the sketch profile. + LIBRARY_LOCATION_PROFILE = 5; } message ZipLibraryInstallRequest {