Skip to content

Commit 3f5c0eb

Browse files
[skip-changelog] legacy: refactor (part 4) (#2310)
* move CoreBuilder in arduino/builder and move CompilationDatabase in compilation pkg * rename CompilationDatabse in Database * move libraries phases in arduino/builder * move linker phases in arduino/builder * move sketch_builder phases in arduino/builder * move sizer phases in arduino/builder/sizer * create bulder logger * use builder logger in the sketLibrariesDetector * replace context Info logger with BuilderLogger * replace context Warn logger with BuilderLogger * replace context WriteStdout logger with BuilderLogger * replace context WriteStderr logger with BuilderLogger * directly pass the BuilderLogger to RecipeByPrefixSuffixRunner func * directly pass the BuilderLogger to part2 * directly pass the BuilderLogger to Linker func * directly pass the BuilderLogger to sizer.Size func * remove Stdout, Stderr and stdlock from Context * appease golint * add missinig license headers * remove WarningsLevel from context * remove Verbose from context
1 parent cf5db1b commit 3f5c0eb

27 files changed

+699
-749
lines changed

Diff for: arduino/builder/compilation_database.go renamed to arduino/builder/compilation/database.go

+19-16
Original file line numberDiff line numberDiff line change
@@ -13,52 +13,55 @@
1313
// Arduino software without disclosing the source code of your own applications.
1414
// To purchase a commercial license, send an email to [email protected].
1515

16-
package builder
16+
package compilation
1717

1818
import (
1919
"encoding/json"
2020
"fmt"
2121
"os"
2222

2323
"github.com/arduino/arduino-cli/executils"
24+
"github.com/arduino/arduino-cli/i18n"
2425
"github.com/arduino/go-paths-helper"
2526
)
2627

27-
// CompilationDatabase keeps track of all the compile commands run by the builder
28-
type CompilationDatabase struct {
29-
Contents []CompilationCommand
28+
var tr = i18n.Tr
29+
30+
// Database keeps track of all the compile commands run by the builder
31+
type Database struct {
32+
Contents []Command
3033
File *paths.Path
3134
}
3235

33-
// CompilationCommand keeps track of a single run of a compile command
34-
type CompilationCommand struct {
36+
// Command keeps track of a single run of a compile command
37+
type Command struct {
3538
Directory string `json:"directory"`
3639
Command string `json:"command,omitempty"`
3740
Arguments []string `json:"arguments,omitempty"`
3841
File string `json:"file"`
3942
}
4043

41-
// NewCompilationDatabase creates an empty CompilationDatabase
42-
func NewCompilationDatabase(filename *paths.Path) *CompilationDatabase {
43-
return &CompilationDatabase{
44+
// NewDatabase creates an empty CompilationDatabase
45+
func NewDatabase(filename *paths.Path) *Database {
46+
return &Database{
4447
File: filename,
45-
Contents: []CompilationCommand{},
48+
Contents: []Command{},
4649
}
4750
}
4851

49-
// LoadCompilationDatabase reads a compilation database from a file
50-
func LoadCompilationDatabase(file *paths.Path) (*CompilationDatabase, error) {
52+
// LoadDatabase reads a compilation database from a file
53+
func LoadDatabase(file *paths.Path) (*Database, error) {
5154
f, err := file.ReadFile()
5255
if err != nil {
5356
return nil, err
5457
}
55-
res := NewCompilationDatabase(file)
58+
res := NewDatabase(file)
5659
return res, json.Unmarshal(f, &res.Contents)
5760
}
5861

5962
// SaveToFile save the CompilationDatabase to file as a clangd-compatible compile_commands.json,
6063
// see https://clang.llvm.org/docs/JSONCompilationDatabase.html
61-
func (db *CompilationDatabase) SaveToFile() {
64+
func (db *Database) SaveToFile() {
6265
if jsonContents, err := json.MarshalIndent(db.Contents, "", " "); err != nil {
6366
fmt.Println(tr("Error serializing compilation database: %s", err))
6467
return
@@ -68,7 +71,7 @@ func (db *CompilationDatabase) SaveToFile() {
6871
}
6972

7073
// Add adds a new CompilationDatabase entry
71-
func (db *CompilationDatabase) Add(target *paths.Path, command *executils.Process) {
74+
func (db *Database) Add(target *paths.Path, command *executils.Process) {
7275
commandDir := command.GetDir()
7376
if commandDir == "" {
7477
// This mimics what Cmd.Run also does: Use Dir if specified,
@@ -80,7 +83,7 @@ func (db *CompilationDatabase) Add(target *paths.Path, command *executils.Proces
8083
commandDir = dir
8184
}
8285

83-
entry := CompilationCommand{
86+
entry := Command{
8487
Directory: commandDir,
8588
Arguments: command.GetArgs(),
8689
File: target.String(),

Diff for: arduino/builder/compilation_database_test.go renamed to arduino/builder/compilation/database_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// Arduino software without disclosing the source code of your own applications.
1414
// To purchase a commercial license, send an email to [email protected].
1515

16-
package builder
16+
package compilation
1717

1818
import (
1919
"testing"
@@ -30,11 +30,11 @@ func TestCompilationDatabase(t *testing.T) {
3030

3131
cmd, err := executils.NewProcess(nil, "gcc", "arg1", "arg2")
3232
require.NoError(t, err)
33-
db := NewCompilationDatabase(tmpfile)
33+
db := NewDatabase(tmpfile)
3434
db.Add(paths.New("test"), cmd)
3535
db.SaveToFile()
3636

37-
db2, err := LoadCompilationDatabase(tmpfile)
37+
db2, err := LoadDatabase(tmpfile)
3838
require.NoError(t, err)
3939
require.Equal(t, db, db2)
4040
require.Len(t, db2.Contents, 1)

Diff for: arduino/builder/core.go

+215-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,222 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 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+
116
package builder
217

3-
import "github.com/arduino/go-paths-helper"
18+
import (
19+
"crypto/md5"
20+
"encoding/hex"
21+
"fmt"
22+
"os"
23+
"strings"
24+
25+
"github.com/arduino/arduino-cli/arduino/builder/compilation"
26+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
27+
"github.com/arduino/arduino-cli/arduino/builder/logger"
28+
"github.com/arduino/arduino-cli/arduino/builder/progress"
29+
"github.com/arduino/arduino-cli/arduino/builder/utils"
30+
"github.com/arduino/arduino-cli/arduino/cores"
31+
"github.com/arduino/arduino-cli/buildcache"
32+
f "github.com/arduino/arduino-cli/internal/algorithms"
33+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
34+
"github.com/arduino/go-paths-helper"
35+
"github.com/arduino/go-properties-orderedmap"
36+
"github.com/pkg/errors"
37+
)
438

539
// CoreBuildCachePath fixdoc
640
func (b *Builder) CoreBuildCachePath() *paths.Path {
741
return b.coreBuildCachePath
842
}
43+
44+
// CoreBuilder fixdoc
45+
func CoreBuilder(
46+
buildPath, coreBuildPath, coreBuildCachePath *paths.Path,
47+
buildProperties *properties.Map,
48+
actualPlatform *cores.PlatformRelease,
49+
onlyUpdateCompilationDatabase, clean bool,
50+
compilationDatabase *compilation.Database,
51+
jobs int,
52+
builderLogger *logger.BuilderLogger,
53+
progress *progress.Struct, progressCB rpc.TaskProgressCB,
54+
) (paths.PathList, *paths.Path, error) {
55+
if err := coreBuildPath.MkdirAll(); err != nil {
56+
return nil, nil, errors.WithStack(err)
57+
}
58+
59+
if coreBuildCachePath != nil {
60+
if _, err := coreBuildCachePath.RelTo(buildPath); err != nil {
61+
builderLogger.Info(tr("Couldn't deeply cache core build: %[1]s", err))
62+
builderLogger.Info(tr("Running normal build of the core..."))
63+
coreBuildCachePath = nil
64+
} else if err := coreBuildCachePath.MkdirAll(); err != nil {
65+
return nil, nil, errors.WithStack(err)
66+
}
67+
}
68+
69+
archiveFile, objectFiles, err := compileCore(
70+
onlyUpdateCompilationDatabase, clean,
71+
actualPlatform,
72+
coreBuildPath, coreBuildCachePath,
73+
buildProperties,
74+
compilationDatabase,
75+
jobs,
76+
builderLogger,
77+
progress, progressCB,
78+
)
79+
if err != nil {
80+
return nil, nil, errors.WithStack(err)
81+
}
82+
83+
return objectFiles, archiveFile, nil
84+
}
85+
86+
func compileCore(
87+
onlyUpdateCompilationDatabase, clean bool,
88+
actualPlatform *cores.PlatformRelease,
89+
buildPath, buildCachePath *paths.Path,
90+
buildProperties *properties.Map,
91+
compilationDatabase *compilation.Database,
92+
jobs int,
93+
builderLogger *logger.BuilderLogger,
94+
progress *progress.Struct, progressCB rpc.TaskProgressCB,
95+
) (*paths.Path, paths.PathList, error) {
96+
coreFolder := buildProperties.GetPath("build.core.path")
97+
variantFolder := buildProperties.GetPath("build.variant.path")
98+
targetCoreFolder := buildProperties.GetPath("runtime.platform.path")
99+
100+
includes := []string{coreFolder.String()}
101+
if variantFolder != nil && variantFolder.IsDir() {
102+
includes = append(includes, variantFolder.String())
103+
}
104+
includes = f.Map(includes, cpp.WrapWithHyphenI)
105+
106+
var err error
107+
variantObjectFiles := paths.NewPathList()
108+
if variantFolder != nil && variantFolder.IsDir() {
109+
variantObjectFiles, err = utils.CompileFilesRecursive(
110+
variantFolder, buildPath, buildProperties, includes,
111+
onlyUpdateCompilationDatabase,
112+
compilationDatabase,
113+
jobs,
114+
builderLogger,
115+
progress, progressCB,
116+
)
117+
if err != nil {
118+
return nil, nil, errors.WithStack(err)
119+
}
120+
}
121+
122+
var targetArchivedCore *paths.Path
123+
if buildCachePath != nil {
124+
realCoreFolder := coreFolder.Parent().Parent()
125+
archivedCoreName := GetCachedCoreArchiveDirName(
126+
buildProperties.Get("build.fqbn"),
127+
buildProperties.Get("compiler.optimization_flags"),
128+
realCoreFolder,
129+
)
130+
targetArchivedCore = buildCachePath.Join(archivedCoreName, "core.a")
131+
132+
if _, err := buildcache.New(buildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) {
133+
return nil, nil, fmt.Errorf(tr("creating core cache folder: %s", err))
134+
}
135+
136+
var canUseArchivedCore bool
137+
if onlyUpdateCompilationDatabase || clean {
138+
canUseArchivedCore = false
139+
} else if isOlder, err := utils.DirContentIsOlderThan(realCoreFolder, targetArchivedCore); err != nil || !isOlder {
140+
// Recreate the archive if ANY of the core files (including platform.txt) has changed
141+
canUseArchivedCore = false
142+
} else if targetCoreFolder == nil || realCoreFolder.EquivalentTo(targetCoreFolder) {
143+
canUseArchivedCore = true
144+
} else if isOlder, err := utils.DirContentIsOlderThan(targetCoreFolder, targetArchivedCore); err != nil || !isOlder {
145+
// Recreate the archive if ANY of the build core files (including platform.txt) has changed
146+
canUseArchivedCore = false
147+
} else {
148+
canUseArchivedCore = true
149+
}
150+
151+
if canUseArchivedCore {
152+
// use archived core
153+
if builderLogger.Verbose() {
154+
builderLogger.Info(tr("Using precompiled core: %[1]s", targetArchivedCore))
155+
}
156+
return targetArchivedCore, variantObjectFiles, nil
157+
}
158+
}
159+
160+
coreObjectFiles, err := utils.CompileFilesRecursive(
161+
coreFolder, buildPath, buildProperties, includes,
162+
onlyUpdateCompilationDatabase,
163+
compilationDatabase,
164+
jobs,
165+
builderLogger,
166+
progress, progressCB,
167+
)
168+
if err != nil {
169+
return nil, nil, errors.WithStack(err)
170+
}
171+
172+
archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles(
173+
buildPath, paths.New("core.a"), coreObjectFiles, buildProperties,
174+
onlyUpdateCompilationDatabase, builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(),
175+
)
176+
if builderLogger.Verbose() {
177+
builderLogger.Info(string(verboseInfo))
178+
}
179+
if err != nil {
180+
return nil, nil, errors.WithStack(err)
181+
}
182+
183+
// archive core.a
184+
if targetArchivedCore != nil && !onlyUpdateCompilationDatabase {
185+
err := archiveFile.CopyTo(targetArchivedCore)
186+
if builderLogger.Verbose() {
187+
if err == nil {
188+
builderLogger.Info(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore))
189+
} else if os.IsNotExist(err) {
190+
builderLogger.Info(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s",
191+
actualPlatform,
192+
"https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-build-the-corea-archive-file"))
193+
} else {
194+
builderLogger.Info(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err))
195+
}
196+
}
197+
}
198+
199+
return archiveFile, variantObjectFiles, nil
200+
}
201+
202+
// GetCachedCoreArchiveDirName returns the directory name to be used to store
203+
// the global cached core.a.
204+
func GetCachedCoreArchiveDirName(fqbn string, optimizationFlags string, coreFolder *paths.Path) string {
205+
fqbnToUnderscore := strings.ReplaceAll(fqbn, ":", "_")
206+
fqbnToUnderscore = strings.ReplaceAll(fqbnToUnderscore, "=", "_")
207+
if absCoreFolder, err := coreFolder.Abs(); err == nil {
208+
coreFolder = absCoreFolder
209+
} // silently continue if absolute path can't be detected
210+
211+
md5Sum := func(data []byte) string {
212+
md5sumBytes := md5.Sum(data)
213+
return hex.EncodeToString(md5sumBytes[:])
214+
}
215+
hash := md5Sum([]byte(coreFolder.String() + optimizationFlags))
216+
realName := fqbnToUnderscore + "_" + hash
217+
if len(realName) > 100 {
218+
// avoid really long names, simply hash the name again
219+
realName = md5Sum([]byte(realName))
220+
}
221+
return realName
222+
}

0 commit comments

Comments
 (0)