Skip to content

Commit 432aa1f

Browse files
committed
WIP continue from lib folder generation
1 parent 3906685 commit 432aa1f

File tree

1 file changed

+111
-10
lines changed

1 file changed

+111
-10
lines changed

cmd/compile.go

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ Copyright © 2021 NAME HERE <EMAIL ADDRESS>
55
package cmd
66

77
import (
8+
"bytes"
89
"encoding/json"
10+
"io/ioutil"
911
"os"
1012
"os/exec"
13+
"strings"
1114

1215
"github.com/arduino/go-paths-helper"
1316
"github.com/sirupsen/logrus"
@@ -77,24 +80,122 @@ func compileSketch(cmd *cobra.Command, args []string) {
7780
json.Unmarshal(cmdOutput, &unmarshalledOutput)
7881
logrus.Infof("arduino-cli version: %s", unmarshalledOutput["VersionString"])
7982

80-
// let's call arduino-cli compile and parse the verbose output
81-
logrus.Infof("running: arduino-cli compile -b %s %s -v --format json", fqbn, args[0])
82-
cmdOutput, err = exec.Command("arduino-cli", "compile", "-b", fqbn, args[0], "-v", "--format", "json").Output()
83+
// let's check if ar is installed on the users machine
84+
cmdOutput, err = exec.Command("ar", "--version").Output()
8385
if err != nil {
86+
logrus.Warn("Before running this tool be sure to have \"GNU ar\" installed in your $PATH")
8487
logrus.Fatal(err)
8588
}
86-
objFilesPaths, returnJson := parseOutput(cmdOutput)
89+
logrus.Infof(strings.Split(string(cmdOutput), "\n")[0]) // print the version of ar
8790

88-
workingDir, err := paths.Getwd()
91+
// check if the path of the sketch passed as args[0] is valid
92+
sketchPath := paths.New(args[0])
93+
if !sketchPath.Exist() {
94+
logrus.Fatalf("the path %s do not exist!", sketchPath)
95+
}
96+
var inoPath *paths.Path
97+
if sketchPath.Ext() == ".ino" {
98+
inoPath = sketchPath
99+
} else { // if there are multiple .ino files in the sketchPath we need to know which is the one containing setup() and loop() functions
100+
files, _ := sketchPath.ReadDir()
101+
files.FilterSuffix(".ino")
102+
if len(files) == 0 {
103+
logrus.Fatal("the sketch path specified does not contain an .ino file")
104+
} else if len(files) > 1 {
105+
logrus.Fatalf("the sketch path specified contains multiple .ino files:\n %s \nIn order to make the magic please use the path of the .ino file containing the setup() and loop() functions", strings.Join(files.AsStrings(), "\n"))
106+
}
107+
inoPath = files[0]
108+
}
109+
logrus.Infof("the ino file path is %s", inoPath)
110+
111+
// create a main.cpp file in the same dir of the sketch.ino
112+
// the main.cpp contains the following:
113+
mainCpp := `
114+
#include "Arduino.h"
115+
void _setup();
116+
void _loop();
117+
118+
void setup() {
119+
_setup();
120+
}
121+
122+
void loop() {
123+
_loop();
124+
}`
125+
mainCppPath := inoPath.Parent().Join("main.cpp").String()
126+
err = os.WriteFile(mainCppPath, []byte(mainCpp), 0644)
89127
if err != nil {
90128
logrus.Fatal(err)
91129
}
92-
buildDir := workingDir.Join("build")
93-
if !buildDir.Exist() {
94-
if err = buildDir.Mkdir(); err != nil {
130+
logrus.Infof("created %s", mainCppPath)
131+
132+
// replace setup() with _setup() and loop() with _loop() in the user's sketch.ino file
133+
// TODO make a backup copy of the sketch and restore it at the end (we have it in input var)
134+
input, err := ioutil.ReadFile(inoPath.String())
135+
if err != nil {
136+
logrus.Fatal(err)
137+
}
138+
// TODO this check has meaning??
139+
if bytes.Contains(input, []byte("_setup()")) {
140+
logrus.Warnf("already replaced setup() function in %s, skipping", inoPath)
141+
}
142+
// TODO this check has meaning??
143+
if bytes.Contains(input, []byte("_loop()")) {
144+
logrus.Warnf("already replaced loop() function in %s, skipping", inoPath)
145+
} else {
146+
output := bytes.Replace(input, []byte("void setup()"), []byte("void _setup()"), -1)
147+
output = bytes.Replace(output, []byte("void loop()"), []byte("void _loop()"), -1)
148+
if err = ioutil.WriteFile(inoPath.String(), output, 0644); err != nil {
95149
logrus.Fatal(err)
96150
}
151+
logrus.Infof("replaced setup() and loop() functions in %s", inoPath)
152+
}
153+
154+
// let's call arduino-cli compile and parse the verbose output
155+
cmdArgs := []string{"compile", "-b", fqbn, inoPath.String(), "-v", "--format", "json"}
156+
logrus.Infof("running: arduino-cli %s", cmdArgs)
157+
cmdOutput, err = exec.Command("arduino-cli", cmdArgs...).Output()
158+
if err != nil {
159+
logrus.Fatal(err)
160+
}
161+
objFilesPaths, returnJson := parseCliCompileOutput(cmdOutput)
162+
163+
// TODO remove the main.cpp file and restore the sketch ino file
164+
165+
// we are going to leverage the precompiled library infrastructure to make the linking work.
166+
// this type of lib, as the type suggest, is already compiled so it only gets linked during the linking phase of a sketch
167+
// but we have to create a library folder structure in the current directory
168+
// libsketch
169+
// ├── examples
170+
// │ └── sketch
171+
// │ └── sketch.ino
172+
// ├── library.properties
173+
// └── src
174+
// ├── cortex-m0plus
175+
// │ └── libsketch.a
176+
// └── libsketch.h
177+
libName := strings.ToLower(inoPath.Base())
178+
workingDir, err := paths.Getwd()
179+
if err != nil {
180+
logrus.Fatal(err)
181+
}
182+
libDir := workingDir.Join("lib" + libName)
183+
if libDir.Exist() { // if the dir already exixst we clean it before
184+
os.RemoveAll(libDir.String())
185+
logrus.Warn("removed %s", libDir)
97186
}
187+
if err = libDir.Mkdir(); err != nil {
188+
logrus.Fatal(err)
189+
}
190+
191+
// run ar to create an archive containing all the object files except the main.cpp.o (we'll create it later)
192+
// we exclude the main.cpp.o because we are going to link the archive libsjetch.a against another main.cpp
193+
objFilesPaths.FilterOutPrefix("main.cpp")
194+
// TODO use the correct name for the archive
195+
cmdArgs = append([]string{"rcs", buildDir.Join("libsketch.a").String()}, objFilesPaths.AsStrings()...)
196+
logrus.Infof("running: ar %s", cmdArgs)
197+
cmdOutput, _ = exec.Command("ar", cmdArgs...).Output()
198+
logrus.Print(cmdOutput)
98199

99200
// Copy the object files from the `<tempdir>/arduino-sketch_stuff/sketch` folder
100201
for _, objFilePath := range objFilesPaths {
@@ -117,11 +218,11 @@ func compileSketch(cmd *cobra.Command, args []string) {
117218
}
118219
}
119220

120-
// parseOutput function takes cmdOutToParse as argument,
221+
// parseCliCompileOutput function takes cmdOutToParse as argument,
121222
// cmdOutToParse is the json output captured from the command run
122223
// the function extracts and returns the paths of the .o files
123224
// (generated during the compile phase) and a ReturnJson object
124-
func parseOutput(cmdOutToParse []byte) ([]*paths.Path, *ResultJson) {
225+
func parseCliCompileOutput(cmdOutToParse []byte) (paths.PathList, *ResultJson) {
125226
var compileOutput CompileOutput
126227
err := json.Unmarshal(cmdOutToParse, &compileOutput)
127228
if err != nil {

0 commit comments

Comments
 (0)