Skip to content

Commit 2ef0ef9

Browse files
authored
Parallel compiling: arduino-builder will leverage your multi core pc
If -jobs X param is specified and X is greater than 0, arduino-builder won't spawn more than X processes. Fixes arduino#17 Rebased from Federico Fissore branch arduino@0a3d888#diff-8f074e2b3fc911dbe8255891fc1a9b13R96 Remove and if which suppress some GCC error messages here: arduino@0a3d888#diff-8f074e2b3fc911dbe8255891fc1a9b13R96
1 parent 7883e01 commit 2ef0ef9

File tree

3 files changed

+122
-24
lines changed

3 files changed

+122
-24
lines changed

Diff for: src/arduino.cc/builder/builder_utils/utils.go

+56-11
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,17 @@ package builder_utils
3131

3232
import (
3333
"bytes"
34-
"fmt"
3534
"io"
3635
"os"
3736
"os/exec"
3837
"path/filepath"
3938
"strings"
39+
"sync"
4040

4141
"arduino.cc/builder/constants"
4242
"arduino.cc/builder/i18n"
4343
"arduino.cc/builder/utils"
44+
"arduino.cc/builder/types"
4445
"arduino.cc/properties"
4546
)
4647

@@ -146,16 +147,49 @@ func findAllFilesInFolder(sourcePath string, recurse bool) ([]string, error) {
146147
}
147148

148149
func compileFilesWithRecipe(objectFiles []string, sourcePath string, sources []string, buildPath string, buildProperties properties.Map, includes []string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) {
150+
if len(sources) == 0 {
151+
return objectFiles, nil
152+
}
153+
objectFilesChan := make(chan string)
154+
errorsChan := make(chan error)
155+
doneChan := make(chan struct{})
156+
157+
var wg sync.WaitGroup
158+
wg.Add(len(sources))
159+
149160
for _, source := range sources {
150-
objectFile, err := compileFileWithRecipe(sourcePath, source, buildPath, buildProperties, includes, recipe, verbose, warningsLevel, logger)
151-
if err != nil {
152-
return nil, i18n.WrapError(err)
153-
}
161+
go func(source string) {
162+
defer wg.Done()
163+
objectFile, err := compileFileWithRecipe(sourcePath, source, buildPath, buildProperties, includes, recipe, verbose, warningsLevel, logger)
164+
if err != nil {
165+
errorsChan <- err
166+
} else {
167+
objectFilesChan <- objectFile
168+
}
169+
}(source)
170+
}
171+
172+
go func() {
173+
wg.Wait()
174+
doneChan <- struct{}{}
175+
}()
154176

155-
objectFiles = append(objectFiles, objectFile)
177+
for {
178+
select {
179+
case objectFile := <-objectFilesChan:
180+
objectFiles = append(objectFiles, objectFile)
181+
case err := <-errorsChan:
182+
return nil, i18n.WrapError(err)
183+
case <-doneChan:
184+
close(objectFilesChan)
185+
for objectFile := range objectFilesChan {
186+
objectFiles = append(objectFiles, objectFile)
187+
}
188+
return objectFiles, nil
189+
}
156190
}
157-
return objectFiles, nil
158191
}
192+
159193

160194
func compileFileWithRecipe(sourcePath string, source string, buildPath string, buildProperties properties.Map, includes []string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) (string, error) {
161195
properties := buildProperties.Clone()
@@ -361,11 +395,22 @@ func ExecRecipe(properties properties.Map, recipe string, removeUnsetProperties
361395
}
362396

363397
if echoOutput {
364-
command.Stdout = os.Stdout
398+
printToStdOut := func(data []byte) {
399+
logger.UnformattedWrite(os.Stdout, data)
400+
}
401+
stdout := &types.BufferedUntilNewLineWriter{PrintFunc: printToStdOut, Buffer: bytes.Buffer{}}
402+
defer stdout.Flush()
403+
command.Stdout = stdout
365404
}
366405

367-
command.Stderr = os.Stderr
368-
406+
printToStdErr := func(data []byte) {
407+
logger.UnformattedWrite(os.Stderr, data)
408+
}
409+
stderr := &types.BufferedUntilNewLineWriter{PrintFunc: printToStdErr, Buffer: bytes.Buffer{}}
410+
defer stderr.Flush()
411+
command.Stderr = stderr
412+
413+
369414
if echoOutput {
370415
err := command.Run()
371416
return nil, i18n.WrapError(err)
@@ -396,7 +441,7 @@ func PrepareCommandForRecipe(buildProperties properties.Map, recipe string, remo
396441
}
397442

398443
if echoCommandLine {
399-
fmt.Println(commandLine)
444+
logger.UnformattedFprintln(os.Stdout, commandLine)
400445
}
401446

402447
return command, nil

Diff for: src/arduino.cc/builder/ctags_runner.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
package builder
3131

3232
import (
33-
"fmt"
33+
"os"
3434

3535
"arduino.cc/builder/constants"
3636
"arduino.cc/builder/ctags"
@@ -63,7 +63,7 @@ func (s *CTagsRunner) Run(ctx *types.Context) error {
6363

6464
verbose := ctx.Verbose
6565
if verbose {
66-
fmt.Println(commandLine)
66+
logger.UnformattedFprintln(os.Stdout, commandLine)
6767
}
6868

6969
sourceBytes, err := command.Output()

Diff for: src/arduino.cc/builder/i18n/i18n.go

+64-11
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ import (
3838
"regexp"
3939
"strconv"
4040
"strings"
41+
"sync"
4142
)
4243

4344
var PLACEHOLDER = regexp.MustCompile("{(\\d)}")
4445

4546
type Logger interface {
4647
Fprintln(w io.Writer, level string, format string, a ...interface{})
48+
UnformattedFprintln(w io.Writer, s string)
49+
UnformattedWrite(w io.Writer, data []byte)
4750
Println(level string, format string, a ...interface{})
4851
Name() string
4952
}
@@ -52,6 +55,10 @@ type NoopLogger struct{}
5255

5356
func (s NoopLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {}
5457

58+
func (s NoopLogger) UnformattedFprintln(w io.Writer, str string) {}
59+
60+
func (s NoopLogger) UnformattedWrite(w io.Writer, data []byte) {}
61+
5562
func (s NoopLogger) Println(level string, format string, a ...interface{}) {}
5663

5764
func (s NoopLogger) Name() string {
@@ -62,55 +69,101 @@ type HumanTagsLogger struct{}
6269

6370
func (s HumanTagsLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
6471
format = "[" + level + "] " + format
65-
fmt.Fprintln(w, Format(format, a...))
72+
fprintln(w, Format(format, a...))
6673
}
6774

6875
func (s HumanTagsLogger) Println(level string, format string, a ...interface{}) {
6976
s.Fprintln(os.Stdout, level, format, a...)
7077
}
7178

79+
func (s HumanTagsLogger) UnformattedFprintln(w io.Writer, str string) {
80+
fprintln(w, str)
81+
}
82+
83+
func (s HumanTagsLogger) UnformattedWrite(w io.Writer, data []byte) {
84+
write(w, data)
85+
}
86+
7287
func (s HumanTagsLogger) Name() string {
7388
return "humantags"
7489
}
7590

91+
7692
type HumanLogger struct{}
7793

7894
func (s HumanLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
79-
fmt.Fprintln(w, Format(format, a...))
95+
fprintln(w, Format(format, a...))
8096
}
8197

8298
func (s HumanLogger) Println(level string, format string, a ...interface{}) {
8399
s.Fprintln(os.Stdout, level, format, a...)
84100
}
85101

102+
func (s HumanLogger) UnformattedFprintln(w io.Writer, str string) {
103+
fprintln(w, str)
104+
}
105+
106+
func (s HumanLogger) UnformattedWrite(w io.Writer, data []byte) {
107+
write(w, data)
108+
}
109+
86110
func (s HumanLogger) Name() string {
87111
return "human"
88112
}
89113

114+
90115
type MachineLogger struct{}
91116

92-
func (s MachineLogger) printWithoutFormatting(w io.Writer, level string, format string, a []interface{}) {
117+
func (s MachineLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
118+
printMachineFormattedLogLine(w, level, format, a)
119+
}
120+
121+
func (s MachineLogger) Println(level string, format string, a ...interface{}) {
122+
printMachineFormattedLogLine(os.Stdout, level, format, a)
123+
}
124+
125+
func (s MachineLogger) UnformattedFprintln(w io.Writer, str string) {
126+
fprintln(w, str)
127+
}
128+
129+
func (s MachineLogger) Name() string {
130+
return "machine"
131+
}
132+
133+
func (s MachineLogger) UnformattedWrite(w io.Writer, data []byte) {
134+
write(w, data)
135+
}
136+
137+
138+
func printMachineFormattedLogLine(w io.Writer, level string, format string, a []interface{}) {
93139
a = append([]interface{}(nil), a...)
94140
for idx, value := range a {
95141
typeof := reflect.Indirect(reflect.ValueOf(value)).Kind()
96142
if typeof == reflect.String {
97143
a[idx] = url.QueryEscape(value.(string))
98144
}
99145
}
100-
fmt.Fprintf(w, "===%s ||| %s ||| %s", level, format, a)
101-
fmt.Fprintln(w)
146+
fprintf(w, "===%s ||| %s ||| %s\n", level, format, a)
102147
}
103148

104-
func (s MachineLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
105-
s.printWithoutFormatting(w, level, format, a)
149+
var lock sync.Mutex
150+
151+
func fprintln(w io.Writer, s string) {
152+
lock.Lock()
153+
defer lock.Unlock()
154+
fmt.Fprintln(w, s)
106155
}
107156

108-
func (s MachineLogger) Println(level string, format string, a ...interface{}) {
109-
s.printWithoutFormatting(os.Stdout, level, format, a)
157+
func write(w io.Writer, data []byte) {
158+
lock.Lock()
159+
defer lock.Unlock()
160+
w.Write(data)
110161
}
111162

112-
func (s MachineLogger) Name() string {
113-
return "machine"
163+
func fprintf(w io.Writer, format string, a ...interface{}) {
164+
lock.Lock()
165+
defer lock.Unlock()
166+
fmt.Fprintf(w, format, a...)
114167
}
115168

116169
func FromJavaToGoSyntax(s string) string {

0 commit comments

Comments
 (0)