diff --git a/docs/sketch-build-process.md b/docs/sketch-build-process.md
index 25347481a23..2bbe95cd61c 100644
--- a/docs/sketch-build-process.md
+++ b/docs/sketch-build-process.md
@@ -27,6 +27,9 @@ compiler:
   rare cases, prototype generation may fail for some functions. To work around this, you can provide your own prototypes
   for these functions.
 - `#line` directives are added to make warning or error messages reflect the original sketch layout.
+- Special and optional sketch variables named ARDUIFINE and ARDUINOGLOBAL are parsed, and their content is used to
+  provide more arguments to the compiler commands. Those arguments are used for every compiled source file, including
+  the core, internal and external libraries. Their content is displayed in the message area.
 
 No pre-processing is done to files in a sketch with any extension other than .ino or .pde. Additionally, .h files in the
 sketch are not automatically #included from the main sketch file. Further, if you want to call functions defined in a .c
diff --git a/i18n/data/en.po b/i18n/data/en.po
index 088e6d19e41..88c201da28a 100644
--- a/i18n/data/en.po
+++ b/i18n/data/en.po
@@ -61,7 +61,7 @@ msgstr "%s is not managed by package manager"
 msgid "%s must be installed."
 msgstr "%s must be installed."
 
-#: legacy/builder/builder_utils/utils.go:530
+#: legacy/builder/builder_utils/utils.go:533
 #: legacy/builder/ctags_runner.go:41
 msgid "%s pattern is missing"
 msgstr "%s pattern is missing"
@@ -110,6 +110,10 @@ msgstr "ARCH"
 msgid "ARDUINO COMMAND LINE MANUAL"
 msgstr "ARDUINO COMMAND LINE MANUAL"
 
+#: legacy/builder/phases/libraries_builder.go:48
+msgid "Additional compiler options provided by user sketch: {0}"
+msgstr "Additional compiler options provided by user sketch: {0}"
+
 #: cli/usage.go:32
 msgid "Additional help topics:"
 msgstr "Additional help topics:"
@@ -349,7 +353,7 @@ msgstr "Check dependencies status for the specified library."
 msgid "Checking lib install prerequisites"
 msgstr "Checking lib install prerequisites"
 
-#: legacy/builder/builder_utils/utils.go:280
+#: legacy/builder/builder_utils/utils.go:283
 msgid "Checking previous results for {0} (result = {1}, dep = {2})"
 msgstr "Checking previous results for {0} (result = {1}, dep = {2})"
 
@@ -391,7 +395,7 @@ msgstr "Compiling core..."
 msgid "Compiling libraries..."
 msgstr "Compiling libraries..."
 
-#: legacy/builder/phases/libraries_builder.go:135
+#: legacy/builder/phases/libraries_builder.go:139
 msgid "Compiling library \"{0}\""
 msgstr "Compiling library \"{0}\""
 
@@ -525,7 +529,7 @@ msgstr "Deletes a settings key and all its sub keys."
 msgid "Dependencies: %s"
 msgstr "Dependencies: %s"
 
-#: legacy/builder/builder_utils/utils.go:358
+#: legacy/builder/builder_utils/utils.go:361
 msgid "Depfile is about different file: {0}"
 msgstr "Depfile is about different file: {0}"
 
@@ -794,7 +798,7 @@ msgstr "Error getting libraries info: %v"
 msgid "Error getting port settings details: %s"
 msgstr "Error getting port settings details: %s"
 
-#: legacy/builder/types/context.go:239
+#: legacy/builder/types/context.go:244
 msgid "Error in FQBN: %s"
 msgstr "Error in FQBN: %s"
 
@@ -1059,7 +1063,7 @@ msgstr "Failed to listen on TCP port: %[1]s. Unexpected error: %[2]v"
 msgid "Failed to listen on TCP port: %s. Address already in use."
 msgstr "Failed to listen on TCP port: %s. Address already in use."
 
-#: legacy/builder/builder_utils/utils.go:380
+#: legacy/builder/builder_utils/utils.go:383
 msgid "Failed to read: {0}"
 msgstr "Failed to read: {0}"
 
@@ -1358,7 +1362,7 @@ msgstr "Library installed"
 msgid "Library name"
 msgstr "Library name"
 
-#: legacy/builder/phases/libraries_builder.go:91
+#: legacy/builder/phases/libraries_builder.go:95
 msgid "Library {0} has been declared precompiled:"
 msgstr "Library {0} has been declared precompiled:"
 
@@ -1511,7 +1515,7 @@ msgstr "New version"
 msgid "No boards found."
 msgstr "No boards found."
 
-#: legacy/builder/builder_utils/utils.go:351
+#: legacy/builder/builder_utils/utils.go:354
 msgid "No colon in first line of depfile"
 msgstr "No colon in first line of depfile"
 
@@ -1563,13 +1567,13 @@ msgstr "No valid dependencies solution found"
 msgid "Not enough memory; see %s for tips on reducing your footprint."
 msgstr "Not enough memory; see %s for tips on reducing your footprint."
 
-#: legacy/builder/builder_utils/utils.go:284
+#: legacy/builder/builder_utils/utils.go:287
 msgid "Not found: nil"
 msgstr "Not found: nil"
 
-#: legacy/builder/builder_utils/utils.go:300
-#: legacy/builder/builder_utils/utils.go:313
-#: legacy/builder/builder_utils/utils.go:387
+#: legacy/builder/builder_utils/utils.go:303
+#: legacy/builder/builder_utils/utils.go:316
+#: legacy/builder/builder_utils/utils.go:390
 msgid "Not found: {0}"
 msgstr "Not found: {0}"
 
@@ -1745,8 +1749,8 @@ msgstr "Port closed:"
 msgid "Port monitor error"
 msgstr "Port monitor error"
 
-#: legacy/builder/phases/libraries_builder.go:101
-#: legacy/builder/phases/libraries_builder.go:109
+#: legacy/builder/phases/libraries_builder.go:105
+#: legacy/builder/phases/libraries_builder.go:113
 msgid "Precompiled library in \"{0}\" not found"
 msgstr "Precompiled library in \"{0}\" not found"
 
@@ -2004,11 +2008,11 @@ msgstr "Skip linking of final executable."
 msgid "Skipping 1200-bps touch reset: no serial port selected!"
 msgstr "Skipping 1200-bps touch reset: no serial port selected!"
 
-#: legacy/builder/builder_utils/utils.go:476
+#: legacy/builder/builder_utils/utils.go:479
 msgid "Skipping archive creation of: {0}"
 msgstr "Skipping archive creation of: {0}"
 
-#: legacy/builder/builder_utils/utils.go:269
+#: legacy/builder/builder_utils/utils.go:272
 msgid "Skipping compile of: {0}"
 msgstr "Skipping compile of: {0}"
 
@@ -2069,7 +2073,7 @@ msgstr "The key '%[1]v' is not a list of items, can't remove from it.\n"
 msgid "The output format for the logs, can be: %s"
 msgstr "The output format for the logs, can be: %s"
 
-#: legacy/builder/phases/libraries_builder.go:151
+#: legacy/builder/phases/libraries_builder.go:155
 msgid "The platform does not support '{0}' for precompiled libraries."
 msgstr "The platform does not support '{0}' for precompiled libraries."
 
@@ -2333,13 +2337,13 @@ msgstr "Using library {0} in folder: {1} {2}"
 msgid "Using precompiled core: {0}"
 msgstr "Using precompiled core: {0}"
 
-#: legacy/builder/phases/libraries_builder.go:98
-#: legacy/builder/phases/libraries_builder.go:106
+#: legacy/builder/phases/libraries_builder.go:102
+#: legacy/builder/phases/libraries_builder.go:110
 msgid "Using precompiled library in {0}"
 msgstr "Using precompiled library in {0}"
 
-#: legacy/builder/builder_utils/utils.go:267
-#: legacy/builder/builder_utils/utils.go:499
+#: legacy/builder/builder_utils/utils.go:270
+#: legacy/builder/builder_utils/utils.go:502
 msgid "Using previously compiled file: {0}"
 msgstr "Using previously compiled file: {0}"
 
@@ -3429,9 +3433,9 @@ msgstr "wrong format in server response"
 msgid "{0} invalid, rebuilding all"
 msgstr "{0} invalid, rebuilding all"
 
-#: legacy/builder/builder_utils/utils.go:323
-#: legacy/builder/builder_utils/utils.go:329
-#: legacy/builder/builder_utils/utils.go:393
+#: legacy/builder/builder_utils/utils.go:326
+#: legacy/builder/builder_utils/utils.go:332
+#: legacy/builder/builder_utils/utils.go:396
 msgid "{0} newer than {1}"
 msgstr "{0} newer than {1}"
 
diff --git a/legacy/builder/builder_utils/utils.go b/legacy/builder/builder_utils/utils.go
index 5a504aa29a2..67b6992787d 100644
--- a/legacy/builder/builder_utils/utils.go
+++ b/legacy/builder/builder_utils/utils.go
@@ -232,6 +232,9 @@ func compileFileWithRecipe(ctx *types.Context, sourcePath *paths.Path, source *p
 	properties := buildProperties.Clone()
 	properties.Set(constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS, properties.Get(constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+ctx.WarningsLevel))
 	properties.Set(constants.BUILD_PROPERTIES_INCLUDES, strings.Join(includes, constants.SPACE))
+	if len(ctx.Arduifines) > 0 {
+		properties.Set(constants.BUILD_PROPERTIES_INCLUDES, properties.Get(constants.BUILD_PROPERTIES_INCLUDES) + " " + ctx.Arduifines + " ")
+	}
 	properties.SetPath(constants.BUILD_PROPERTIES_SOURCE_FILE, source)
 	relativeSource, err := sourcePath.RelTo(source)
 	if err != nil {
diff --git a/legacy/builder/ctags/ctags_parser.go b/legacy/builder/ctags/ctags_parser.go
index 97a2a2a5ee1..1953afe621a 100644
--- a/legacy/builder/ctags/ctags_parser.go
+++ b/legacy/builder/ctags/ctags_parser.go
@@ -32,6 +32,8 @@ const KIND_FUNCTION = "function"
 const TEMPLATE = "template"
 const STATIC = "static"
 const EXTERN = "extern \"C\""
+const ARDUIFINE = "ARDUIFINE"
+const ARDUINOGLOBAL = "ARDUINOGLOBAL"
 
 var KNOWN_TAG_KINDS = map[string]bool{
 	"prototype": true,
@@ -43,14 +45,21 @@ type CTagsParser struct {
 	mainFile *paths.Path
 }
 
-func (p *CTagsParser) Parse(ctagsOutput string, mainFile *paths.Path) []*types.CTag {
+func (p *CTagsParser) Parse(ctagsOutput string, mainFile *paths.Path) ([]*types.CTag, string) {
+	Arduifines := ""
 	rows := strings.Split(ctagsOutput, "\n")
 	rows = removeEmpty(rows)
 
 	p.mainFile = mainFile
 
 	for _, row := range rows {
-		p.tags = append(p.tags, parseTag(row))
+		if strings.Index(row, " "+ARDUINOGLOBAL) != -1 {
+			Arduifines += encloseForCmdLine(extractCtagsDoubleQuotedString(row, ARDUINOGLOBAL))
+		} else if strings.Index(row, " "+ARDUIFINE) != -1 {
+			Arduifines += encloseForCmdLine(toCompilerCmdLine(extractCtagsDoubleQuotedString(row, ARDUIFINE)))
+		} else {
+			p.tags = append(p.tags, parseTag(row))
+		}
 	}
 
 	p.skipTagsWhere(tagIsUnknown)
@@ -60,7 +69,7 @@ func (p *CTagsParser) Parse(ctagsOutput string, mainFile *paths.Path) []*types.C
 	p.skipDuplicates()
 	p.skipTagsWhere(p.prototypeAndCodeDontMatch)
 
-	return p.tags
+	return p.tags, Arduifines
 }
 
 func (p *CTagsParser) addPrototypes() {
@@ -238,3 +247,36 @@ func removeEmpty(rows []string) []string {
 
 	return newRows
 }
+
+func extractCtagsDoubleQuotedString (row string, directive string) string {
+	first := strings.Index(row, "\"");
+	last := strings.LastIndex(row, "\";$/;\""); // <- $/;" is a ctag addition
+	if (first <= 0) || (last <= 0) || (first + 1 >= last) {
+		//print("\nERROR: malformed \"" + directive + "\" global directive\n\n")
+		return ""
+	}
+	return strings.Replace(strings.Replace(row[first+1 : last], "\\\\", "\\", -1), "\\\"", "\"", -1)
+}
+
+func toCompilerCmdLine (define string) string {
+	// transforms ` A = "B C" ` to `-DA="B C"`
+	// transforms ` A `         to `-DA`
+	elts := strings.SplitAfterN(define, "=", 2)
+	ret := ""
+	eltsLength := len(elts)
+	if eltsLength > 0 {
+		equalsLength := eltsLength - 1
+		ret += "-D"+strings.TrimSpace(elts[0][:len(elts[0])-equalsLength])
+		if equalsLength > 0 {
+			ret += "="+strings.TrimSpace(elts[1])
+		}
+	}
+	return ret
+}
+
+func encloseForCmdLine (str string) string {
+	if len(str) > 0 {
+		return " \""+str+"\" "
+	}
+	return ""
+}
diff --git a/legacy/builder/ctags/ctags_parser_test.go b/legacy/builder/ctags/ctags_parser_test.go
index 13e10e8e79c..25de6998483 100644
--- a/legacy/builder/ctags/ctags_parser_test.go
+++ b/legacy/builder/ctags/ctags_parser_test.go
@@ -30,7 +30,9 @@ func produceTags(t *testing.T, filename string) []*types.CTag {
 	require.NoError(t, err)
 
 	parser := CTagsParser{}
-	return parser.Parse(string(bytes), nil)
+	tags, Arduifines := parser.Parse(string(bytes), nil)
+	_ = Arduifines
+	return tags
 }
 
 func TestCTagsParserShouldListPrototypes(t *testing.T) {
diff --git a/legacy/builder/ctags_runner.go b/legacy/builder/ctags_runner.go
index 299ffb45962..f6df64bdea3 100644
--- a/legacy/builder/ctags_runner.go
+++ b/legacy/builder/ctags_runner.go
@@ -56,7 +56,7 @@ func (s *CTagsRunner) Run(ctx *types.Context) error {
 
 	parser := &ctags.CTagsParser{}
 
-	ctx.CTagsOfPreprocessedSource = parser.Parse(ctx.CTagsOutput, ctx.Sketch.MainFile)
+	ctx.CTagsOfPreprocessedSource, ctx.Arduifines = parser.Parse(ctx.CTagsOutput, ctx.Sketch.MainFile)
 	parser.FixCLinkageTagsDeclarations(ctx.CTagsOfPreprocessedSource)
 
 	protos, line := parser.GeneratePrototypes()
diff --git a/legacy/builder/phases/libraries_builder.go b/legacy/builder/phases/libraries_builder.go
index a5253f76303..b42256f4ef9 100644
--- a/legacy/builder/phases/libraries_builder.go
+++ b/legacy/builder/phases/libraries_builder.go
@@ -44,6 +44,10 @@ func (s *LibrariesBuilder) Run(ctx *types.Context) error {
 		return errors.WithStack(err)
 	}
 
+	if len(ctx.Arduifines) > 0 {
+		ctx.GetLogger().Println(constants.LOG_LEVEL_DEBUG, tr("Additional compiler options provided by user sketch: {0}"), ctx.Arduifines)
+	}
+
 	objectFiles, err := compileLibraries(ctx, libs, librariesBuildPath, buildProperties, includes)
 	if err != nil {
 		return errors.WithStack(err)
diff --git a/legacy/builder/test/builder_test.go b/legacy/builder/test/builder_test.go
index 7bc35b46a39..641677c3953 100644
--- a/legacy/builder/test/builder_test.go
+++ b/legacy/builder/test/builder_test.go
@@ -43,6 +43,25 @@ func prepareBuilderTestContext(t *testing.T, sketchPath *paths.Path, fqbn string
 	}
 }
 
+func TestBuilderArduifine(t *testing.T) {
+	DownloadCoresAndToolsAndLibraries(t)
+
+	ctx := prepareBuilderTestContext(t, paths.New("sketch_arduifine", "sketch_arduifine.ino"), "arduino:avr:uno")
+	ctx.DebugLevel = 10
+
+	buildPath := SetupBuildPath(t, ctx)
+	defer buildPath.RemoveAll()
+
+	// Run builder
+	command := builder.Builder{}
+	err := command.Run(ctx)
+	NoError(t, err)
+
+	exist, err := buildPath.Join("sketch_arduifine.ino.hex").ExistCheck()
+	NoError(t, err)
+	require.True(t, exist)
+}
+
 func TestBuilderEmptySketch(t *testing.T) {
 	DownloadCoresAndToolsAndLibraries(t)
 
diff --git a/legacy/builder/test/libraries/lib4arduifine/lib4arduifine.cpp b/legacy/builder/test/libraries/lib4arduifine/lib4arduifine.cpp
new file mode 100644
index 00000000000..1baa30fc21b
--- /dev/null
+++ b/legacy/builder/test/libraries/lib4arduifine/lib4arduifine.cpp
@@ -0,0 +1,8 @@
+
+#include <lib4arduifine.h>
+
+#if MYVERSION == 1337
+#pragma message "arduifine: MYVERSION is correctly defined"
+#else
+#error arduifine: MYVERSION is not correctly defined
+#endif
diff --git a/legacy/builder/test/libraries/lib4arduifine/lib4arduifine.h b/legacy/builder/test/libraries/lib4arduifine/lib4arduifine.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/legacy/builder/test/libraries_loader_test.go b/legacy/builder/test/libraries_loader_test.go
index 9bed71806a5..7d5fdd5c2be 100644
--- a/legacy/builder/test/libraries_loader_test.go
+++ b/legacy/builder/test/libraries_loader_test.go
@@ -66,7 +66,7 @@ func TestLoadLibrariesAVR(t *testing.T) {
 	require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[2].Path))
 
 	libs := extractLibraries(ctx)
-	require.Equal(t, 24, len(libs))
+	require.Equal(t, 25, len(libs))
 
 	sort.Sort(ByLibraryName(libs))
 
@@ -176,7 +176,7 @@ func TestLoadLibrariesSAM(t *testing.T) {
 	require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[2].Path))
 
 	libraries := extractLibraries(ctx)
-	require.Equal(t, 22, len(libraries))
+	require.Equal(t, 23, len(libraries))
 
 	sort.Sort(ByLibraryName(libraries))
 
diff --git a/legacy/builder/test/sketch_arduifine/sketch_arduifine.ino b/legacy/builder/test/sketch_arduifine/sketch_arduifine.ino
new file mode 100644
index 00000000000..6ae6b4a7306
--- /dev/null
+++ b/legacy/builder/test/sketch_arduifine/sketch_arduifine.ino
@@ -0,0 +1,7 @@
+
+#include <lib4arduifine.h>
+
+const char* ARDUIFINEtest = "MYVERSION = 1337";
+
+void setup() {}
+void loop() {}
diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go
index a3f8ee98626..4d98823aa9c 100644
--- a/legacy/builder/types/context.go
+++ b/legacy/builder/types/context.go
@@ -177,6 +177,11 @@ 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 options from ctags extraction
+	// example: 'char ARDUIFINExxx = "MYLIB_BUFFER_LEN = 1234";'
+	// example: 'char ARDUINOGLOBALyyy = "-DMYLIB_BUFFER2_LEN=1234 -free -fipa-pta";'
+	Arduifines string
 }
 
 // ExecutableSectionSize represents a section of the executable output file