Skip to content

Commit

Permalink
introduce the Result struct returnedby the proprocessing funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
alessio-perugini committed Jan 31, 2024
1 parent 985f8d8 commit ff36bba
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 60 deletions.
4 changes: 2 additions & 2 deletions internal/arduino/builder/compilation.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ func (b *Builder) compileFileWithRecipe(

// Parse the output of the compiler to gather errors and warnings...
if b.diagnosticsManager != nil {
b.diagnosticsManager.ParseOutput(command.GetArgs(), commandStdout.Bytes())
b.diagnosticsManager.ParseOutput(command.GetArgs(), commandStderr.Bytes())
b.diagnosticsManager.Parse(command.GetArgs(), commandStdout.Bytes())
b.diagnosticsManager.Parse(command.GetArgs(), commandStderr.Bytes())
}

// ...and then return the error
Expand Down
26 changes: 14 additions & 12 deletions internal/arduino/builder/internal/detector/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
}

var preprocErr error
var preprocStderr []byte
var preprocFirstResult preprocessor.Result

var missingIncludeH string
if unchanged && cache.valid {
Expand All @@ -350,21 +350,20 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
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, l.diagnosticManager)
preprocFirstResult, preprocErr = preprocessor.GCC(sourcePath, targetFilePath, includeFolders, buildProperties)
if l.logger.Verbose() {
l.logger.WriteStdout(preprocStdout)
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 || preprocStderr == nil {
} else if isExitErr := errors.As(preprocErr, &exitErr); !isExitErr || preprocFirstResult.Stderr() == nil {
// Ignore ExitErrors (e.g. gcc returning non-zero status), but bail out on other errors
return preprocErr
} else {
missingIncludeH = IncludesFinderWithRegExp(string(preprocStderr))
missingIncludeH = IncludesFinderWithRegExp(string(preprocFirstResult.Stderr()))
if missingIncludeH == "" && l.logger.Verbose() {
l.logger.Info(tr("Error while detecting libraries included by %[1]s", sourcePath))
}
Expand All @@ -380,22 +379,25 @@ func (l *SketchLibrariesDetector) findIncludesUntilDone(
library := l.resolveLibrary(missingIncludeH, platformArch)
if library == nil {
// Library could not be resolved, show error
if preprocErr == nil || preprocStderr == nil {
if preprocErr == nil || preprocFirstResult.Stderr() == nil {
// Filename came from cache, so run preprocessor to obtain error to show
var preprocStdout []byte
preprocStdout, preprocStderr, preprocErr = preprocessor.GCC(sourcePath, targetFilePath, includeFolders, buildProperties, l.diagnosticManager)
result, err := preprocessor.GCC(sourcePath, targetFilePath, includeFolders, buildProperties)
if l.logger.Verbose() {
l.logger.WriteStdout(preprocStdout)
l.logger.WriteStdout(result.Stdout())
}
if preprocErr == nil {
if err == nil {
// If there is a missing #include in the cache, but running
// gcc does not reproduce that, there is something wrong.
// Returning an error here will cause the cache to be
// deleted, so hopefully the next compilation will succeed.
return errors.New(tr("Internal error in cache"))
}
l.diagnosticManager.Parse(result.Args(), result.Stderr())
l.logger.WriteStderr(result.Stderr())
return err
}
l.logger.WriteStderr(preprocStderr)
l.diagnosticManager.Parse(preprocFirstResult.Args(), preprocFirstResult.Stderr())
l.logger.WriteStderr(preprocFirstResult.Stderr())
return preprocErr
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"path/filepath"
"runtime"

"github.com/arduino/arduino-cli/internal/arduino/builder/internal/diagnosticmanager"
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils"
"github.com/arduino/arduino-cli/internal/arduino/sketch"
"github.com/arduino/go-paths-helper"
Expand All @@ -34,21 +33,20 @@ import (
func PreprocessSketchWithArduinoPreprocessor(
sk *sketch.Sketch, buildPath *paths.Path, includeFolders paths.PathList,
lineOffset int, buildProperties *properties.Map, onlyUpdateCompilationDatabase bool,
diagnosticmanager *diagnosticmanager.Manager,
) ([]byte, []byte, error) {
) (Result, error) {
verboseOut := &bytes.Buffer{}
normalOut := &bytes.Buffer{}
if err := buildPath.Join("preproc").MkdirAll(); err != nil {
return nil, nil, err
return Result{}, err
}

sourceFile := buildPath.Join("sketch", sk.MainFile.Base()+".cpp")
targetFile := buildPath.Join("preproc", "sketch_merged.cpp")
gccStdout, gccStderr, err := GCC(sourceFile, targetFile, includeFolders, buildProperties, diagnosticmanager)
verboseOut.Write(gccStdout)
verboseOut.Write(gccStderr)
gccResult, err := GCC(sourceFile, targetFile, includeFolders, buildProperties)
verboseOut.Write(gccResult.Stdout())
verboseOut.Write(gccResult.Stderr())
if err != nil {
return nil, nil, err
return Result{}, err
}

arduiniPreprocessorProperties := properties.NewMap()
Expand All @@ -61,18 +59,18 @@ func PreprocessSketchWithArduinoPreprocessor(
arduiniPreprocessorProperties.SetPath("source_file", targetFile)
pattern := arduiniPreprocessorProperties.Get("pattern")
if pattern == "" {
return nil, nil, errors.New(tr("arduino-preprocessor pattern is missing"))
return Result{}, errors.New(tr("arduino-preprocessor pattern is missing"))
}

commandLine := arduiniPreprocessorProperties.ExpandPropsInString(pattern)
parts, err := properties.SplitQuotedString(commandLine, `"'`, false)
if err != nil {
return nil, nil, err
return Result{}, err
}

command, err := paths.NewProcess(nil, parts...)
if err != nil {
return nil, nil, err
return Result{}, err
}
if runtime.GOOS == "windows" {
// chdir in the uppermost directory to avoid UTF-8 bug in clang (https://github.com/arduino/arduino-preprocessor/issues/2)
Expand All @@ -83,14 +81,13 @@ func PreprocessSketchWithArduinoPreprocessor(
commandStdOut, commandStdErr, err := command.RunAndCaptureOutput(context.Background())
verboseOut.Write(commandStdErr)
if err != nil {
return normalOut.Bytes(), verboseOut.Bytes(), err
return 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 normalOut.Bytes(), verboseOut.Bytes(), err
return Result{args: gccResult.Args(), stdout: verboseOut.Bytes(), stderr: normalOut.Bytes()}, err
}

return normalOut.Bytes(), verboseOut.Bytes(), err
return Result{args: gccResult.Args(), stdout: verboseOut.Bytes(), stderr: normalOut.Bytes()}, err
}
30 changes: 14 additions & 16 deletions internal/arduino/builder/internal/preprocessor/ctags.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"strings"

"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/diagnosticmanager"
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/preprocessor/internal/ctags"
"github.com/arduino/arduino-cli/internal/arduino/sketch"
"github.com/arduino/arduino-cli/internal/i18n"
Expand All @@ -44,12 +43,11 @@ var DebugPreprocessor bool
func PreprocessSketchWithCtags(
sketch *sketch.Sketch, buildPath *paths.Path, includes paths.PathList,
lineOffset int, buildProperties *properties.Map, onlyUpdateCompilationDatabase bool,
diagnosticManager *diagnosticmanager.Manager,
) ([]byte, []byte, error) {
) (Result, error) {
// Create a temporary working directory
tmpDir, err := paths.MkTempDir("", "")
if err != nil {
return nil, nil, err
return Result{}, err
}
defer tmpDir.RemoveAll()
ctagsTarget := tmpDir.Join("sketch_merged.cpp")
Expand All @@ -59,38 +57,38 @@ func PreprocessSketchWithCtags(

// Run GCC preprocessor
sourceFile := buildPath.Join("sketch", sketch.MainFile.Base()+".cpp")
gccStdout, gccStderr, err := GCC(sourceFile, ctagsTarget, includes, buildProperties, diagnosticManager)
verboseOutput.Write(gccStdout)
verboseOutput.Write(gccStderr)
normalOutput.Write(gccStderr)
result, err := GCC(sourceFile, ctagsTarget, includes, buildProperties)
verboseOutput.Write(result.Stdout())
verboseOutput.Write(result.Stderr())
normalOutput.Write(result.Stderr())
if err != nil {
if !onlyUpdateCompilationDatabase {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}

// Do not bail out if we are generating the compile commands database
normalOutput.WriteString(fmt.Sprintf("%s: %s",
tr("An error occurred adding prototypes"),
tr("the compilation database may be incomplete or inaccurate")))
if err := sourceFile.CopyTo(ctagsTarget); err != nil {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}
}

if src, err := ctagsTarget.ReadFile(); err == nil {
filteredSource := filterSketchSource(sketch, bytes.NewReader(src), false)
if err := ctagsTarget.WriteFile([]byte(filteredSource)); err != nil {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}
} else {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}

// Run CTags on gcc-preprocessed source
ctagsOutput, ctagsStdErr, err := RunCTags(ctagsTarget, buildProperties)
verboseOutput.Write(ctagsStdErr)
if err != nil {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}

// Parse CTags output
Expand All @@ -105,13 +103,13 @@ func PreprocessSketchWithCtags(
if sourceData, err := sourceFile.ReadFile(); err == nil {
source = string(sourceData)
} else {
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.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 normalOutput.Bytes(), verboseOutput.Bytes(), nil
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, nil
}

insertionLine := firstFunctionLine + lineOffset - 1
Expand All @@ -137,7 +135,7 @@ func PreprocessSketchWithCtags(

// Write back arduino-preprocess output to the sourceFile
err = sourceFile.WriteFile([]byte(preprocessedSource))
return normalOutput.Bytes(), verboseOutput.Bytes(), err
return Result{args: result.Args(), stdout: verboseOutput.Bytes(), stderr: normalOutput.Bytes()}, err
}

func composePrototypeSection(line int, prototypes []*ctags.Prototype) string {
Expand Down
16 changes: 5 additions & 11 deletions internal/arduino/builder/internal/preprocessor/gcc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (

f "github.com/arduino/arduino-cli/internal/algorithms"
"github.com/arduino/arduino-cli/internal/arduino/builder/cpp"
"github.com/arduino/arduino-cli/internal/arduino/builder/internal/diagnosticmanager"
"github.com/arduino/go-paths-helper"
"github.com/arduino/go-properties-orderedmap"
)
Expand All @@ -33,8 +32,7 @@ import (
func GCC(
sourceFilePath, targetFilePath *paths.Path,
includes paths.PathList, buildProperties *properties.Map,
diagnosticManager *diagnosticmanager.Manager,
) ([]byte, []byte, error) {
) (Result, error) {
gccBuildProperties := properties.NewMap()
gccBuildProperties.Set("preproc.macros.flags", "-w -x c++ -E -CC")
gccBuildProperties.Merge(buildProperties)
Expand All @@ -59,14 +57,14 @@ func GCC(

pattern := gccBuildProperties.Get(gccPreprocRecipeProperty)
if pattern == "" {
return nil, nil, errors.New(tr("%s pattern is missing", gccPreprocRecipeProperty))
return Result{}, errors.New(tr("%s pattern is missing", gccPreprocRecipeProperty))
}

commandLine := gccBuildProperties.ExpandPropsInString(pattern)
commandLine = properties.DeleteUnexpandedPropsFromString(commandLine)
args, err := properties.SplitQuotedString(commandLine, `"'`, false)
if err != nil {
return nil, nil, err
return Result{}, err
}

// Remove -MMD argument if present. Leaving it will make gcc try
Expand All @@ -75,16 +73,12 @@ func GCC(

proc, err := paths.NewProcess(nil, args...)
if err != nil {
return nil, nil, err
return Result{}, err
}
stdout, stderr, err := proc.RunAndCaptureOutput(context.Background())

if diagnosticManager != nil {
diagnosticManager.ParseOutput(proc.GetArgs(), stderr)
}

// Append gcc arguments to stdout
stdout = append([]byte(fmt.Sprintln(strings.Join(args, " "))), stdout...)

return stdout, stderr, err
return Result{args: proc.GetArgs(), stdout: stdout, stderr: stderr}, err
}
19 changes: 19 additions & 0 deletions internal/arduino/builder/internal/preprocessor/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package preprocessor

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
}
8 changes: 4 additions & 4 deletions internal/arduino/builder/preprocess_sketch.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ import (
// preprocessSketch fixdoc
func (b *Builder) preprocessSketch(includes paths.PathList) error {
// In the future we might change the preprocessor
normalOutput, verboseOutput, err := preprocessor.PreprocessSketchWithCtags(
result, err := preprocessor.PreprocessSketchWithCtags(
b.sketch, b.buildPath, includes, b.lineOffset,
b.buildProperties, b.onlyUpdateCompilationDatabase,
b.diagnosticsManager,
)
if b.logger.Verbose() {
b.logger.WriteStdout(verboseOutput)
b.logger.WriteStdout(result.Stdout())
} else {
b.logger.WriteStdout(normalOutput)
b.logger.WriteStdout(result.Stderr())
}
b.diagnosticsManager.Parse(result.Args(), result.Stderr())

return err
}

0 comments on commit ff36bba

Please sign in to comment.