Skip to content

Commit 846216e

Browse files
pillo79cmaglie
andauthored
linker: allow multi-step link recipe (c.combine) (#2954)
* builder: RunRecipe: run either a set of recipes or a single recipe Recipes must follow the 'prefix.NNN.suffix' pattern, where 'NNN' is a number. When there is also a single 'prefix.suffix' property defined, make sure to not include that in the list of recipes to run. However, if no numbered recipes are found, use the single 'prefix.suffix' form if it exists. This allows to have both a single recipe and a set of numbered recipes in the same build properties, for backwards compatibility. Signed-off-by: Luca Burelli <l.burelli@arduino.cc> * linker: switch 'recipe.c.combine.pattern' to a recipe Enable the use of recipes for the `recipe.c.combine.pattern` command. Allows for more flexibility in the build process. Signed-off-by: Luca Burelli <l.burelli@arduino.cc> * Removed useless cloning of buildProperties * Added unit test for recipe finder --------- Signed-off-by: Luca Burelli <l.burelli@arduino.cc> Co-authored-by: Cristian Maglie <c.maglie@arduino.cc>
1 parent ed93bf3 commit 846216e

File tree

5 files changed

+101
-13
lines changed

5 files changed

+101
-13
lines changed

docs/platform-specification.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ compiler.libraries.ldflags=
302302
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} "{archive_file_path}" "-L{build.path}" -lm
303303
```
304304

305+
If the linking process requires multiple steps, the recipe can be written using the **recipe.c.combine.NUMBER.pattern**
306+
syntax. In this case, each step will be executed in the order specified by the number. When multiple steps are defined,
307+
the **recipe.c.combine.pattern** property is ignored.
308+
305309
#### Recipes for extraction of executable files and other binary data
306310

307311
An arbitrary number of extra steps can be performed at the end of objects linking. These steps can be used to extract

internal/arduino/builder/builder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ func (b *Builder) build() error {
464464
}
465465
b.Progress.CompleteStep()
466466

467-
if err := b.RunRecipe("recipe.objcopy.", ".pattern", true); err != nil {
467+
if err := b.RunRecipe("recipe.objcopy", ".pattern", true); err != nil {
468468
return err
469469
}
470470
b.Progress.CompleteStep()

internal/arduino/builder/linker.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,5 @@ func (b *Builder) link() error {
9090
properties.Set("archive_file_path", b.buildArtifacts.coreArchiveFilePath.String())
9191
properties.Set("object_files", objectFileList)
9292

93-
command, err := b.prepareCommandForRecipe(properties, "recipe.c.combine.pattern", false)
94-
if err != nil {
95-
return err
96-
}
97-
98-
return b.execCommand(command)
93+
return b.RunRecipeWithProps("recipe.c.combine", ".pattern", properties, false)
9994
}

internal/arduino/builder/recipe.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,18 @@ import (
2727

2828
// RunRecipe fixdoc
2929
func (b *Builder) RunRecipe(prefix, suffix string, skipIfOnlyUpdatingCompilationDatabase bool) error {
30+
return b.RunRecipeWithProps(prefix, suffix, b.buildProperties, skipIfOnlyUpdatingCompilationDatabase)
31+
}
32+
33+
func (b *Builder) RunRecipeWithProps(prefix, suffix string, buildProperties *properties.Map, skipIfOnlyUpdatingCompilationDatabase bool) error {
3034
logrus.Debugf("Looking for recipes like %s", prefix+"*"+suffix)
3135

32-
// TODO is it necessary to use Clone?
33-
buildProperties := b.buildProperties.Clone()
3436
recipes := findRecipes(buildProperties, prefix, suffix)
3537

36-
// TODO is it necessary to use Clone?
37-
properties := buildProperties.Clone()
3838
for _, recipe := range recipes {
3939
logrus.Debugf("Running recipe: %s", recipe)
4040

41-
command, err := b.prepareCommandForRecipe(properties, recipe, false)
41+
command, err := b.prepareCommandForRecipe(buildProperties, recipe, false)
4242
if err != nil {
4343
return err
4444
}
@@ -60,12 +60,20 @@ func (b *Builder) RunRecipe(prefix, suffix string, skipIfOnlyUpdatingCompilation
6060

6161
func findRecipes(buildProperties *properties.Map, patternPrefix string, patternSuffix string) []string {
6262
var recipes []string
63+
64+
exactKey := patternPrefix + patternSuffix
65+
6366
for _, key := range buildProperties.Keys() {
64-
if strings.HasPrefix(key, patternPrefix) && strings.HasSuffix(key, patternSuffix) && buildProperties.Get(key) != "" {
67+
if key != exactKey && strings.HasPrefix(key, patternPrefix) && strings.HasSuffix(key, patternSuffix) && buildProperties.Get(key) != "" {
6568
recipes = append(recipes, key)
6669
}
6770
}
6871

72+
// If no recipes were found, check if the exact key exists
73+
if len(recipes) == 0 && buildProperties.Get(exactKey) != "" {
74+
recipes = append(recipes, exactKey)
75+
}
76+
6977
sort.Strings(recipes)
7078

7179
return recipes
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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 license@arduino.cc.
15+
16+
package builder
17+
18+
import (
19+
"testing"
20+
21+
properties "github.com/arduino/go-properties-orderedmap"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestRecipeFinder(t *testing.T) {
26+
t.Run("NumberedRecipes", func(t *testing.T) {
27+
buildProperties := properties.NewMap()
28+
buildProperties.Set("recipe.test", "test")
29+
buildProperties.Set("recipe.1.test", "test2")
30+
buildProperties.Set("recipe.2.test", "test3")
31+
recipes := findRecipes(buildProperties, "recipe", ".test")
32+
require.Equal(t, []string{"recipe.1.test", "recipe.2.test"}, recipes)
33+
})
34+
t.Run("NumberedRecipesWithGaps", func(t *testing.T) {
35+
buildProperties := properties.NewMap()
36+
buildProperties.Set("recipe.test", "test")
37+
buildProperties.Set("recipe.2.test", "test3")
38+
buildProperties.Set("recipe.0.test", "test2")
39+
recipes := findRecipes(buildProperties, "recipe", ".test")
40+
require.Equal(t, []string{"recipe.0.test", "recipe.2.test"}, recipes)
41+
})
42+
t.Run("NumberedRecipesWithGapsAndDifferentLenghtNumbers", func(t *testing.T) {
43+
buildProperties := properties.NewMap()
44+
buildProperties.Set("recipe.test", "test")
45+
buildProperties.Set("recipe.12.test", "test3")
46+
buildProperties.Set("recipe.2.test", "test2")
47+
recipes := findRecipes(buildProperties, "recipe", ".test")
48+
// The order is sorted alphabetically, not numerically
49+
require.Equal(t, []string{"recipe.12.test", "recipe.2.test"}, recipes)
50+
})
51+
t.Run("NumberedRecipesWithGapsAndNumbers", func(t *testing.T) {
52+
buildProperties := properties.NewMap()
53+
buildProperties.Set("recipe.test", "test")
54+
buildProperties.Set("recipe.12.test", "test3")
55+
buildProperties.Set("recipe.02.test", "test2")
56+
buildProperties.Set("recipe.09.test", "test2")
57+
recipes := findRecipes(buildProperties, "recipe", ".test")
58+
require.Equal(t, []string{"recipe.02.test", "recipe.09.test", "recipe.12.test"}, recipes)
59+
})
60+
t.Run("UnnumberedRecipies", func(t *testing.T) {
61+
buildProperties := properties.NewMap()
62+
buildProperties.Set("recipe.test", "test")
63+
buildProperties.Set("recipe.a.test", "test3")
64+
buildProperties.Set("recipe.b.test", "test2")
65+
recipes := findRecipes(buildProperties, "recipe", ".test")
66+
require.Equal(t, []string{"recipe.a.test", "recipe.b.test"}, recipes)
67+
})
68+
t.Run("ObjcopyRecipies/1", func(t *testing.T) {
69+
buildProperties := properties.NewMap()
70+
buildProperties.Set("recipe.objcopy.eep.pattern", "test")
71+
buildProperties.Set("recipe.objcopy.hex.pattern", "test")
72+
recipes := findRecipes(buildProperties, "recipe.objcopy", ".pattern")
73+
require.Equal(t, []string{"recipe.objcopy.eep.pattern", "recipe.objcopy.hex.pattern"}, recipes)
74+
})
75+
t.Run("ObjcopyRecipies/2", func(t *testing.T) {
76+
buildProperties := properties.NewMap()
77+
buildProperties.Set("recipe.objcopy.partitions.bin.pattern", "test")
78+
recipes := findRecipes(buildProperties, "recipe.objcopy", ".pattern")
79+
require.Equal(t, []string{"recipe.objcopy.partitions.bin.pattern"}, recipes)
80+
})
81+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy