'Undefined reference' to library in `lib/` directory

I am using CLion. I created a new project for an Arduino example that I’m following. I created the project using this command:

platformio init --ide clion --board megaatmega2560 --project-dir my-dir

I have included a library in the lib/ directory and put the header file in the include/ directory. Here is my project structure:

.
├── CMakeLists.txt
├── CMakeListsPrivate.txt
├── cmake-build-debug
│   └── CMakeFiles
├── cmake-build-megaatmega2560
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── Makefile
│   ├── cmake_install.cmake
│   └── proximity-alarm.cbp
├── include
│   ├── README
│   └── SR04.h
├── lib
│   ├── README
│   ├── SR04.cpp
│   └── SR04.h
├── platformio.ini
├── src
│   └── proximity_alarm.cpp
└── test
    └── README

I opened this project in CLion and have run “Reload CMake Project” a few times.

In proximity_alarm.cpp, I am including the library like this:

#include <Arduino.h>
#include <SR04.h>

# other code

When I build, I am getting this error:

/var/folders/5f/q429hvss3w5cymp2m3dk_31c0000gp/T//cc0yW322.ltrans2.ltrans.o: In function `global constructors keyed to 65535_0_proximity_alarm.cpp.o.1900':
<artificial>:(.text.startup+0x64): undefined reference to `SR04::SR04(int, int)'

Originally for this project, I used pio to install this library like this:

pio lib install --save lib/HC-SR04/

But that installed the library to some mysterious .pio directory and I would rather avoid having to run a command to install libraries for my projects, and I would rather rely on dropping files in include/ or lib/, which is why I recreated this project and am trying to debug why the lib/ directory is not working as expected.

The proximity_alarm.cpp code is unchanged, I know that it works when the SR04 library is on the path/linked/whatever correctly. I’m trying to understand why it’s not being found - I was expecting the pio project to bootstrap the lib include paths for the lib/ and include/ directories.

What gives?

I have read this question and answers: Don't understand how /lib in the project folder works??? · Issue #273 · platformio/platformio-core · GitHub

I have tried this lib structure, but a failure still occurs:

├── lib
│   ├── README
│   └── SR04
│       ├── SR04.cpp
│       └── SR04.h

I have also read: Redirecting...

And I think I’m doing what it says, but it still doesn’t compile :frowning: Do I need to configure anything else (like the ini or CMakeList file)?

Edit:

I see this library in my ‘External Libraries’ section:

When I ‘reveal’ the location of that library it is pointing to my lib/SR04/* path, which I think is good, but I am still perplexed as to why it wont compile.

Also, interestingly my #include autocompletes:

I doubt that was quite the command:

pio lib install --save lib/HC-SR04/

As it would (correctly, as there is no library with the name lib/HC-SR04) fail with

Error: Library `{'name': 'lib/HC-SR04/', 'requirements': None}` has not been found in PlatformIO Registry.
You can ignore this message, if `{'name': 'lib/HC-SR04/', 'requirements': None}` is a built-in library (included in framework, SDK). E.g., SPI, Wire, etc.

The pio lib install command is meant to work with the standard library storage mechanism of PIO, which is to either use a global library, or project specific storage. If you had used just pio lib install --save HC-SR04

pio lib install --save HC-SR04
Looking for HC-SR04 library in registry
Conflict: More than one library has been found by request {"name": "HC-SR04", "requirements": null}:
Found: https://platformio.org/lib/show/2350/HC-SR04
LibraryManager: Installing id=2350
HC-SR04 @ be89035b2c has been successfully installed!

I can see at least two issues here

  • since there are multiple matches for that name, you may not have the correct SR04 library installed. i.e. there are 20 overall matches, and two with that exact name… which is the one you actually wanted? This is when you need to use the library ID, although that situation should be improving in the near future.
    image
  • when you run the pio lib install --save command, the --save parameter instructs PIO to add the specified library to the lib_deps parameter of your platformio.ini file, so that if you ever try to build the project on a machine where the library isn’t present, it will be automatically installed (to project-dir\.pio\libdeps\env-name\lib-name) - no manual intervention required. It’s done this way to allow for different environments to have different libraries and library versions, and to allow complete control over exactly which version of which library your code uses. If you don’t want that, you’re better off ignoring pio lib install completely, and instead putting the librarys in \lib manually.
1 Like

I think you’re misunderstanding what I’m asking about.

The command I ran does work, but it relies on a local file-system library, not the PIO registery of libraries:

$ pio lib list
Library Storage: [redacted]/proximity-alarm/.pio/libdeps/megaatmega2560
No items found

$ pio lib install lib/SR04/
Library Storage: [redacted]/proximity-alarm/.pio/libdeps/megaatmega2560
LibraryManager: Installing SR04
SR04 @ 0.0.0 has been successfully installed!

$ pio lib list
Library Storage: [redacted]/proximity-alarm/.pio/libdeps/megaatmega2560
SR04
====

Version: 0.0.0
Keywords: uncategorized
Source: file://lib/SR04/

$ pio lib uninstall SR04
Library Storage: [redacted]/proximity-alarm/.pio/libdeps/megaatmega2560
Uninstalling SR04 @ 0.0.0: 	[OK]

$ pio lib list
Library Storage: [redacted]/proximity-alarm/.pio/libdeps/megaatmega2560
No items found

Essentially what it does is use the local files to install the library into the PIO project library, which is hidden inside the .pio directory.

What I’m trying to understand is why my libs in my project at lib/* are not on the lib deps path and are missing from compilation.

For my case, pretend I’m not talking about the SR04 library, instead pretend it’s a personal library that I have written. I have tested this by creating a jong.h and jong.cpp file and putting them in lib/ as well as lib/jong/, but neither works.

This is what I’m trying to accomplish - when I put .cpp and .h files into lib/, they are not available in my project. By ‘not available’ I mean:

  • compiling will fail with the undefined reference error.
  • auto-complete in CLion does not work for .h files in lib/, it only works if I put a .h file in include/.

Hm… interesting… I thought lib install would only work with local files when you put file:// at the front… anyway… if it’s in \lib it should be in the include path. i.e. like the example mentioned in the readme for the lib folder.

|--lib
|  |--Foo
|  |  |- Foo.c
|  |  |- Foo.h

Re-reading your first post, I realised you have SR04.h in both lib and include… I wonder if that’s confusing the linker? It should just be

├── lib
│   └── SR04
│       ├── SR04.cpp
│       └── SR04.h
├── src
│   └── proximity_alarm.cpp
└── platformio.ini

You should be able to delete everything else (except for the CMakeLists*.txt files perhaps?)

re:

auto-complete in CLion does not work for .h files in lib/ , it only works if I put a .h file in include/ .

Someone who’s familiar with CLion will have help you with that one… All I can suggest is that it mentions in the docs to run platformio init --ide “to refresh source files list” and to check if you installed the File Watchers plugin - needed “to automatically update project configuration when changes are made in platformio.ini” .

1 Like

This was the thing I was missing!

I ran this command:

pio init --ide clion

In my project directory and I see this diff:

 <?xml version="1.0" encoding="UTF-8"?>
-<module classpath="CMake" type="CPP_MODULE" version="4" />
\ No newline at end of file
+<module type="CPP_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

For both .idea/clion.iml and .idea/platformio.iml.

I had been doing the Reload CMake Project menu action in CLion whenever I added files, I guess that is different from running pio init. I think that means I need to do both whenever I add a file. Maybe future additions to lib will not require anything since it looks like that directory is used for sources now.

Thank you!

What is working: auto-complete from lib/* and compiling.

1 Like

Fantastic! :slight_smile: Glad it’s all working for you now!

And I think I remember seeing something suggesting why the Reload CMake Project isn’t doing anything useful… probably something to do with this: :wink:

PlatformIO Core (CLI) DOES NOT depend on CMake , it has own cross-platform Build System.