Skip to content

Add first implementation of the tool #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cslt-tool
.vscode
build/
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# cslt-tool

cslt-tool is a convenient wrapper of [arduino-cli](https://github.com/arduino/arduino-cli), it compiles Arduino sketches outputting object files and a json file in a `build/` directory
The json contains information regarding libraries and core to use in order to build the sketch. The result is achieved by parsing the verbose output of `arduino-cli`.

## Requisites
In order to run this tool you have to install first the [arduino-cli](https://github.com/arduino/arduino-cli) and have `arduino-cli` binary in your path, otherwise `cslt-tool` won't work.
Please use a version of the cli that has [this](https://github.com/arduino/arduino-cli/pull/1608) change, version > 0.20.2

## Build it
In order to build it just use `go build`

## Usage
`./cslt-tool compile -b <fqbn> <sketch_path>`

This is an example execution:
``` bash
$ ./cslt-tool compile -b arduino:samd:mkrwan1310 /home/umberto/getdeveui
INFO[0001] arduino-cli version: git-snapshot
INFO[0001] running: arduino-cli compile -b arduino:samd:mkrwan1310 /home/umberto/getdeveui -v --format json
INFO[0002] copied file to /home/umberto/Nextcloud/8tb/Lavoro/cslt-tool/build/getdeveui.ino.cpp.o
INFO[0002] created new file in: /home/umberto/Nextcloud/8tb/Lavoro/cslt-tool/build/result.json
```
The structure of the `build` forder is the following:
```
build/
├── getdeveui.ino.cpp.o
└── result.json
```
And the content of `build/result.json` is:
```json
{
"coreInfo": {
"id": "arduino:samd",
"version": "1.8.12"
},
"libsInfo": [
{
"name": "MKRWAN",
"version": "1.1.0"
}
]
}
```
149 changes: 149 additions & 0 deletions cmd/compile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>

*/
package cmd

import (
"encoding/json"
"os"
"os/exec"

"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var fqbn string

// compileOutput represents the json returned by the arduino-cli compile command
type CompileOutput struct {
CompilerErr string `json:"compiler_err"`
BuilderResult *BuilderResult `json:"builder_result"`
Success bool `json:"success"`
}

type BuilderResult struct {
BuildPath string `json:"build_path"`
UsedLibraries []*UsedLibrary `json:"used_libraries"`
BuildPlatform *BuildPlatform `json:"build_platform"`
}

// UsedLibrary contains information regarding the library used during the compile process
type UsedLibrary struct {
Name string `json:"name"`
Version string `json:"version"`
}

// BuildPlatform contains information regarding the platform used during the compile process
type BuildPlatform struct {
Id string `json:"id"`
Version string `json:"version"`
}

// ResultJson contains information regarding the core and libraries used during the compile process
type ResultJson struct {
CoreInfo *BuildPlatform `json:"coreInfo"`
LibsInfo []*UsedLibrary `json:"libsInfo"`
}

// compileCmd represents the compile command
var compileCmd = &cobra.Command{
Use: "compile",
Short: "Compiles Arduino sketches.",
Long: `Compiles Arduino sketches outputting an object file and a json file in a build directory
The json contains information regarding libraries and core to use in order to build the sketch`,
Example: os.Args[0] + `compile -b arduino:avr:uno /home/umberto/Arduino/Blink`,
Args: cobra.ExactArgs(1), // the path of the sketch to build
Run: compileSketch,
}

func init() {
rootCmd.AddCommand(compileCmd)
compileCmd.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno")
compileCmd.MarkFlagRequired("fqbn")
}

func compileSketch(cmd *cobra.Command, args []string) {
logrus.Debug("compile called")

// let's check the arduino-cli version
cmdOutput, err := exec.Command("arduino-cli", "version", "--format", "json").Output()
if err != nil {
logrus.Warn("Before running this tool be sure to have arduino-cli installed in your $PATH")
logrus.Fatal(err)
}
var unmarshalledOutput map[string]interface{}
json.Unmarshal(cmdOutput, &unmarshalledOutput)
logrus.Infof("arduino-cli version: %s", unmarshalledOutput["VersionString"])

// let's call arduino-cli compile and parse the verbose output
logrus.Infof("running: arduino-cli compile -b %s %s -v --format json", fqbn, args[0])
cmdOutput, err = exec.Command("arduino-cli", "compile", "-b", fqbn, args[0], "-v", "--format", "json").Output()
if err != nil {
logrus.Fatal(err)
}
objFilesPaths, returnJson := parseOutput(cmdOutput)

workingDir, err := paths.Getwd()
if err != nil {
logrus.Fatal(err)
}
buildDir := workingDir.Join("build")
if !buildDir.Exist() {
if err = buildDir.Mkdir(); err != nil {
logrus.Fatal(err)
}
}

// Copy the object files from the `<tempdir>/arduino-sketch_stuff/sketch` folder
for _, objFilePath := range objFilesPaths {
destObjFilePath := buildDir.Join(objFilePath.Base())
if err = objFilePath.CopyTo(destObjFilePath); err != nil {
logrus.Errorf("error copying object file: %s", err)
} else {
logrus.Infof("copied file to %s", destObjFilePath)
}
}

// save the result.json in the build dir
jsonFilePath := buildDir.Join("result.json")
if jsonContents, err := json.MarshalIndent(returnJson, "", " "); err != nil {
logrus.Errorf("error serializing json: %s", err)
} else if err := jsonFilePath.WriteFile(jsonContents); err != nil {
logrus.Errorf("error writing result.json: %s", err)
} else {
logrus.Infof("created new file in: %s", jsonFilePath)
}
}

// parseOutput function takes cmdOutToParse as argument,
// cmdOutToParse is the json output captured from the command run
// the function extracts and returns the paths of the .o files
// (generated during the compile phase) and a ReturnJson object
func parseOutput(cmdOutToParse []byte) ([]*paths.Path, *ResultJson) {
var compileOutput CompileOutput
err := json.Unmarshal(cmdOutToParse, &compileOutput)
if err != nil {
logrus.Fatal(err)
} else if !compileOutput.Success {
logrus.Fatalf("sketch compile was not successful: %s", compileOutput.CompilerErr)
}

// this dir contains all the obj files we need (the sketch related ones and not the core or libs)
sketchDir := paths.New(compileOutput.BuilderResult.BuildPath).Join("sketch")
sketchFilesPaths, err := sketchDir.ReadDir()
if err != nil {
logrus.Fatal(err)
} else if len(sketchFilesPaths) == 0 {
logrus.Fatalf("empty directory: %s", sketchDir)
}
sketchFilesPaths.FilterSuffix(".o")

returnJson := ResultJson{
CoreInfo: compileOutput.BuilderResult.BuildPlatform,
LibsInfo: compileOutput.BuilderResult.UsedLibraries,
}

return sketchFilesPaths, &returnJson
}
26 changes: 26 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>

*/
package cmd

import (
"os"

"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cslt-tool",
Short: "cslt-tool is a command-line tool that uses the Arduino CLI to generate objectfiles and a json file with info regarding core and libraries used",
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module cslt-tool

go 1.17

require (
github.com/arduino/go-paths-helper v1.6.1
github.com/spf13/cobra v1.3.0
)

require (
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
)

require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/spf13/pflag v1.0.5 // indirect
)
Loading