From 036aedb623929d9b4a71390a1ce5864f832779ea Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 15 Oct 2024 12:14:39 +0200 Subject: [PATCH] Fixed charset handling in reader for dep files --- .../arduino/builder/internal/utils/utils.go | 99 +++++++++++-------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/internal/arduino/builder/internal/utils/utils.go b/internal/arduino/builder/internal/utils/utils.go index 2c44cbeddab..7d3f8b672ea 100644 --- a/internal/arduino/builder/internal/utils/utils.go +++ b/internal/arduino/builder/internal/utils/utils.go @@ -17,6 +17,7 @@ package utils import ( "os" + "runtime" "strings" "unicode" @@ -96,57 +97,71 @@ func ObjFileIsUpToDate(sourceFile, objectFile, dependencyFile *paths.Path) (bool return f.Filter(rows, f.NotEquals("")), nil } - rows, err := readDepFileWithEncoding(nil) - if err != nil { - logrus.Debugf("Could not read dependency file: %s", dependencyFile) - return false, err - } - if len(rows) == 0 { - return true, nil - } - - firstRow := rows[0] - if !strings.HasSuffix(firstRow, ":") { - logrus.Debugf("No colon in first line of depfile") - return false, nil - } - objFileInDepFile := firstRow[:len(firstRow)-1] - if objFileInDepFile != objectFile.String() { - logrus.Debugf("Depfile is about different object file: %v", objFileInDepFile) - return false, nil - } - - // The first line of the depfile contains the path to the object file to generate. - // The second line of the depfile contains the path to the source file. - // All subsequent lines contain the header files necessary to compile the object file. - - // If we don't do this check it might happen that trying to compile a source file - // that has the same name but a different path wouldn't recreate the object file. - if sourceFile.String() != strings.Trim(rows[1], " ") { - logrus.Debugf("Depfile is about different source file: %v", strings.Trim(rows[1], " ")) - return false, nil - } + checkDepFileWithEncoding := func(mapping *charmap.Charmap) (bool, error) { + rows, err := readDepFileWithEncoding(mapping) + if err != nil { + logrus.Debugf("Could not read dependency file: %s", dependencyFile) + return false, err + } + if len(rows) == 0 { + return true, nil + } - rows = rows[1:] - for _, row := range rows { - depStat, err := os.Stat(row) - if err != nil && !os.IsNotExist(err) { - // There is probably a parsing error of the dep file - // Ignore the error and trigger a full rebuild anyway - logrus.WithError(err).Debugf("Failed to read: %v", row) + firstRow := rows[0] + if !strings.HasSuffix(firstRow, ":") { + logrus.Debugf("No colon in first line of depfile") return false, nil } - if os.IsNotExist(err) { - logrus.Debugf("Not found: %v", row) + objFileInDepFile := firstRow[:len(firstRow)-1] + if objFileInDepFile != objectFile.String() { + logrus.Debugf("Depfile is about different object file: %v", objFileInDepFile) return false, nil } - if depStat.ModTime().After(objectFileStat.ModTime()) { - logrus.Debugf("%v newer than %v", row, objectFile) + + // The first line of the depfile contains the path to the object file to generate. + // The second line of the depfile contains the path to the source file. + // All subsequent lines contain the header files necessary to compile the object file. + + // If we don't do this check it might happen that trying to compile a source file + // that has the same name but a different path wouldn't recreate the object file. + if sourceFile.String() != strings.Trim(rows[1], " ") { + logrus.Debugf("Depfile is about different source file: %v", strings.Trim(rows[1], " ")) return false, nil } + + rows = rows[1:] + for _, row := range rows { + depStat, err := os.Stat(row) + if err != nil && !os.IsNotExist(err) { + // There is probably a parsing error of the dep file + // Ignore the error and trigger a full rebuild anyway + logrus.WithError(err).Debugf("Failed to read: %v", row) + return false, nil + } + if os.IsNotExist(err) { + logrus.Debugf("Not found: %v", row) + return false, nil + } + if depStat.ModTime().After(objectFileStat.ModTime()) { + logrus.Debugf("%v newer than %v", row, objectFile) + return false, nil + } + } + + return true, nil } - return true, nil + // This is required because on Windows we don't know which encoding is used + // by gcc to write the dep file (it could be UTF-8 or any of the Windows + // default mappings. Would ISO8859_1 be enough? Or we should differentiate the + // various ISO8859_XX based on selected locale? Only time will tell...). + if runtime.GOOS == "windows" { + if upToDate, err := checkDepFileWithEncoding(charmap.ISO8859_1); err == nil { + return upToDate, nil + } + // Fallback to UTF-8... + } + return checkDepFileWithEncoding(nil) } func removeEndingBackSlash(s string) string {