Skip to content

Commit 0585435

Browse files
authored
[skip-changelog] legacy: Arduino preprocess subroutine refactorization (part 4) (#2194)
* Simplified GCCPreprocRunner function * Renamed variable * Removed dependency on builder ctx in GCCPreprocRunner * Moved GCCPreprocRunner into proper place * Replaced algorithm with stdlib equivalent * Reduced public API surface of CTags parser * Renamed variable for lint checks
1 parent 9ce2904 commit 0585435

11 files changed

+117
-104
lines changed

Diff for: arduino/builder/preprocessor/gcc.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package preprocessor
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"strings"
22+
23+
"github.com/arduino/arduino-cli/executils"
24+
f "github.com/arduino/arduino-cli/internal/algorithms"
25+
"github.com/arduino/arduino-cli/legacy/builder/utils"
26+
"github.com/arduino/go-paths-helper"
27+
"github.com/arduino/go-properties-orderedmap"
28+
"github.com/pkg/errors"
29+
)
30+
31+
// GCC performs a run of the gcc preprocess (macro/includes expansion). The function outputs the result
32+
// to targetFilePath. Returns the stdout/stderr of gcc if any.
33+
func GCC(sourceFilePath *paths.Path, targetFilePath *paths.Path, includes paths.PathList, buildProperties *properties.Map) ([]byte, []byte, error) {
34+
gccBuildProperties := properties.NewMap()
35+
gccBuildProperties.Set("preproc.macros.flags", "-w -x c++ -E -CC")
36+
gccBuildProperties.Merge(buildProperties)
37+
gccBuildProperties.Set("build.library_discovery_phase", "1")
38+
gccBuildProperties.SetPath("source_file", sourceFilePath)
39+
gccBuildProperties.SetPath("preprocessed_file_path", targetFilePath)
40+
41+
includesStrings := f.Map(includes.AsStrings(), utils.WrapWithHyphenI)
42+
gccBuildProperties.Set("includes", strings.Join(includesStrings, " "))
43+
44+
const gccPreprocRecipeProperty = "recipe.preproc.macros"
45+
if gccBuildProperties.Get(gccPreprocRecipeProperty) == "" {
46+
// autogenerate preprocess macros recipe from compile recipe
47+
preprocPattern := gccBuildProperties.Get("recipe.cpp.o.pattern")
48+
// add {preproc.macros.flags} to {compiler.cpp.flags}
49+
preprocPattern = strings.Replace(preprocPattern, "{compiler.cpp.flags}", "{compiler.cpp.flags} {preproc.macros.flags}", 1)
50+
// replace "{object_file}" with "{preprocessed_file_path}"
51+
preprocPattern = strings.Replace(preprocPattern, "{object_file}", "{preprocessed_file_path}", 1)
52+
53+
gccBuildProperties.Set(gccPreprocRecipeProperty, preprocPattern)
54+
}
55+
56+
pattern := gccBuildProperties.Get(gccPreprocRecipeProperty)
57+
if pattern == "" {
58+
return nil, nil, errors.Errorf(tr("%s pattern is missing"), gccPreprocRecipeProperty)
59+
}
60+
61+
commandLine := gccBuildProperties.ExpandPropsInString(pattern)
62+
args, err := properties.SplitQuotedString(commandLine, `"'`, false)
63+
if err != nil {
64+
return nil, nil, err
65+
}
66+
67+
// Remove -MMD argument if present. Leaving it will make gcc try
68+
// to create a /dev/null.d dependency file, which won't work.
69+
args = f.Filter(args, f.NotEquals("-MMD"))
70+
71+
proc, err := executils.NewProcess(nil, args...)
72+
if err != nil {
73+
return nil, nil, err
74+
}
75+
stdout, stderr, err := proc.RunAndCaptureOutput(context.Background())
76+
77+
// Append gcc arguments to stdout
78+
stdout = append([]byte(fmt.Sprintln(strings.Join(args, " "))), stdout...)
79+
80+
return stdout, stderr, err
81+
}

Diff for: legacy/builder/container_add_prototypes.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ func PreprocessSketchWithCtags(ctx *types.Context) error {
4040

4141
// Run preprocessor
4242
sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Base() + ".cpp")
43-
stderr, err := GCCPreprocRunner(ctx, sourceFile, targetFilePath, ctx.IncludeFolders)
44-
ctx.WriteStderr(stderr)
43+
gccStdout, gccStderr, err := preprocessor.GCC(sourceFile, targetFilePath, ctx.IncludeFolders, ctx.BuildProperties)
44+
if ctx.Verbose {
45+
ctx.WriteStdout(gccStdout)
46+
ctx.WriteStderr(gccStderr)
47+
}
4548
if err != nil {
4649
if !ctx.OnlyUpdateCompilationDatabase {
4750
return errors.WithStack(err)

Diff for: legacy/builder/container_find_includes.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import (
9898
"os/exec"
9999
"time"
100100

101+
"github.com/arduino/arduino-cli/arduino/builder/preprocessor"
101102
"github.com/arduino/arduino-cli/arduino/globals"
102103
"github.com/arduino/arduino-cli/arduino/libraries"
103104
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
@@ -369,7 +370,12 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
369370
ctx.Info(tr("Using cached library dependencies for file: %[1]s", sourcePath))
370371
}
371372
} else {
372-
preproc_stderr, preproc_err = GCCPreprocRunner(ctx, sourcePath, targetFilePath, includes)
373+
var preproc_stdout []byte
374+
preproc_stdout, preproc_stderr, preproc_err = preprocessor.GCC(sourcePath, targetFilePath, includes, ctx.BuildProperties)
375+
if ctx.Verbose {
376+
ctx.WriteStdout(preproc_stdout)
377+
ctx.WriteStdout(preproc_stderr)
378+
}
373379
// Unwrap error and see if it is an ExitError.
374380
_, is_exit_error := errors.Cause(preproc_err).(*exec.ExitError)
375381
if preproc_err == nil {
@@ -397,11 +403,13 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFileQu
397403
library := ResolveLibrary(ctx, include)
398404
if library == nil {
399405
// Library could not be resolved, show error
400-
// err := runCommand(ctx, &GCCPreprocRunner{SourceFilePath: sourcePath, TargetFileName: paths.New(constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E), Includes: includes})
401-
// return errors.WithStack(err)
402406
if preproc_err == nil || preproc_stderr == nil {
403407
// Filename came from cache, so run preprocessor to obtain error to show
404-
preproc_stderr, preproc_err = GCCPreprocRunner(ctx, sourcePath, targetFilePath, includes)
408+
var preproc_stdout []byte
409+
preproc_stdout, preproc_stderr, preproc_err = preprocessor.GCC(sourcePath, targetFilePath, includes, ctx.BuildProperties)
410+
if ctx.Verbose {
411+
ctx.WriteStdout(preproc_stdout)
412+
}
405413
if preproc_err == nil {
406414
// If there is a missing #include in the cache, but running
407415
// gcc does not reproduce that, there is something wrong.

Diff for: legacy/builder/ctags/ctags_has_issues.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,20 @@ import (
1919
"bufio"
2020
"os"
2121
"strings"
22+
23+
"golang.org/x/exp/slices"
2224
)
2325

24-
func (p *CTagsParser) FixCLinkageTagsDeclarations() {
26+
func (p *CTagsParser) fixCLinkageTagsDeclarations() {
2527
linesMap := p.FindCLinkageLines(p.tags)
2628
for i := range p.tags {
27-
if sliceContainsInt(linesMap[p.tags[i].Filename], p.tags[i].Line) &&
29+
if slices.Contains(linesMap[p.tags[i].Filename], p.tags[i].Line) &&
2830
!strings.Contains(p.tags[i].PrototypeModifiers, EXTERN) {
2931
p.tags[i].PrototypeModifiers = p.tags[i].PrototypeModifiers + " " + EXTERN
3032
}
3133
}
3234
}
3335

34-
func sliceContainsInt(s []int, e int) bool {
35-
for _, a := range s {
36-
if a == e {
37-
return true
38-
}
39-
}
40-
return false
41-
}
42-
4336
func (p *CTagsParser) prototypeAndCodeDontMatch(tag *CTag) bool {
4437
if tag.SkipMe {
4538
return true

Diff for: legacy/builder/ctags/ctags_parser.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ type CTag struct {
5858
PrototypeModifiers string
5959
}
6060

61-
func (p *CTagsParser) Parse(ctagsOutput []byte, mainFile *paths.Path) []*CTag {
61+
func (p *CTagsParser) Parse(ctagsOutput []byte, mainFile *paths.Path) ([]*Prototype, int) {
6262
rows := strings.Split(string(ctagsOutput), "\n")
6363
rows = removeEmpty(rows)
6464

@@ -74,8 +74,9 @@ func (p *CTagsParser) Parse(ctagsOutput []byte, mainFile *paths.Path) []*CTag {
7474
p.removeDefinedProtypes()
7575
p.skipDuplicates()
7676
p.skipTagsWhere(p.prototypeAndCodeDontMatch)
77+
p.fixCLinkageTagsDeclarations()
7778

78-
return p.tags
79+
return p.toPrototypes(), p.findLineWhereToInsertPrototypes()
7980
}
8081

8182
func (p *CTagsParser) addPrototypes() {

Diff for: legacy/builder/ctags/ctags_parser_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"path/filepath"
2121
"testing"
2222

23+
"github.com/arduino/go-paths-helper"
2324
"github.com/stretchr/testify/require"
2425
)
2526

@@ -28,7 +29,8 @@ func produceTags(t *testing.T, filename string) []*CTag {
2829
require.NoError(t, err)
2930

3031
parser := CTagsParser{}
31-
return parser.Parse(bytes, nil)
32+
parser.Parse(bytes, paths.New("sketch.ino"))
33+
return parser.tags
3234
}
3335

3436
func TestCTagsParserShouldListPrototypes(t *testing.T) {

Diff for: legacy/builder/ctags/ctags_to_prototypes.go

-4
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ func (proto *Prototype) String() string {
3232
return proto.Modifiers + " " + proto.Prototype + " @ " + strconv.Itoa(proto.Line)
3333
}
3434

35-
func (p *CTagsParser) GeneratePrototypes() ([]*Prototype, int) {
36-
return p.toPrototypes(), p.findLineWhereToInsertPrototypes()
37-
}
38-
3935
func (p *CTagsParser) findLineWhereToInsertPrototypes() int {
4036
firstFunctionLine := p.firstFunctionAtLine()
4137
firstFunctionPointerAsArgument := p.firstFunctionPointerUsedAsArgument()

Diff for: legacy/builder/ctags/ctags_to_prototypes_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ func producePrototypes(t *testing.T, filename string, mainFile string) ([]*Proto
2929
require.NoError(t, err)
3030

3131
parser := &CTagsParser{}
32-
parser.Parse(bytes, paths.New(mainFile))
33-
return parser.GeneratePrototypes()
32+
return parser.Parse(bytes, paths.New(mainFile))
3433
}
3534

3635
func TestCTagsToPrototypesShouldListPrototypes(t *testing.T) {

Diff for: legacy/builder/gcc_preproc_runner.go

-72
This file was deleted.

Diff for: legacy/builder/preprocess_sketch.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"runtime"
2424

2525
bldr "github.com/arduino/arduino-cli/arduino/builder"
26+
"github.com/arduino/arduino-cli/arduino/builder/preprocessor"
2627
"github.com/arduino/arduino-cli/legacy/builder/types"
2728
"github.com/arduino/arduino-cli/legacy/builder/utils"
2829
properties "github.com/arduino/go-properties-orderedmap"
@@ -36,11 +37,15 @@ func PreprocessSketchWithArduinoPreprocessor(ctx *types.Context) error {
3637

3738
sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Base() + ".cpp")
3839
targetFile := ctx.PreprocPath.Join("sketch_merged.cpp")
39-
stderr, err := GCCPreprocRunner(ctx, sourceFile, targetFile, ctx.IncludeFolders)
40-
ctx.WriteStderr(stderr)
40+
gccStdout, gccStderr, err := preprocessor.GCC(sourceFile, targetFile, ctx.IncludeFolders, ctx.BuildProperties)
41+
if ctx.Verbose {
42+
ctx.WriteStdout(gccStdout)
43+
ctx.WriteStderr(gccStderr)
44+
}
4145
if err != nil {
4246
return err
4347
}
48+
4449
buildProperties := properties.NewMap()
4550
buildProperties.Set("tools.arduino-preprocessor.path", "{runtime.tools.arduino-preprocessor.path}")
4651
buildProperties.Set("tools.arduino-preprocessor.cmd.path", "{path}/arduino-preprocessor")

Diff for: legacy/builder/prototypes_adder.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ var DebugPreprocessor bool
3030

3131
func PrototypesAdder(sketch *sketch.Sketch, source string, ctagsStdout []byte, lineOffset int) string {
3232
parser := &ctags.CTagsParser{}
33-
parser.Parse(ctagsStdout, sketch.MainFile)
34-
parser.FixCLinkageTagsDeclarations()
35-
36-
prototypes, firstFunctionLine := parser.GeneratePrototypes()
33+
prototypes, firstFunctionLine := parser.Parse(ctagsStdout, sketch.MainFile)
3734
if firstFunctionLine == -1 {
3835
firstFunctionLine = 0
3936
}

0 commit comments

Comments
 (0)