Private lib: undefined reference

Hey there everyone!
Im trying heavily to implement a private library in the lib folder int o my platformio project but its not compiling and i tried everything i found on that topic in the forums, so im a bit frustrated.

My folder structure:

  • lib
    • myLib
      • myLib.h
      • myLib.c
  • src
    • main.cpp

contents of myLib.h:

void hello(void);

contents of myLib.c

#include "myLib.h"
void hello(){
}

contents of main.cpp:

#include <Arduino.h>
#include <myLib.h>
void setup(){
   hello();
}
void loop(){}

compiler output:

Compiling .pio\build\adafruit_feather_m0\FrameworkArduino\wiring_private.c.o
Compiling .pio\build\adafruit_feather_m0\FrameworkArduino\wiring_shift.c.o
Archiving .pio\build\adafruit_feather_m0\libFrameworkArduino.a
Indexing .pio\build\adafruit_feather_m0\libFrameworkArduino.a
Linking .pio\build\adafruit_feather_m0\firmware.elf
.pio\build\adafruit_feather_m0\src\main.cpp.o: In function `setup':
main.cpp:(.text.setup+0x6a): undefined reference to `hello()'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\adafruit_feather_m0\firmware.elf] Error 1

platformio.ini:

[env:adafruit_feather_m0]
platform = atmelsam
board = adafruit_feather_m0
framework = arduino
lib_deps = myLib

Please help me i dont know why its not working, already tried extra build_flags with -l etc

I’m pretty sure – about 86% – that because the hello() function does nothing, the compiler has optimised it away and the linker can’t see it. I might be wrong though – I’m away from my “toys” at present.

If you put some code in it that does something, light an LED for example, does it compile and link?

Cheers,
Norm.

Whaa-Whaa-Whaaaaaaaaa… :stuck_out_tongue: Compilers and linkers can be a bit dumb, thou, can’t they… too smart for their own good at times (or is it for our sanity?)…

It’s the file extension… the compiler probably thinks you’re trying to include C code in C++, and it doesn’t match.

If you’re not writing C code, change the file extension of your main library code file from myLib.c to myLib.cpp… otherwise, you need to wrap the include in main.cpp in extern C, like so:

extern "C" {
#include <myLib.h>
}

Not as dumb as me though! At least I had my doubts.

Thanks for spotting that which I didn’t. :slightly_smiling_face:

Cheers,
Norm.

1 Like

Wow thank you very much for your fast replies! The extern C wrapper did the trick! Thanks @pfeerick! And it looks like the compiler didn’t optimized the empty function away for some reason @normandunbar :smiley:

But another question:
When I’m Referring to other C headers from my mainLib.h do I need to add the extern C header in every header?

1 Like

The very good reason for that? I’m a pillock! :cry:

Short story: not if those libraries are in files with a .cpp extension.

Long version:

As @pfeerick pointed out, the file extension being .c is causing the C compiler to be used. Had it been .cpp then the C++ compiler would have been used. Your main.cpp is compiled by the latter and your library with the former.

C++ “decorates” function named to show which type of parameters they take as this allows for many functions with the same name, but different parameters, to be defined. C doesn’t – function names must be unique.

Your setup() function was looking for some C++ function internally called something like helloNULL() but only the C hello() was there. The extern "C" stuff tells the compiler not to decorate calls to those functions, or, to decorate them to be called from C++ – one or the other, I forget. (I’m old and decrepit!)

HTH

Cheers,
Norm.

I wouldn’t go so far as that… the glasses were probably just in need of a clean! :laughing:

Nice… I didn’t know the why, just the what was happening… see… being

has its uses… as you just explained the why :wink:

Talking of learning new tricks… :wink: I only recently found out about… string literals in C++… didn’t exist when I studied it… I studied formally learnt C++ in 2005/2006 at uni… they didn’t arrive until c++11, and by that point I wasn’t doing programming… handy tool… those string literals… you can basically tell the compiler to leave your alone with complex strings and just throw down a blob of text. i.e.

image

Only lines 20-22 will count, and will be stored exactly as laid out… no need to escape the double quotes, or backslashes, etc.

In Oracle, those string literals are called “Q Strings”. They are pretty much the same except if your opening delimiter is one of <[{( then the closing one must be one of >]}), otherwise, it’s the same as the opening one. Very handy for embedding “stuff” in a string.

mySQLQuery := q'<SELECT stuff FROM table_x WHERE surname = 'O'Brien'....>';

(I think I got that right! :wink:)

No need for escapes etc, great! They do make strings look odd though, when you are used to escaping and doubling up on quotes etc.

Cheers,
Norm,.

1 Like