Arduino IDE 2 pico build process problem

PC: Mint 22
Arduino IDE 2.3.6
Board: pico2040
Programmer: picoprobe
Board lib installed:

  • pico rp2040/2350 5.4.2
  • rp 2040 Ethernet
    Board config selected: pico(picoprobe)

Intro
I am using the PC/pico/picotool for over a year. Geany, pure c++ (no Arduino code), Cmake, make, arm compiler, openocd, minicom. Cumbersome but no issues.

I just started to use Arduino IDE 2.3.6. Problems galore.

The setup
Simple .ino has some printouts to Serial1. Compiles, uploads runs fine prints out the few lines.

There is the typical blink function, that works as it should.

But I have some 30 other files in the project. When I copy them into the sketch's directory, and compile, they are being compiled. Interesting because THEY ARE NOT INCLUDED IN THE .ino. Not one of them. They are just sitting in the dir.

Only the <Arduino.h> is included in the .ino.

It takes some time to build but OK, I can live with that.
Building is OK.

Then I upload it.
Goes fine, verifies OK.

But it doesn’t print out anything. Doesn’t blink either. I hard reset the pico – nothing at all.

Yes it is set to debug core, port serial1, ttyACM0 as it’s the only one.
And I closed the Arduino serial monitor and opened minicom. Yes, minicom is also set up correctly, works in all other cases.

If I remove the files, it works again. Blinks, Arduino serial or minicom prints what needs to be.

So the million dollar question is, how do these not-involved files affect the otherwise simple project?

Thanks

All .ino files in a sketch directory will be merged into one big .ino.cpp file which will be compiled.

If you're using .h / .cpp files all .cpp files will compiled, that is how the process works. Those compiled .cpp files will also be linked in the final executable; the parts that are not needed are "thrown away". But if you don't include anything it should not be an issue.

I hope that the above explains it.

Note:
A sketch is not a file (.ino) but a directory with the name of the main .ino file in that directory.

You are of course right. It shouldn't be an issue - but it is.
This is exactly the problem.

So the question still stands: how do these not-involved files affect the otherwise simple project?

So I did a little test.

A new, empty ino with Arduino.h included builds to a 64k ino.bin

I cleaned up my project's ino, empty setup/loop or otherwise, with Arduino.h included. Builds to 103.4 k. The other files ARE in the dir.

Then I left the setup/loop empty but enabled all #includes in the ino.
Builds to 103.4k ino.bin

Now I cleaned up the ino again from the includes and DELETED all files from the dir leaving the ino only.
Low and behold: builds to 69 K

Can you post your sketch?

If it's just two or three files just post them in a reply using code tags (just in case, see How to get the best out of this forum); please specify the filenames.

If it's more files, zip the sketch directory and attach. As a new user that functionality might be blocked.

We also would like to know where to find any non-standard libraries that you're using so we don't have to chase them down.

Aaaaammm ... it's not a big project but still, about 10-12,000 lines in 30+ files.

On the other hand, what could possibly be in those files that overrides the explicitly missing #include instruction(s) in the .ino?

An empty sketch (only setup() and loop()) compiles to

Sketch uses 53812 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

The bin file is 71,584 bytes.

After that I used the below sketch as a starter

void setup()
{
  Serial.begin(115200);
}

void loop()
{
}

Result

Sketch uses 53828 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

The bin is 71,600 bytes bytes.

Next I added two files to the IDE
somestuff.h

#include <Arduino.h>

#ifndef __SOMESTUFF__
#define __SOMESTUFF__

void printIt();

#endif

somestuff.cpp

#include "someStuff.h"

void printIt()
{
  Serial.println("some stuff");
}

I did not modify the .ino file.

The result

Sketch uses 53828 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

The bin is still 71,600 bytes

Next I added the include to the ino file

#include "someStuff.h"

void setup()
{
  Serial.begin(115200);
}

void loop()
{
}

Compiling results in no change in size

Sketch uses 53828 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

Next a call to the printIt() function was added in loop().

#include "someStuff.h"

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  printIt();
}

The result

Sketch uses 53924 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

And the bin file is 71,696 bytes.

Lastly I removed the call again and got as result

Sketch uses 53828 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 9952 bytes (1%) of dynamic memory, leaving 514336 bytes for local variables. Maximum is 524288 bytes.

So the size changed back to the previous size.

I have no idea. As demonstrated above not calling functions in additional files or including the additional someStuff.h file results in smaller size.

Thank you. Exactly what it should be.

Then why didn't the file-size decrease in my case when I DIDN't include anything and DIDN't call any functions?
This is still the question.

Zip your project, attach it to a reply and we can try to figure it out.

Again: what do you expect to find? What can in any of the files POSSIBLY instruct the preprocessor to create non-existing #include directives?
Please share it with the community.

Instead of uploading some 12 thousand lines of code + custom libs + modified core libs ... I simplified the problem.
Create a project - as per specifications at the top of my original post - called 'build_process_test' - or whatever you fancy.

Create the .ino file:
//NOTICE THE ABSENCE OF THE #include "my_class.h" DIRECTIVE!

#include <Arduino.h>

void setup() 
{
  Serial1.begin(115200);
  delay(1000);

  Serial1.print("Hello I don't print");
}

void loop() 
{
  // put your main code here, to run repeatedly:
}

Now create the intuitively named my_class.h file:

#include <Arduino.h>
class MyClassC
{
   public:
    MyClassC();
    void some_function(){Serial1.println("ERROR");}
};

extern MyClassC MyClass;

and the my_class.cpp:

#include "my_class.h"

MyClassC::MyClassC()
{
  some_function();  //<-- THIS CRASHES
}

MyClassC MyClass; //<-- IF OBJECT CREATED

Compile, upload, crashes. OK.
BUT WHY ARE THESE FILES INCLUDED IN THE .BIN?
WHY ARE THEY UPLOADED?
Herein lies the conundrum.
At least for me.

Cheers

I'm absolutely not a compiler expert so probably not the most satisfying answer but it looks like it's the way it works with the compiler for your board.

I took your ino and compiled. The result

Sketch uses 55880 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 10240 bytes (1%) of dynamic memory, leaving 514048 bytes for local variables. Maximum is 524288 bytes.

Next I added your two class files and compiled. The result

Sketch uses 55948 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 10240 bytes (1%) of dynamic memory, leaving 514048 bytes for local variables. Maximum is 524288 bytes.

Program storage increased, RAM stayed the same.

Next I modified the cpp file and did not create the object.

#include "my_class.h"

MyClassC::MyClassC()
{
  some_function();  //<-- THIS CRASHES
}

//MyClassC MyClass;  //<-- IF OBJECT CREATED

The compile result is the same as when only using the ino

Sketch uses 55880 bytes (1%) of program storage space. Maximum is 4186112 bytes.
Global variables use 10240 bytes (1%) of dynamic memory, leaving 514048 bytes for local variables. Maximum is 524288 bytes.

Based on the results, my conclusion is that the code to create the object is part of the bin file. Not using the object anywhere else has the result that the object is thrown away so RAM usage does not increase but the code to create the object stays.

I did repeat the test for an Arduino Leonardo and the results are slightly different.

Plain ino

Sketch uses 4500 bytes (15%) of program storage space. Maximum is 28672 bytes.
Global variables use 344 bytes (13%) of dynamic memory, leaving 2216 bytes for local variables. Maximum is 2560 bytes.

ino plus class files (note that both program memory and RAM usage went up instead of only program memory as was the case for the pico)

Sketch uses 4540 bytes (15%) of program storage space. Maximum is 28672 bytes.
Global variables use 352 bytes (13%) of dynamic memory, leaving 2208 bytes for local variables. Maximum is 2560 bytes.

Not creating the object

Sketch uses 4500 bytes (15%) of program storage space. Maximum is 28672 bytes.
Global variables use 344 bytes (13%) of dynamic memory, leaving 2216 bytes for local variables. Maximum is 2560 bytes.

You should never access hardware in constructors, in this case your Serial1.println() but it applies to any hardware (e.g. pins with pinMode() and digitalWrite()). The code to execute the constructor is executed before the hardware is initialised.

The flow

  1. memory initialisation
  2. construct objects
  3. call main()
    • initialise hardware; this might undo a pinMode() used in a constructor.
    • call setup()
    • in a loop call loop()

The usual way is to use a begin method that you call from setup().

If my lotto win was so sure as I was knowing that this reply will come up I would be rich as.
You are completely misunderstanding the whole lot.
I gave specific instructions - you chose to disregard.

Perhaps I can assist with your comprehension ability:

I NEW that it is a faulty code.

I specifically created it to demonstrate an issue with the build process.

The crash is created INTENTIONALLY to show that the .h and .cpp files are included in the executable even though they should not be included.

Now, if you want to contribute to the 'investigation', follow the instructions to the letter, observe the result and share it with the community.
Including the complete setup of your test environment.
THAT is the scientific way.
It would be interesting for the community to know if this happens on other IDE versions/other boards' compilers.

As far as i'm concerned with this issue i conclude:

  • the issue is in the build process - as per setup/test environment in the original post
  • possibly somewhat slack programming, not a bug
  • however, it comes up under very specific conditions thus it does not warrant much concern
  • yet it warrants this thread in case someone else comes across with the issue

I think everything is covered what needed be.
Cheers, have fun!

I don't think I did misunderstand. The only thing that I could not do is run it because I don't have Raspberry (Pico) boards.

I did try to do the analysis and that is it.