[Solved!] Any way to remove unused virtual functions from final image?

I have some virtual functions that I will never call that I'd like to get rid of. Since they are in the vtable, they are 'used' as far as the linker is concerned, so they stay in.

I tried creating an override class, and using stub implementations, but the originals are still there. I think that during object creation, the base class vtable is filled in then immediately over-written with the derived class, so it's still 'referenced'.

I'd rather not have to edit the base class (EthernetClient), since I don't control it

I'm using the EthernetClient class to receive connections. I'll never call 'connect()', and right now that's bringing in about 3000 bytes of dead code (mostly DNS name resolution), that's almost 10% of the available space on a UNO.

 class WebEthernetClient : public EthernetClient
 {
 public:
 EthernetClient& operator=(const EthernetClient& rhs);

 private:
 //  Override function we don't use

 virtual int connect(const char* host, uint16_t port) override;
 };

int WebEthernetClient::connect(
 const char*, uint16_t)
{
 return 0;
}

EthernetClient& WebEthernetClient::operator=(const EthernetClient& rhs)
{
 return EthernetClient::operator=(rhs);
}

Looking at the code map, all the DNS and UDP functionality is still being pulled in.

[Edit] Of course another problem is that other parts of the Ethernet library do instantiate the EthernetClient class, so it's probably an exercise in futility for this particular case.

you can experiment with the final keyword if the source is in your control, but I was not successful with it. the compiler and LTO are not able to detect that the functions are not used.

Something that worked!

  • Define a replacement function in your .INO file (or any other file that will be linked ahead of the library that has the function you want to whack)
  • add '-Wl,--allow-multiple-definition' to the c.elf flags. You can add this in platform.txt, or use project specific options if your IDE allows it.

For my project, normal build (using a MEGA this time):

Program size: 24,088 bytes (used 9% of a 253,952 byte maximum) (3.84 secs)
Minimum Memory Usage: 1404 bytes (17% of a 8192 byte maximum)

With this option enabled, and the following in my .INO file:

int EthernetClient::connect(const char*, uint16_t)
{
 return 0;
}

the build returns this now:

Program size: 20,858 bytes (used 8% of a 253,952 byte maximum) (3.38 secs)
Minimum Memory Usage: 1356 bytes (17% of a 8192 byte maximum)

So, not only a lot less code space used, but some RAM savings as well.

For robustness, the replacement function should probably do something that will be easily noticeable during development, because if you see it, you need the original function.