diff --git a/legacy/builder/gcc_preproc_runner.go b/legacy/builder/gcc_preproc_runner.go index a1ddab96cd2..59d712f6e25 100644 --- a/legacy/builder/gcc_preproc_runner.go +++ b/legacy/builder/gcc_preproc_runner.go @@ -61,7 +61,8 @@ func prepareGCCPreprocRecipeProperties(ctx *types.Context, sourceFilePath *paths properties.SetPath(constants.BUILD_PROPERTIES_SOURCE_FILE, sourceFilePath) properties.SetPath(constants.BUILD_PROPERTIES_PREPROCESSED_FILE_PATH, targetFilePath) - includesStrings := utils.Map(includes.AsStrings(), utils.WrapWithHyphenI) + ctx.SetGlobalIncludeOption() + includesStrings := append(utils.Map(includes.AsStrings(), utils.WrapWithHyphenI), ctx.GlobalIncludeOption) properties.Set(constants.BUILD_PROPERTIES_INCLUDES, strings.Join(includesStrings, constants.SPACE)) if properties.Get(constants.RECIPE_PREPROC_MACROS) == "" { diff --git a/legacy/builder/phases/libraries_builder.go b/legacy/builder/phases/libraries_builder.go index a5253f76303..71ff97c0728 100644 --- a/legacy/builder/phases/libraries_builder.go +++ b/legacy/builder/phases/libraries_builder.go @@ -37,7 +37,8 @@ type LibrariesBuilder struct{} func (s *LibrariesBuilder) Run(ctx *types.Context) error { librariesBuildPath := ctx.LibrariesBuildPath buildProperties := ctx.BuildProperties - includes := utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI) + ctx.SetGlobalIncludeOption() + includes := append(utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI), ctx.GlobalIncludeOption) libs := ctx.ImportedLibraries if err := librariesBuildPath.MkdirAll(); err != nil { diff --git a/legacy/builder/phases/sketch_builder.go b/legacy/builder/phases/sketch_builder.go index 8fea0f129c0..c488f7b732c 100644 --- a/legacy/builder/phases/sketch_builder.go +++ b/legacy/builder/phases/sketch_builder.go @@ -27,7 +27,8 @@ type SketchBuilder struct{} func (s *SketchBuilder) Run(ctx *types.Context) error { sketchBuildPath := ctx.SketchBuildPath buildProperties := ctx.BuildProperties - includes := utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI) + ctx.SetGlobalIncludeOption() + includes := append(utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI), ctx.GlobalIncludeOption) if err := sketchBuildPath.MkdirAll(); err != nil { return errors.WithStack(err) diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index a3f8ee98626..550107b7d43 100644 --- a/legacy/builder/types/context.go +++ b/legacy/builder/types/context.go @@ -16,6 +16,7 @@ package types import ( + "os" "io" "strings" @@ -27,6 +28,7 @@ import ( "github.com/arduino/arduino-cli/arduino/libraries/librariesresolver" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/i18n" + "github.com/arduino/arduino-cli/legacy/builder/constants" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -177,6 +179,9 @@ type Context struct { // The provided source data is used instead of reading it from disk. // The keys of the map are paths relative to sketch folder. SourceOverride map[string]string + + // Compiler directive for transparent inclusion of global definition when present + GlobalIncludeOption string } // ExecutableSectionSize represents a section of the executable output file @@ -254,3 +259,23 @@ func (ctx *Context) GetLogger() i18n.Logger { func (ctx *Context) SetLogger(l i18n.Logger) { ctx.logger = l } + +func (ctx *Context) SetGlobalIncludeOption () { + if len(ctx.GlobalIncludeOption) == 0 { + + // testing existence of path/to/sketch/sketch_globals.h + + globalsHeaderName := ctx.BuildPath.Join("sketch").Join(ctx.Sketch.Name + "_globals.h").String() + _, err := os.Stat(globalsHeaderName); + + if os.IsNotExist(err) { + ctx.GetLogger().Fprintln(os.Stdout, constants.LOG_LEVEL_INFO, tr("global definition file is not present") + " '" + globalsHeaderName + "'") + } else { + ctx.GlobalIncludeOption = "-include " + ctx.GlobalIncludeOption += globalsHeaderName + ctx.GetLogger().Fprintln(os.Stdout, constants.LOG_LEVEL_INFO, tr("Using global definition file") + " '" + globalsHeaderName + "'") + } + + ctx.GlobalIncludeOption += " " + } +} diff --git a/test/testdata/sketch_with_multiple_custom_libraries/libraries2/Lib/lib2.h b/test/testdata/sketch_with_multiple_custom_libraries/libraries2/Lib/lib2.h index e69de29bb2d..8ddc0f50ff1 100644 --- a/test/testdata/sketch_with_multiple_custom_libraries/libraries2/Lib/lib2.h +++ b/test/testdata/sketch_with_multiple_custom_libraries/libraries2/Lib/lib2.h @@ -0,0 +1,6 @@ + +#ifndef LIB2_SOME_CONFIG +#define LIB2_SOME_CONFIG 0 +#endif + +#define LIB2_SOME_SIZE ((LIB2_SOME_CONFIG) * 42) diff --git a/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries.ino b/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries.ino index fb99d2a57ee..191e7cc8a19 100644 --- a/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries.ino +++ b/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries.ino @@ -1,6 +1,10 @@ #include "lib1.h" #include "lib2.h" +#if LIB2_SOME_SIZE != 42 +#error should be 42 per global configuration +#endif + void setup() { } diff --git a/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries_globals.h b/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries_globals.h new file mode 100644 index 00000000000..fc2c6a553bc --- /dev/null +++ b/test/testdata/sketch_with_multiple_custom_libraries/sketch_with_multiple_custom_libraries_globals.h @@ -0,0 +1,8 @@ + +// When it exists under the name 'sketch_globals.h' (next to 'sketch.ino'), +// this user file is always included first during libraries and sketch compilation. +// It allows global library configuration per sketch. + +#pragma once + +#define LIB2_SOME_CONFIG 1