Skip to content

Commit 1ca362c

Browse files
committed
DRAFT
1 parent a5c79c7 commit 1ca362c

File tree

3 files changed

+89
-14
lines changed

3 files changed

+89
-14
lines changed

internal/arduino/builder/internal/detector/cache.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/runner"
2323
"github.com/arduino/go-paths-helper"
24+
"github.com/sirupsen/logrus"
2425
)
2526

2627
type detectorCache struct {
@@ -83,6 +84,15 @@ func (c *detectorCache) Load(cacheFile *paths.Path) error {
8384
if err := json.Unmarshal(data, &entries); err != nil {
8485
return err
8586
}
87+
// Check for invalid entries (stale files from previous Arduino CLI versions)
88+
for _, entry := range entries {
89+
if entry == nil {
90+
return nil
91+
}
92+
if entry.Compile != nil && entry.CompileTask == nil {
93+
return nil
94+
}
95+
}
8696
c.curr = 0
8797
c.entries = entries
8898
return nil
@@ -91,11 +101,14 @@ func (c *detectorCache) Load(cacheFile *paths.Path) error {
91101
// Expect adds an entry to the cache and checks if it matches the next expected entry.
92102
func (c *detectorCache) Expect(entry *detectorCacheEntry) {
93103
if c.curr < len(c.entries) {
104+
logrus.Debugf("Expecting cache entry: %s", entry)
94105
if c.entries[c.curr].Equals(entry) {
95106
// Cache hit, move to the next entry
96107
c.curr++
108+
logrus.Debugf(" CACHE HIT!")
97109
return
98110
}
111+
logrus.Debugf(" Cache MISMATCH!")
99112
// Cache mismatch, invalidate and cut the remainder of the cache
100113
c.entries = c.entries[:c.curr]
101114
}

internal/arduino/builder/internal/detector/detector.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
"github.com/arduino/arduino-cli/internal/i18n"
4242
"github.com/arduino/go-paths-helper"
4343
"github.com/arduino/go-properties-orderedmap"
44+
"github.com/sirupsen/logrus"
4445
)
4546

4647
type libraryResolutionResult struct {
@@ -273,8 +274,9 @@ func (l *SketchLibrariesDetector) findIncludes(
273274
l.preRunner = runner.New(ctx, jobs)
274275
for _, entry := range l.cache.EntriesAhead() {
275276
if entry.Compile != nil && entry.CompileTask != nil {
276-
upToDate, _ := entry.Compile.ObjFileIsUpToDate()
277+
upToDate, _ := entry.Compile.ObjFileIsUpToDate(logrus.WithField("source_file", entry.Compile.SourcePath))
277278
if !upToDate {
279+
_ = entry.Compile.PrepareBuildPath()
278280
l.preRunner.Enqueue(entry.CompileTask)
279281
}
280282
}
@@ -360,7 +362,8 @@ func (l *SketchLibrariesDetector) gccPreprocessTask(sourceFile *sourceFile, buil
360362
includeFolders = append(includeFolders, extraInclude)
361363
}
362364

363-
return preprocessor.GCC(sourceFile.SourcePath, paths.NullPath(), includeFolders, buildProperties, nil)
365+
_ = sourceFile.PrepareBuildPath()
366+
return preprocessor.GCC(sourceFile.SourcePath, paths.NullPath(), includeFolders, buildProperties, sourceFile.DepfilePath)
364367
}
365368

366369
func (l *SketchLibrariesDetector) findMissingIncludesInCompilationUnit(
@@ -385,7 +388,7 @@ func (l *SketchLibrariesDetector) findMissingIncludesInCompilationUnit(
385388
// TODO: This reads the dependency file, but the actual building
386389
// does it again. Should the result be somehow cached? Perhaps
387390
// remove the object file if it is found to be stale?
388-
unchanged, err := sourceFile.ObjFileIsUpToDate()
391+
unchanged, err := sourceFile.ObjFileIsUpToDate(logrus.WithField("source_file", sourcePath))
389392
if err != nil {
390393
return err
391394
}
@@ -533,8 +536,7 @@ func (l *SketchLibrariesDetector) makeSourceFile(sourceRoot, buildRoot, sourceFi
533536
}
534537
res := &sourceFile{
535538
SourcePath: sourceRoot.JoinPath(sourceFilePath),
536-
ObjectPath: buildRoot.Join(sourceFilePath.String() + ".o"),
537-
DepfilePath: buildRoot.Join(sourceFilePath.String() + ".d"),
539+
DepfilePath: buildRoot.Join(fmt.Sprintf("%s.libsdetect.d", sourceFilePath)),
538540
ExtraIncludePath: extraIncludePath,
539541
}
540542
return res, nil

internal/arduino/builder/internal/detector/source_file.go

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ import (
1919
"fmt"
2020
"slices"
2121

22-
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
22+
"os"
23+
24+
"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
2325
"github.com/arduino/go-paths-helper"
26+
"github.com/sirupsen/logrus"
2427
)
2528

2629
type sourceFile struct {
2730
// SourcePath is the path to the source file
2831
SourcePath *paths.Path `json:"source_path"`
2932

30-
// ObjectPath is the path to the object file that will be generated
31-
ObjectPath *paths.Path `json:"object_path"`
32-
3333
// DepfilePath is the path to the dependency file that will be generated
3434
DepfilePath *paths.Path `json:"depfile_path"`
3535

@@ -41,22 +41,82 @@ type sourceFile struct {
4141
}
4242

4343
func (f *sourceFile) String() string {
44-
return fmt.Sprintf("SourcePath:%s SourceRoot:%s BuildRoot:%s ExtraInclude:%s",
45-
f.SourcePath, f.ObjectPath, f.DepfilePath, f.ExtraIncludePath)
44+
return fmt.Sprintf("%s -> dep:%s (ExtraInclude:%s)",
45+
f.SourcePath, f.DepfilePath, f.ExtraIncludePath)
4646
}
4747

4848
// Equals checks if a sourceFile is equal to another.
4949
func (f *sourceFile) Equals(g *sourceFile) bool {
5050
return f.SourcePath.EqualsTo(g.SourcePath) &&
51-
f.ObjectPath.EqualsTo(g.ObjectPath) &&
5251
f.DepfilePath.EqualsTo(g.DepfilePath) &&
5352
((f.ExtraIncludePath == nil && g.ExtraIncludePath == nil) ||
5453
(f.ExtraIncludePath != nil && g.ExtraIncludePath != nil && f.ExtraIncludePath.EqualsTo(g.ExtraIncludePath)))
5554
}
5655

56+
// PrepareBuildPath ensures that the directory for the dependency file exists.
57+
func (f *sourceFile) PrepareBuildPath() error {
58+
if f.DepfilePath != nil {
59+
return f.DepfilePath.Parent().MkdirAll()
60+
}
61+
return nil
62+
}
63+
5764
// ObjFileIsUpToDate checks if the compile object file is up to date.
58-
func (f *sourceFile) ObjFileIsUpToDate() (unchanged bool, err error) {
59-
return utils.ObjFileIsUpToDate(f.SourcePath, f.ObjectPath, f.DepfilePath)
65+
func (f *sourceFile) ObjFileIsUpToDate(log *logrus.Entry) (unchanged bool, err error) {
66+
log.Debugf("Checking previous results for %v (dep = %v)", f.SourcePath, f.DepfilePath)
67+
if f.DepfilePath == nil {
68+
log.Debugf(" Object file or dependency file not provided")
69+
return false, nil
70+
}
71+
72+
sourceFile := f.SourcePath.Clean()
73+
sourceFileStat, err := sourceFile.Stat()
74+
if err != nil {
75+
log.Debugf(" Could not stat source file: %s", err)
76+
return false, err
77+
}
78+
dependencyFile := f.DepfilePath.Clean()
79+
dependencyFileStat, err := dependencyFile.Stat()
80+
if err != nil {
81+
if os.IsNotExist(err) {
82+
log.Debugf(" Dependency file not found: %v", dependencyFile)
83+
return false, nil
84+
}
85+
log.Debugf(" Could not stat dependency file: %s", err)
86+
return false, err
87+
}
88+
if sourceFileStat.ModTime().After(dependencyFileStat.ModTime()) {
89+
log.Debugf(" %v newer than %v", sourceFile, dependencyFile)
90+
return false, nil
91+
}
92+
deps, err := cpp.ReadDepFile(dependencyFile)
93+
if err != nil {
94+
log.Debugf(" Could not read dependency file: %s", dependencyFile)
95+
return false, err
96+
}
97+
if len(deps.Dependencies) == 0 {
98+
return true, nil
99+
}
100+
if deps.Dependencies[0] != sourceFile.String() {
101+
log.Debugf(" Depfile is about different source file: %v (expected %v)", deps.Dependencies[0], sourceFile)
102+
return false, nil
103+
}
104+
for _, dep := range deps.Dependencies[1:] {
105+
depStat, err := os.Stat(dep)
106+
if os.IsNotExist(err) {
107+
log.Debugf(" Not found: %v", dep)
108+
return false, nil
109+
}
110+
if err != nil {
111+
logrus.WithError(err).Debugf(" Failed to read: %v", dep)
112+
return false, nil
113+
}
114+
if depStat.ModTime().After(dependencyFileStat.ModTime()) {
115+
log.Debugf(" %v newer than %v", dep, dependencyFile)
116+
return false, nil
117+
}
118+
}
119+
return true, nil
60120
}
61121

62122
// uniqueSourceFileQueue is a queue of source files that does not allow duplicates.

0 commit comments

Comments
 (0)