Problem with Linker including same binary structure twice

Hi folks!

I am working on a project for the ATtiny85, so flash memory is always a problem.

I have some bitmaps defined in a separate header file, defined like this:

const unsigned char joey [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, ........, 0xf0, 0x98, 0x9c };

Then I have a table to access all these bitmaps by a key value (defined in the same header file):
// list of possible non wall objects (i.e. monsters, doors, ...) (11 bytes per object)
const NON_WALL_OBJECT objectList [] PROGMEM = {
// itemType , width, verticalOffsetBits, heightBits, lineOffset, maxView, scalingThreshold, bitmapData
{ SKELETON , 28, 2 * 8, 5 * 8, 56, 3, { 1, 2, 99 }, joey },
...
{ RAT , 20, 5 * 8, 2 * 8, 40, 2, { 1, 2, 99 }, rat },
};

My problem occurs if I'm accessing this table (or a single bitmap, e.g. joey) in two methods of a class (e.g. Dungeon).
This appears to make the linker include the bitmaps (if a bitmap joey was accessed)
or all bitmaps in the table (when objectList was accessed) a second time.
I'm quite sure, because my flash size increases by sizeof(joey) or sizeof(all bitmaps).

I don't understand this behaviour...
I'm sure that all bitmaps are already in the flash, because I'm using them all the time.
The code is working fine on a larger MCU and compiles without warnings.

I can reproduce the problem with Arduino 1.8.16 (avr-gcc) and Arduino 2.0.0rc3 (clang), so this will most probably be a problem with my code.

Any ideas? I can provide more code if necessary.

Thanks in advance,
Sven

Please post a small but complete sketch that illustrates the problem

Ok, I created a minimal sketch and I think I found the source of the problem:

My project consists of

  • a project file (something.ino)
  • a header file containing all the bitmaps (e.g. 'joey')
  • a class header file (myClass.h)
  • TWO files containing the class member functions (myClassA.cpp, myClassB.cpp),
    because I wanted to split the methods logically.

If methods in both class implementation files access 'joey', 'joey' will be linked twice.

Is there anything I can do against this except merging myClassA.cpp and myClassB.cpp
back into one file?

Shouldn't the linker "know" that it is the same resource? ('#pragma once') is set...

Please enlighten me :slight_smile:

Sven

Hi folks, perhaps somebody is still watching?

Here is the a full sample sketch:

bitmapDrawing.cpp (499 Bytes)
dungeon.cpp (464 Bytes)
dungeon.h (761 Bytes)
Problem.ino (101 Bytes)

With the ATTinyCore the sketch uses 4218 bytes when the bitmap is only linked once.
If 9 line in bitmapDrawing.cpp is uncommented,
the sketch size increases by 4096 bytes, blowing the flash of the ATtiny85.

I'm still hoping for an explanation.

Sven

Did you mean line 9 of dungeon.cpp?

#define DISPLAY_SCALED_BITMAP

I don't know anything about the first part, but #pragma once only prevents double inclusion within a given translation unit. I think the more standard alternative "include guard" approach makes this more clear.

The .ino files of the sketch, bitmapDrawing.cpp, and dungeon.cpp are each separate translation units, so you get a full copy of dungeon.h in each of them.

1 Like

Yes, I did - sorry for the confusion.

Ok, that explains the identical behaviour of the two compilers and confirms my guess that the problem is in my code... :slight_smile:

I will try to declare the structure extern in one of the modules and
give it another try. Of course I could stick with all methods in one file, but that suck's.

Thanks for all replies,
Sven

I tried with extern and get my code to compile, but the linker errors out because it doesn't find the structure I declated extern.
I give up for now, the one file approach works good enough and due to the limited flash capacity the files can't get too large :stuck_out_tongue_winking_eye:

I will mark in0's reply as a solution, as it explains the root cause for the behaviour.

If anyone has a solution how to get it working with multiple source files, please let me know any :wink:

See my Post #5 in this thread.

1 Like

@gfvalvo Thanks for your tips on "best practices". They are surely true!

Nonetheless that doesn't answer my remaining question on how to share access to a structure from two source files (implementing methods of the same class):

Stay safe,
Sven

Post an MRE that demonstrates the problem. Make sure it's the smallest amount of code and files that demonstrates the problem (and only that problem) without any extraneous clutter. Post it in-line with code tags not as files I must download.

You must define this structure in one of your .cpp files.
.h files should only contain the declarations ( extern ... ), while you must have only one definition in a .cpp file.

@gfvalvo described this very well in his link.

1 Like

Mea Culpa - I seem to have missed something the last time I tried to proceed the way @gfvalvo suggested in his linked article.
When I tried to create an MRE, everything worked as it was supposed to - so no more problem here anymore.
Just a simple UTSE (User too stupid error) :wink: