Skip to content

Commit 923c686

Browse files
committed
Add support to specify global build defines and options
A script manages the use of a file with a unique name, like `SketchName.ino.globals.h`, in the Sketch source directory to provide compiler command-line options (build options) and sketch global defines. The build option data is encapsulated in a unique "C" comment block and extracted into the build tree during prebuild.
1 parent a736a95 commit 923c686

File tree

4 files changed

+546
-2
lines changed

4 files changed

+546
-2
lines changed

doc/faq/a06-global-build-options.rst

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
How to specify global build defines and options
2+
===============================================
3+
4+
To create global defines for a Sketch, create a file with a name based
5+
on your sketch’s file name followed by ``.globals.h`` in the Sketch folder.
6+
For example, if the main Sketch file is named
7+
``LowWatermark.ino``, its global defines file would be
8+
``LowWatermark.ino.globals.h``. This file will be implicitly included
9+
with every module built for your Sketch. Do not directly include it in
10+
any of your sketch files or in any other source files. There is no need
11+
to create empty/dummy files, when not used.
12+
13+
This global define ``.h`` also supports embedding compiler command-line
14+
options in a unique “C” block comment. Compiler options are placed in a
15+
“C” block comment starting with ``/*@create-file:build.opt@``. This
16+
signature line must be alone on a single line. The block comment ending
17+
``*/`` should also be alone on a single line. In between, place your
18+
compiler command-line options just as you would have for the GCC @file
19+
command option.
20+
21+
Actions taken in processing comment block to create ``build.opt`` \* for
22+
each line, white space is trimmed \* blank lines are skipped \* lines
23+
starting with ``*``, ``//``, or ``#`` are skipped \* the remaining
24+
results are written to build tree\ ``/core/build.opt`` \* ``build.opt``
25+
is finished with a ``-include ...`` command, which references the global
26+
.h its contents were extracted from.
27+
28+
Example Sketch: ``LowWatermark.ino``
29+
30+
.. code:: cpp
31+
32+
#include <umm_malloc/umm_malloc.h> // has prototype for umm_free_heap_size_min()
33+
34+
void setup() {
35+
Serial.begin(115200);
36+
delay(200);
37+
#ifdef MYTITLE1
38+
Serial.printf("\r\n" MYTITLE1 MYTITLE2 "\r\n");
39+
#else
40+
Serial.println("ERROR: MYTITLE1 not present");
41+
#endif
42+
Serial.printf("Heap Low Watermark %u\r\n", umm_free_heap_size_min());
43+
}
44+
45+
void loop() {}
46+
47+
Global ``.h`` file: ``LowWatermark.ino.globals.h``
48+
49+
.. code:: cpp
50+
51+
/*@create-file:build.opt@
52+
// An embedded build.opt file using a "C" block comment. The starting signature
53+
// must be on a line by itself. The closing block comment pattern should be on a
54+
// line by itself. Each line within the block comment will be space trimmed and
55+
// written to build.opt, skipping blank lines and lines starting with '//', '*'
56+
// or '#'.
57+
58+
* this line is ignored
59+
# this line is ignored
60+
-DMYTITLE1="\"Running on \""
61+
-O3
62+
//-fanalyzer
63+
-DUMM_STATS_FULL=1
64+
*/
65+
66+
#ifndef LOWWATERMARK_INO_GLOBALS_H
67+
#define LOWWATERMARK_INO_GLOBALS_H
68+
69+
#if !defined(__ASSEMBLER__)
70+
// Defines kept away from assembler modules
71+
// i.e. Defines for .cpp, .ino, .c ... modules
72+
#endif
73+
74+
#if defined(__cplusplus)
75+
// Defines kept private to .cpp modules
76+
//#pragma message("__cplusplus has been seen")
77+
#define MYTITLE2 "Empty"
78+
#endif
79+
80+
#if !defined(__cplusplus) && !defined(__ASSEMBLER__)
81+
// Defines kept private to .c modules
82+
#define MYTITLE2 "Full"
83+
#endif
84+
85+
#if defined(__ASSEMBLER__)
86+
// Defines kept private to assembler modules
87+
#endif
88+
89+
#endif
90+
91+
Aggressive Caching of ``core.a``
92+
================================
93+
94+
Using global defines or compiler command-line options will lead to bad
95+
builds when the **Aggressively cache compiled core** feature is enabled.
96+
When ``#define`` changes require ``core.a`` to be recompiled, and
97+
multiple Sketches are open, they can no longer reliably share one cached
98+
``core.a``. In a simple case: The 1st Sketch to be built has its version
99+
of ``core.a`` cached. Other sketches will use this cached version for
100+
their builds.
101+
102+
To turn this off, you need to find the location of ``preferences.txt``.
103+
Using the Arduino IDE, go to *File->Preferences*. Make note of the path
104+
to ``prefereces.txt``. You cannot edit the file while the Arduino IDE is
105+
running. Close all Arduino IDE windows and edit the file
106+
``preferences.txt``. Change ``compiler.cache_core=true`` to
107+
``compiler.cache_core=false`` and save. Then each sketch will maintain
108+
its *own* copy of ``core.a``. The alternative when using
109+
``compiler.cache_core=true``, is to close all Arduino IDE sketch
110+
windows. Start and run *only* one instance of the IDE, while building a
111+
Sketch that uses global defines.
112+
113+
Other build confusion
114+
=====================
115+
116+
1. Renaming files does not change the last modified timestamp, possibly
117+
causing issues when replacing files by renaming and rebuilding. A good
118+
example of this problem would be to have then fixed a typo in file
119+
name ``LowWatermark.ino.globals.h``. You need to touch (update
120+
timestamp) the file so a “rebuild all” is performed.
121+
2. When a ``.h`` file is renamed in the sketch folder, a copy of the old
122+
file remains in the build sketch folder. This can create confusion if
123+
you missed an edit in updating an ``#include`` in one or more of your
124+
modules. That module will continue to use the stale version of the
125+
``.h`` until you restart the IDE or other major changes that would
126+
cause the IDE to delete and recopy the contents from the source
127+
Sketch directory. Changes on the IDE Tools selection may cause a
128+
complete rebuild, clearing the problem. This may be the culprit for
129+
“What! It built fine last night!”

doc/faq/readme.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,12 @@ How to resolve "undefined reference to ``flashinit`'" error ?
191191
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192192
193193
Please read `flash layout <../filesystem.rst>`__ documentation entry.
194+
195+
How to specify global build defines and options?
196+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
197+
198+
Using a unique named `.h` file a `#define` value can be globally accessed.
199+
Additionally, compiler command-line options can be embedded in this file as a
200+
unique block comment.
201+
202+
`Read more <a06-global-build-options.rst>`__.

platform.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ runtime.tools.signing={runtime.platform.path}/tools/signing.py
1717
runtime.tools.elf2bin={runtime.platform.path}/tools/elf2bin.py
1818
runtime.tools.sizes={runtime.platform.path}/tools/sizes.py
1919
runtime.tools.makecorever={runtime.platform.path}/tools/makecorever.py
20+
runtime.tools.mkbuildoptglobals={runtime.platform.path}/tools/mkbuildoptglobals.py
2021
runtime.tools.mkdir={runtime.platform.path}/tools/mkdir.py
2122
runtime.tools.cp={runtime.platform.path}/tools/cp.py
2223
runtime.tools.eboot={runtime.platform.path}/bootloaders/eboot/eboot.elf
@@ -58,11 +59,18 @@ build.spiffs_start=
5859
build.spiffs_end=
5960
build.spiffs_blocksize=
6061

62+
# Fully qualified and relative file names for processing sketch global options
63+
globals.h.source.fqfn={build.source.path}/{build.project_name}.globals.h
64+
build.globals.path={build.path}/core
65+
globals.h.fqfn={build.globals.path}/{build.project_name}.globals.h
66+
build.opt.fqfn={build.globals.path}/build.opt
67+
sketchbook.globals.h.rfn=
68+
6169
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
6270
compiler.sdk.path={runtime.platform.path}/tools/sdk
6371

6472
compiler.libc.path={runtime.platform.path}/tools/sdk/libc/xtensa-lx106-elf
65-
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -D_GNU_SOURCE -DESP8266 "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core"
73+
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -D_GNU_SOURCE -DESP8266 @{build.opt.fqfn} "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core"
6674

6775
# support precompiled libraries in IDE v1.8.6+
6876
compiler.libraries.ldflags=
@@ -107,7 +115,11 @@ compiler.elf2hex.extra_flags=
107115
## needs git
108116
recipe.hooks.sketch.prebuild.pattern="{runtime.tools.python3.path}/python3" -I "{runtime.tools.signing}" --mode header --publickey "{build.source.path}/public.key" --out "{build.path}/core/Updater_Signing.h"
109117
# This is quite a working hack. This form of prebuild hook, while intuitive, is not explicitly documented.
110-
recipe.hooks.prebuild.pattern="{runtime.tools.python3.path}/python3" -I "{runtime.tools.makecorever}" --build_path "{build.path}" --platform_path "{runtime.platform.path}" --version "{version}"
118+
recipe.hooks.prebuild.1.pattern="{runtime.tools.python3.path}/python3" -I "{runtime.tools.makecorever}" --build_path "{build.path}" --platform_path "{runtime.platform.path}" --version "{version}"
119+
120+
# Handle processing sketch global options
121+
recipe.hooks.prebuild.2.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.mkbuildoptglobals}" "{globals.h.source.fqfn}" "{globals.h.fqfn}" "{build.opt.fqfn}" "{sketchbook.globals.h.rfn}"
122+
111123

112124
## Build the app.ld linker file
113125
recipe.hooks.linking.prelink.1.pattern="{runtime.tools.python3.path}/python3" -I "{runtime.tools.mkdir}" -p "{build.path}/ld_h/"

0 commit comments

Comments
 (0)