# Reference for .ino file structure? Beyond setup() and loop()

**URL:** <https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552>\
**Category:** Arduino Command Line Tools\
**Created:** [September 7, 2025, 1:36am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552 "2025-09-07T01:36:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 7, 2025, 1:36am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/1 "2025-09-07T01:36:04Z")

</div>

I'm 1 day into Arduino, 35 years into writing C, and I have a very basic question about the structure of the `.ino` file. I've read the [arduino-cli documentation](https://arduino.github.io/arduino-cli/0.32/) about the **sketch** (folder) and the permissive subfolders and how they are treated, but I haven't found a reference for what is permissible in the `.ino` file itself.

I surmise it is sourced as a translation unit and the `void setup (void)` and `void loop (void)` functions are then called in `main()` (wherever that hides), but other than writing all code so `setup()` initializes everything, `#define XYZ ...` providing literals, and then `loop()` being the program loop - are there any other "features" or "limitations" the `.ino` structure provides? Any other magic incantations that can be used?

_Postscript:_

Kudos for the `arduino-cli burn-bootloader` command. I acquired my two Nanos from my son who graduated with an ESET degree from A&M, and the bootloader on one of the nano boards had met an unfortunate demise while driving one motor in a robotics project. The `burn-bootloader` command fixed it right up after downloading, building and loading the `ArduinoISP` on the working nano. Pretty slick!

---

<div class="post-metadata">

**Author:** ![ptillisch](https://avatars.discourse-cdn.com/v4/letter/p/ad7895/32.png) [@ptillisch](https://forum.arduino.cc/u/ptillisch)\
**Post date:** [September 7, 2025, 1:57am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/2 "2025-09-07T01:57:38Z")

</div>

Hi @drankinatty.

> [@drankinatty](#):
>
> I surmise it is sourced as a translation unit

That is correct.

> [@drankinatty](#):
>
> `main()` (wherever that hides)

It is defined in the `main.cpp` file in the core of the board you are compiling for. You can see the file from the core of the "Arduino AVR Boards" platform that adds support to Arduino IDE for the classic Nano board here:

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/cores/arduino/main.cpp#L33-L51>

> [@drankinatty](#):
>
> are there any other "features" or "limitations" the `.ino` structure provides?

There is some relevant information here:

[https://arduino.github.io/arduino-cli/latest/sketch-build-process/#pre-processing](https://arduino.github.io/arduino-cli/latest/sketch-build-process/#pre-processing)

> - All .ino and .pde files in the sketch folder (shown in the Arduino IDE as tabs with no extension) are concatenated together, starting with the file that matches the folder name followed by the others in alphabetical order.

This is something you might have already learned from reading the Arduino Sketch Specification:

[https://arduino.github.io/arduino-cli/latest/sketch-specification/#additional-code-files](https://arduino.github.io/arduino-cli/latest/sketch-specification/#additional-code-files)

So this means you are free to break your code up into multiple `.ino` files. This can facilitate navigating a large sketch codebase, as you can jump to a given subset of the code by selecting the tab of that `.ino` file in Arduino IDE.

You can do the same by adding `.cpp`, `.h`, `.c`, etc. files to the sketch, but that is different in that the source files will be a separate translation unit, whereas the multiple `.ino` files will all be a single file (and therefore a single translation unit) when presented to the compiler. Of course there are benefits to separating the codebase into multiple translation units. However, this makes things more complicated for someone who is not already familiar with those concepts. Likewise, the function prototype generation is only done for code in `.ino` files, so if you find that feature to be convenient then that is another advantage for using multiple `.ino` files to break up a large codebase (and conversely if you don't find prototype generation to be useful, then that is a benefit of using `.cpp` files instead).

> The .cpp filename extension is then added to the resulting file.

Here you can see why the code in the `.ino` file is in a dedicated translation unit.

> - If not already present, `#include <Arduino.h>` is added to the sketch. This header file (found in the core folder for the currently selected board) includes all the definitions needed for the standard Arduino core.

(should say "declarations" instead of "definitions")

So this is why you can reference the Arduino core functions and macros in your sketch code even though there isn't a visible sign of how the declarations are made available. Likewise, if you prefer to make that explicit, you are free to add the `#include` directive. Furthermore, if for some reason you don't want that, you can do something like this:

```cpp
#if false
#include <Arduino.h>
#endif

```

The sketch preprocessor will recognize that you have explicitly provided `#include` directive for `Arduino.h`, and so will refrain from automatically adding the `#include` directive, but since you have disabled the directive via the `#if false` conditional, the declarations will not be provided to the `.ino` file.

> - Prototypes are generated for all function definitions in .ino/.pde files that don't already have prototypes.

So you can reference functions defined later in the `.ino` file, even without explicitly adding a function prototype (AKA "forward declaration") for the function. Likewise, if you prefer to explicitly provide the prototypes in your code (or if you encounter a situation where automatic prototype generation is either not supported, or is not working correctly), you are free to do that.

> - `#line` directives are added to make warning or error messages reflect the original sketch layout.

This is self-explanatory and not terribly interesting, but perhaps worth noting if you are interested in the details of how sketch preprocessing works.

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 7, 2025, 2:25am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/3 "2025-09-07T02:25:18Z")

</div>

Thank you! That hit the nail on the head. I had read the part about the multiple `.ino` files and the `src` and `data` subdirectories, I was really just curious if there were any gotchas, or additional features. I'll go through the `#pre-processing` link and see what I can uncover.

Thank you again for you detailed and salient answer.

---

<div class="post-metadata">

**Author:** ![sterretje](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/sterretje/32/391294_2.png) [@sterretje](https://forum.arduino.cc/u/sterretje)\
**Post date:** [September 7, 2025, 5:26am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/4 "2025-09-07T05:26:24Z")

</div>

> [@drankinatty](#):
>
> I was really just curious if there were any gotchas

There are. The preprocessor (in the past known as the Arduino builder) is not perfect and might place prototypes in the wrong position in the .ino file. Some examples

1. Combining multiple ino files: e.g. [Generated function prototype injected before declaration of custom parameter type for code in secondary `.ino` file · Issue #2946 · arduino/arduino-cli · GitHub](https://github.com/arduino/arduino-cli/issues/2946)
2. Even with a single ino file; e.g. [Generated function prototype injected before declaration of custom parameter type · Issue #2696 · arduino/arduino-cli · GitHub](https://github.com/arduino/arduino-cli/issues/2696)

Just mentioning it in case you encounter compile problems that can not really be explained.

---

<div class="post-metadata">

**Author:** ![westfw](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/westfw/32/213443_2.png) [@westfw](https://forum.arduino.cc/u/westfw)\
**Post date:** [September 7, 2025, 5:28am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/5 "2025-09-07T05:28:19Z")

</div>

> [@drankinatty](#):
>
> any gotchas

The C++ compiler used for AVRs does not support all of C++: it does not have most of the stuff normally in libc++, nor from the C++ STL.

(If you're a C programmer, that probably won't bother you to much...)

Certain C functions also have limited functionality (for example, printf()/etc doesn't support the full range of format specifiers, normally does not include floating point support, and "stdio" is not normally initialized or connected to anything. Then it has some extra features to deal with the embedded environment (interrupts, for instance.) The features of avr-libc are described here: [https://www.nongnu.org/avr-libc/user-manual/](https://www.nongnu.org/avr-libc/user-manual/)

"double" on an AVR is 32bits (the same as float), so it has limited precision and range compared to what you might expect.

If you end up using an ARM or ESP processor, you'll have a more complete and standard-ish C++ environment.

---

<div class="post-metadata">

**Author:** ![6v6gt](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/6v6gt/32/225488_2.png) [@6v6gt](https://forum.arduino.cc/u/6v6gt)\
**Post date:** [September 7, 2025, 7:05am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/6 "2025-09-07T07:05:35Z")

</div>

> [@drankinatty](#):
>
> gotchas. . .

Also some standard C/C++ functions are replaced by macros which can result in unexpected behaviour.

For example, `abs()` is replaced by `#define abs(x) ((x)>0?(x):-(x))` which is vulnerable to side effects say in the possible but unlikely case of `abs(++i)`

For a complete list see: [ArduinoCore-avr/cores/arduino/Arduino.h at master · arduino/ArduinoCore-avr · GitHub](https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Arduino.h)

---

<div class="post-metadata">

**Author:** ![UKHeliBob](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/ukhelibob/32/215663_2.png) [@UKHeliBob](https://forum.arduino.cc/u/UKHeliBob)\
**Post date:** [September 7, 2025, 1:48pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/7 "2025-09-07T13:48:04Z")

</div>

> [@drankinatty](#):
>
> 35 years into writing C

You might like to note that you don't actually need to use the setup()/loop() sketch format if you don't want to

If you put a main() function in your code then the compiler will not use the board specific one described previously. The disadvantage of doing that is that you have to include code to initialise the Arduino hardware and #include the Arduino specific functions if you want to use them

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 8, 2025, 7:04am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/8 "2025-09-08T07:04:25Z")

</div>

> [@UKHeliBob](#):
>
> If you put a main() function in your code then the compiler will not use the board specific one described previously. The disadvantage of doing that is that you have to include code to initialise the Arduino hardware and #include the Arduino specific functions if you want to use them

That is one other curiosity I had. I've been picking though the sources, and will give it a try. The only other embedded RISC chip I build for is the MilkV-Duo, the rest are Arm, either TI or Pi. It was quite refreshing to have the Nano be able to upload over USB directly rather than having to chain two boards together to use as a SWD probe. (pico, and I see there is a Nano RP2040 connect -- that will be nice)

> [@6v6gt](#):
>
> For example, `abs()` is replaced by `#define abs(x) ((x)>0?(x):-(x))` which is vulnerable to side effects say in the possible but unlikely case of `abs(++i)`

Macro provided UB, gotta love it. That is definitely something to lookout for, but the text-replacement for efficiency with small boards makes sense. I've gotten to where I try and avoid pre/post-increment as anything other than a loop increment. Otherwise, an additional line of code with a `+=` or `-=` helps readability (especially for older eyes), and is a small price to pay for certainty regardless of whether the value goes into a macro or function call.

> [@westfw](#):
>
> Certain C functions also have limited functionality (for example, printf()/etc doesn't support the full range of format specifiers, normally does not include floating point support, and "stdio" is not normally initialized or connected to anything. Then it has some extra features to deal with the embedded environment (interrupts, for instance.) The features of avr-libc are described here: [https://www.nongnu.org/avr-libc/user-manual/](https://www.nongnu.org/avr-libc/user-manual/)

That is what I was looking for as well. As with any new platform, finding and collecting all the documentation is always a fun scavenger hunt. It's a volume thing no matter what board you pick up. The Arduino docs are good, but it is still a bit of a hunt. You learn anything new the same way you eat a whale ... one byte at a time...

> [@sterretje](#):
>
> There are. The preprocessor (in the past known as the Arduino builder) is not perfect and might place prototypes in the wrong position in the .ino file. Some examples

Now that would have been a surprise if I wasn't looking for it. I haven't run into that yet, but I'm not much beyond the proverbial microcontroller "Hello World!" yet. But along with the pair of Nanos, I also got several bags full of IC chips (of course with their legs crumpled against the base from being tossed into a backpack). I'd turned my Nano "Hello World" blink into a fun little LM324 and 741 tester to both ease into the AVR library and to test and toss any ICs that didn't make it. (pins 6-9 to the non-inverting inputs, a voltage divider providing 2.5V to the inverting inputs, and then sequential blink with a 2-200 ms delay between toggling each opamp on/off while the LEDs chase each other `:)`

Thank you all for your help and guidance. These are exactly the type of gotchas I would stumble on, that if aware of before are a mere speed-bump, but if ignorant of, I may chase for quite some time before arriving at the cause. (we've all been there) So for that -- a double Thank You to all.

---

<div class="post-metadata">

**Author:** ![westfw](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/westfw/32/213443_2.png) [@westfw](https://forum.arduino.cc/u/westfw)\
**Post date:** [September 8, 2025, 9:49am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/9 "2025-09-08T09:49:38Z")

</div>

And finally, “int” on an avr is only 16 bits.  
Perfectly allowable and standard C, but might be a surprise…

---

<div class="post-metadata">

**Author:** ![robtillaart](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/robtillaart/32/1098811_2.png) [@robtillaart](https://forum.arduino.cc/u/robtillaart)\
**Post date:** [September 8, 2025, 3:16pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/10 "2025-09-08T15:16:21Z")

</div>

I learned to place

```arduino
Serial.println( __FILE__ ); and sometimes more e.g. a version nr

```

in sketches as at a certain moment you want to know which code is in an Arduino.

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 8, 2025, 10:20pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/11 "2025-09-08T22:20:14Z")

</div>

> [@westfw](#):
>
> And finally, “int” on an avr is only 16 bits.  
> Perfectly allowable and standard C, but might be a surprise…

Fortunately, that I did know. It's not uncommon on smaller boards and, at least the C standard leaves it to the implementation (I'd have to check the C++ standard, but can't see it being any different).

One area where I'm still scratching my head is the `arduino-cli compile` command. Is the `--build-property build.extra_flags=-DCHGDIR` the proper way to pass preprocessor defines on the command-line? In the example I want to pass a change-direction define to control conditional inclusion of code during compile. Looking at `--build-property` output, that seems to work adding to the `recipe.c.o.pattern=...` property??

```none
recipe.S.o.pattern="/home/david/dev/arm/arduino/data/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -c -g -x assembler-with-cpp -flto -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -DCHGDIR {includes} "{source_file}" -o "{object_file}"
...
recipe.c.o.pattern="/home/david/dev/arm/arduino/data/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -c -g -Os -w -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -DCHGDIR {includes} "{source_file}" -o "{object_file}"
recipe.cpp.o.pattern="/home/david/dev/arm/arduino/data/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -DCHGDIR {includes} "{source_file}" -o "{object_file}"

```

Is there another `arduino-cli` option that would be more appropriate?

---

<div class="post-metadata">

**Author:** ![ptillisch](https://avatars.discourse-cdn.com/v4/letter/p/ad7895/32.png) [@ptillisch](https://forum.arduino.cc/u/ptillisch)\
**Post date:** [September 9, 2025, 8:10am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/12 "2025-09-09T08:10:41Z")

</div>

> [@drankinatty](#):
>
> It's not uncommon on smaller boards and, at least the C standard leaves it to the implementation (I'd have to check the C++ standard, but can't see it being any different).

It is probably already clear to you, but for the benefit of others with similar question who will read this topic in the future I think it is worth noting that some of the things the participants in this discussion have mentioned are not in any way specific to the Arduino framework.

It is important for people to understand that, beyond the Arduino sketch preprocessing described in [the documentation](https://arduino.github.io/arduino-cli/latest/sketch-build-process/#pre-processing) I referenced previously, the "Arduino language" is just C++ (as implemented by the industry standard GCC toolchain of the platform, e.g., [**avr-gcc**](https://gcc.gnu.org/wiki/avr-gcc)) and the vast amount of information about C++ and the variant of GCC in use is completely applicable.

> [@drankinatty](#):
>
> . Is the `--build-property build.extra_flags=-DCHGDIR` the proper way to pass preprocessor defines on the command-line?

Not strictly. If you look at the platform configuration:

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L39-L40>

The comment indicates the `build.extra_flags` property is intended for internal use by the platform, not as a dedicated interface for free use by the user to inject compiler arguments.

And sure enough if we look in `boards.txt` we see that `build.extra_flags` is indeed used by some board definitions:

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/boards.txt#L57-L57>

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/boards.txt#L428-L428>

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/boards.txt#L471-L471>

and so on...

When you set a value of a property via the `--build-property` flag, you are overwriting the value of that property set by the platform configuration. The ability to do that can be very useful to an advanced user, but if you don't take into consideration how the property is used by the platform, then overwriting it might cause problems.

The platform does provide a set of properties that are dedicated for the exclusive use by the user to inject arguments into the compilation commands:

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L42-L49>

So these properties will be the most safe to use with the `--build-property` flag.

Of course you are welcome to set any platform property you like via the `--build-property` flag, but you should understand that this is a very powerful and advanced capability that is only intended to be used by those who have a good understanding of the internal details of how the specific platform in use is configured.

You should be able to use the set of properties I mentioned above with any of the official boards platforms maintained by the Arduino company (e.g., "Arduino AVR boards"/`arduino:avr`), but when it comes to 3rd party platforms there are no guarantees as providing these properties is only an informal convention established by Arduino, but not enforced by the platform framework. Unfortunately, for absolutely no reason, some 3rd party platform developers made use of these properties in the platform configuration (even though they could just have easily used an arbitrary property for that purpose and left the `extra_flags` property free for use by the user), meaning that if you set the value via the `--build-property` flag you will overwrite the value the platform configuration set for it, and which is intended to be part of the compilation command. It is also possible that some 3rd party platforms don't reference these properties in the compilation command "patterns", in which case setting the value of the property via the `--build-property` flag would have absolutely effect on the compilation command.

If you are interested in the subject, there is some related discussion here:

> <https://github.com/arduino/arduino-cli/issues/846>
>
> \### Describe the request
> 
> Establish two sets of standard "extra flags" build pro…perties:
> 
> \- one set for use by platform developer
> \- one set for use by the user
> 
> These should be clearly documented as being dedicated to the exclusive use by either the platform developer or the user.
> 
> The properties proposed here are only arbitrary properties, without any special use by the build system, so no changes would required in the build system. It is only a matter of setting an example for 3rd party platform developers by adding these additional properties to the \`platform.txt\` files of the official platforms with comments clearly explaining their intent.
> 
> Ideally, the properties would be documented in the \[Arduino platform specification\](https://arduino.github.io/arduino-cli/latest/platform-specification/) as well (https://github.com/arduino/arduino-cli/issues/985).
> 
> 
> \### Describe the current behavior
> 
> Arduino has established a convention of providing "extra flags" properties in \[\`platform.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#platformtxt). These properties are intended to allow the compilation process to be customized by the addition of arbitrary flags in the compilation commands.
> 
> For example:
> 
> https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L39-L49
> 
> \`\`\`text
> \# This can be overridden in boards.txt
> build.extra\_flags=
> 
> \# These can be overridden in platform.local.txt
> compiler.c.extra\_flags=
> compiler.c.elf.extra\_flags=
> compiler.S.extra\_flags=
> compiler.cpp.extra\_flags=
> compiler.ar.extra\_flags=
> compiler.objcopy.eep.extra\_flags=
> compiler.elf2hex.extra\_flags=
> \`\`\`
> 
> These properties are referenced in the appropriate compilation recipes in \`platform.txt\` (\[example\](https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L58)).
> 
> The empty definitions in \`platform.txt\` ensure that if the extra flags are not defined elsewhere, the compilation recipes referencing them will still work. Those default empty definitions can be overrriden from any of the other platform configuration files:
> 
> \- \[\`boards.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt)
> \- \[\`boards.local.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#boardslocaltxt)
> \- \[\`platform.local.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#platformlocaltxt)
> \- \[\`global platform.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#global-platformtxt)
> 
> or from the command line:
> 
> \- \[\`arduino-cli compile --build-property\`\](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli\_compile/#options) 
> \- \[\`arduino --pref\`\](https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options)
> 
> \---
> 
> From the comments in the official \`platform.txt\` files, it seems that \`build.extra\_flags\` is intended to be for the use of the boards platform developer, while the other "extra flags" properties are intended to be for the use of the user (because a platform developer has no need for \`platform.local.txt\`).
> 
> A common use case of these properties for the user would be to add \`-D\` flags (e.g., https://github.com/arduino/arduino-cli/issues/210#issuecomment-493892258, https://github.com/arduino/Arduino/issues/6344), but there are other uses.
> 
> However, platform developers sometimes use these properties in their \`boards.txt\` file (\[example\](https://github.com/MCUdude/MightyCore/blob/v2.0.5/avr/boards.txt#L103-L111)). This presents the problem that the user risks inadvertently overriding the flags defined by the boards platform if they use the "extra flags" properties to modify the compilation command (\[example\](https://github.com/arduino/arduino-cli/issues/2041)).
> 
> \### Arduino CLI version
> 
> N/A
> 
> \### Operating system
> 
> All
> 
> \### Operating system version
> 
> Any
> 
> \### Additional context
> 
> \#### Re: Possible Harmful Effect on APIs
> 
> On a certain level, this does provide the user the global macro setting capability that has been often requested, and often rejected: 
> 
> \- https://github.com/arduino/arduino-builder/issues/15
> \- https://github.com/arduino/arduino-builder/pull/29
> \- https://github.com/arduino/arduino-builder/pull/282
> \- https://github.com/arduino/arduino-builder/issues/283
> \- https://github.com/arduino/arduino-builder/issues/354
> \- https://github.com/arduino/arduino-ide/issues/1837
> \- https://github.com/arduino/Arduino/issues/421
> \- https://github.com/arduino/Arduino/issues/2547
> \- https://github.com/arduino/Arduino/issues/3635
> \- https://github.com/arduino/Arduino/pull/3717
> \- https://github.com/arduino/Arduino/pull/3757
> \- https://github.com/arduino/Arduino/issues/4528
> \- https://github.com/arduino/Arduino/issues/5084
> \- https://github.com/arduino/Arduino/issues/5390
> \- https://github.com/arduino/Arduino/issues/7189
> \- https://github.com/arduino/Arduino/issues/11108
> \- https://github.com/arduino/arduino-cli/issues/159
> \- https://github.com/arduino/arduino-cli/issues/210
> \- https://github.com/arduino/arduino-cli/pull/1117
> \- https://github.com/arduino/arduino-cli/pull/1517
> \- https://github.com/arduino/tooling-rfcs/issues/9
> \- https://github.com/arduino/tooling-rfcs/issues/22
> 
> However, I think this proposal strikes the right balance of:
> 
> \- Allowing advanced users to do advanced things
> \- Not exposing standard users to additional complexity that makes the Arduino development software less beginner friendly
> \- Being very easy for Arduino to implement
> 
> The concern has been that allowing users to set global macros will result in library developers unnecessarily using these as part of the API, making that API less beginner friendly (https://github.com/arduino/arduino-builder/issues/15#issuecomment-145558252). However, if the user is required to use a command line interface or create a specially formatted configuration file in a difficult to access location, the average user won't be interested, and so it will only make sense for a library developer to use this feature for advanced, rarely used features of the library (e.g., enable debug output for troubleshooting of the library). We have already had this "extra flags" capability \[since 2014\](https://github.com/arduino/ArduinoCore-avr/commit/2b9f022eaad0d107b1516c22ac02bdac4977223b), yet I haven't seen it result in any significant incorporation of user set global macros into the user-level API of Arduino libraries.
> 
> \#### Additional requests
> 
> \- https://github.com/arduino/arduino-cli/issues/846#issuecomment-1400723208
> \- https://github.com/arduino/ArduinoCore-avr/issues/1#issue-264722497
> \- https://github.com/synytsim/AudioLab/issues/6#issuecomment-2785057225
> \- https://forum.arduino.cc/t/using-build-property-to-set-optimize-and-define-symbols/1254465
> \- https://forum.arduino.cc/t/compiler-option-defines-overriding-esp32-and-not-compiling/990862
> \- https://forum.arduino.cc/t/how-to-add-compile-options-to-arduino-ide-1-8-13/692640/3
> \- https://forum.arduino.cc/t/ide-to-command-line-build-support-d/682481/3
> \- https://forum.arduino.cc/t/what-could-prevent-platform-local-txt-from-being-read/674998
> 
> \#### Related
> 
> \- https://github.com/arduino/arduino-cli/issues/2706
> \- https://github.com/arduino/arduino-cli/issues/2908
> \- https://github.com/espressif/arduino-esp32/discussions/11087
> 
> \### Issue checklist
> 
> \- \[X\] I searched for previous requests in \[the issue tracker\](https://github.com/arduino/arduino-cli/issues?q=)
> \- \[X\] I verified the feature was still missing when using the latest \[nightly build\](https://arduino.github.io/arduino-cli/dev/installation/#nightly-builds)
> \- \[X\] My request contains all necessary details

* * *

❗ Please only comment on the GitHub issue thread if you have new technical information that will assist with the resolution. General discussion and support requests are always welcome here on Arduino Forum.

* * *

> [@drankinatty](#):
>
> Is there another `arduino-cli` option that would be more appropriate?

For this specific use case, the `--build-property` flag is the correct feature to use. It is only the specific platform property you chose to use with the flag that is questionable.

However, it is worth mentioning that some boards definitions provide "[custom board options](https://arduino.github.io/arduino-cli/latest/platform-specification/#custom-board-options)" which allow the user to adjust the configuration of the definition. If the configuration you need is provided by a custom board option, then you should use that as this is a public interface of the board definition the platform developer has explicitly provided to the user (meaning it is less prone to breakage or unexpected behavior than setting platform properties directly, which the average 3rd party platform developer likely doesn't ever consider the user might do). You can set the custom board options via [the `--board-options` flag](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli_compile/#options), or if you prefer via the `--fqbn` flag value ([reference](https://arduino.github.io/arduino-cli/dev/FAQ/#whats-the-fqbn-string)).

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 9, 2025, 10:15pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/13 "2025-09-09T22:15:04Z")

</div>

> [@ptillisch](#):
>
> When you set a value of a property via the `--build-property` flag, you are overwriting the value of that property set by the platform configuration. The ability to do that can be very useful to an advanced user, but if you don't take into consideration how the property is used by the platform, then overwriting it might cause problems.

Ah, thank you. I had indeed looked at the language flags:

> [@ptillisch](#):
>
> ```arduino
> # These can be overridden in platform.local.txt
> compiler.c.extra_flags=
> compiler.c.elf.extra_flags=
> 
> ```

but my intent was to "Append" instead of "Override", so I looked for an `....extra_flags=` that wasn't already populated for the nano -- without understanding the implications for other boards.

Which I suspect is what the github topic is for -- and I will stop by and comment. A simple way to "Add" or "Append" without a complete need to "Copy existing + Append" to add a preprocessor flag would be quite helpful.

Even for small test files, like the LED example above, I may have several defines that conditionally include code to isolate specific areas of code I'm digesting, or to simply allow for changing the behavior of the code (like changing the direction [sequence] in which the LM324 opamps are called from the code to reverse the directions of LEDs.

I had thought that `arduino-cli` may just "Pass what's Leftover" as part of the command-line allowing it to be treated like a typical call to `gcc`, etc.. But I see the challenge with the build environment combining C/C++/Assembly compilation in a single command.

Question - is this were interacting though the gRPC daemon provides a finer-grained way of interacting with the build process? (I haven't fully digested how to interact with it other than looking over the various properties it exposes). If that allows the ability to grab the current, e.g. `compiler.c.extra_flags=` values and then be able to append the wanted define - that would make that process easier. (I'll read further there)

Thanks again for the education on where my use of `build.extra_flags=` could run into problems (and for all of your other sage advice)

---

<div class="post-metadata">

**Author:** ![ptillisch](https://avatars.discourse-cdn.com/v4/letter/p/ad7895/32.png) [@ptillisch](https://forum.arduino.cc/u/ptillisch)\
**Post date:** [September 9, 2025, 10:35pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/14 "2025-09-09T22:35:34Z")

</div>

> [@drankinatty](#):
>
> A simple way to "Add" or "Append" without a complete need to "Copy existing + Append" to add a preprocessor flag would be quite helpful.

That is exactly what the flags I pointed out are used for:

> [@ptillisch](#):
>
> The platform does provide a set of properties that are dedicated for the exclusive use by the user to inject arguments into the compilation commands:
> 
> [https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L42-L49](https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L42-L49)

The platform's definitions of the properties are empty, so the arguments you provide via the `--build-property` flag and these will simply be added to the compilation command, without removing anything from the command.

> [@drankinatty](#):
>
> is this were interacting though the gRPC daemon provides a finer-grained way of interacting with the build process?

No. It only provides an option for a tighter integration of Arduino CLI into other applications (e.g., Arduino IDE) than would be possible using the command line interface.

> [@drankinatty](#):
>
> If that allows the ability to grab the current, e.g. `compiler.c.extra_flags=` values

You can get the value using the command line by running the `arduino-cli compile` command with the `--show-properties` flag.

> [@drankinatty](#):
>
> and then be able to append the wanted define

As I already explained, you don't need to worry about "appending" as long as you use the properties that are provided for this purpose.

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 9, 2025, 10:58pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/15 "2025-09-09T22:58:49Z")

</div>

Got it! That is where I had a bit of confusion. I didn't know whether the, e.g. `compiler.c.extra_flags=` could be used elsewhere internally like the `build.extra_flags=` property. If the former is for dedicated use of the user, then we are good to go. Thank you again.

---

<div class="post-metadata">

**Author:** ![ptillisch](https://avatars.discourse-cdn.com/v4/letter/p/ad7895/32.png) [@ptillisch](https://forum.arduino.cc/u/ptillisch)\
**Post date:** [September 9, 2025, 11:17pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/16 "2025-09-09T23:17:22Z")

</div>

> [@drankinatty](#):
>
> I didn't know whether the, e.g. `compiler.c.extra_flags=` could be used elsewhere internally like the `build.extra_flags=` property.

They could be. There is nothing in the platform framework that prevents the platform developer from doing something annoying like that. As I already explained:

> [@ptillisch](#):
>
> when it comes to 3rd party platforms there are no guarantees as providing these properties is only an informal convention established by Arduino, but not enforced by the platform framework. Unfortunately, for absolutely no reason, some 3rd party platform developers made use of these properties in the platform configuration (even though they could just have easily used an arbitrary property for that purpose and left the `extra_flags` property free for use by the user), meaning that if you set the value via the `--build-property` flag you will overwrite the value the platform configuration set for it, and which is intended to be part of the compilation command.

For example, you can see it done here for absolutely no good reason in the popular "MiniCore" boards platform:

> <https://github.com/MCUdude/MiniCore/blob/v3.1.1/avr/boards.txt#L120-L122>

However, as I already explained:

> [@ptillisch](#):
>
> You should be able to use the set of properties I mentioned above with any of the official boards platforms maintained by the Arduino company (e.g., "Arduino AVR boards"/`arduino:avr`)

So if you are using the `arduino:avr` platform (i.e., `arduino-cli compile --fqbn arduino:avr:nano`) then you don't need to worry about that because the Arduino developers were smart enough to actually leave the properties free for exclusive use by the user as intended.

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 10, 2025, 12:51am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/17 "2025-09-10T00:51:54Z")

</div>

Here is an interesting caveat that I didn't expect. Setting the define with `compiler.c.extra_flags=-DCHGDIR` isn't sufficient to include the define as part of the build. Using the compile string1:

```none
$ acli compile --fqbn arduino:avr:nano sketches/lm324-led-chase --warnings all 
--build-property compiler.c.extra_flags=-DCHGDIR

```

This doesn't alter the resulting `recipe.preproc.macros` property used in the build. Presumably due to the final build being done with `avr-g++`. Setting also the property `compile.cpp.extra_flags` does make the define visible to the final part of the build/link, e.g.

```none
$ acli compile --fqbn arduino:avr:nano sketches/lm324-led-chase --warnings all 
--build-property compiler.c.extra_flags=-DCHGDIR 
--build-property compiler.cpp.extra_flags=-DCHGDIR

```

Including the `compile.c.extra_flags=-DCHGDIR`, but not the `compile.cpp.extra_flags` property results in:

```none
recipe.preproc.macros="/home/david/dev/arm/arduino/data/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++"
 -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions 
-ffunction-sections -fdata-sections -fno-threadsafe-statics 
-Wno-error=narrowing -MMD -flto -w -x c++ -E -CC -mmcu=atmega328p 
-DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_NANO 
-DARDUINO_ARCH_AVR {includes} "{source_file}" 
-o "{preprocessed_file_path}"

```

Arduino ultimately using `avg-g++` for the build, this does make sense. Another week or so feeling like I'm drinking from a fire-hose digesting all the new Arduino process details, and I may have a solid beginner's understanding for using the Nano.

Thanks again for helping fill in the gaps.

_ **footnotes:** _

(1) `acli` is aliased to `arduino-cli` (saves hunting and pecking for keys)

---

<div class="post-metadata">

**Author:** ![ptillisch](https://avatars.discourse-cdn.com/v4/letter/p/ad7895/32.png) [@ptillisch](https://forum.arduino.cc/u/ptillisch)\
**Post date:** [September 10, 2025, 12:56am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/18 "2025-09-10T00:56:41Z")

</div>

`compile.c.extra_flags` is referenced in the pattern (i.e., template) for the `avr-gcc` command used to compile the `.c` files of the sketch program:

> <https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L54-L55>

(note the `{compile.c.extra_flags}` property reference in the pattern)

---

<div class="post-metadata">

**Author:** ![westfw](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/westfw/32/213443_2.png) [@westfw](https://forum.arduino.cc/u/westfw)\
**Post date:** [September 10, 2025, 9:49am UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/19 "2025-09-10T09:49:51Z")

</div>

Someone should point out that modifying the compile/etc commands is NOT “the arduino way”, and is not commonly done to achieve the sort of results that you are describing. Better to use a config.h that your sketch includes. (Note that the extra flags we’ve been talking about will be applied to the entire arduino core and any libraries as well as your sketch code, which could result in surprises.) (and I’m not sure the builder will get dependencies right if all you change is a compile flag.)

Yeah, that makes it harder to compile different option-versions of a sketch without actually editing a file, but that’s what the ide is for…

---

<div class="post-metadata">

**Author:** ![drankinatty](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/drankinatty/32/1236230_2.png) [@drankinatty](https://forum.arduino.cc/u/drankinatty)\
**Post date:** [September 10, 2025, 9:04pm UTC](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552/20 "2025-09-10T21:04:01Z")

</div>

Thank you for explaining the application to the entire arduino core. I like to be able to build manually, from the command line when learning a build system. I long ago learned that if you understand how your code is actually built, you can then tell and IDE how you want it done instead of just hoping the IDE config gets it right.

I want to make sure I understand, if using, e.g. `compile.c.extra_flags` isn't what one is supposed to do, then what are those build properties for? Yes, I could include a `config.h` or, for that matter, just manually edit the primary sketch file each time I want to isolate particular code, but that seems to ignore the intended purpose of being able to specify build properties, options, etc. on the command line.

The build system works very well, but not being able to do something as simple as pass a `#define` does limit its flexibility in a significant way and the way code must be structured. Don't get me wrong, I'm not throwing rocks at the system, it's all part of learning "the arduino way" (and how to tweak it to do what I need it to do `:)`

Hopefully the github issue to add an easy way to do this will get some movement and provide a solution that doesn't have potential unwanted side effects. It's been open for a while, so maybe it's nearing the point of implementation.

[Next page](https://forum.arduino.cc/t/reference-for-ino-file-structure-beyond-setup-and-loop/1405552.md?page=2)
