(My) Library Confusion

Hi All,

I’ve almost finished moving a project away from an Arduino board to a custom board and now stuck trying to add AdafruitLiquidCrystal library.

As I understand I should add “lib_deps = AdafruitLiquidCrystal-1.1.0” to platformio.ini, on the next build the library manager should download the library and install it.

However the library manager attempts to download a version for the native OS:

Library Manager: Installing AdafruitLiquidCrystal-1.1.0
Warning! Could not find the package with 'AdafruitLiquidCrystal-1.1.0' requirements for your system 'darwin_x86_64'

I’ve manually installed the lib to the project’s lib dir and added suitable “-I” lines to build_flags and this works …almost, build completes but linking fails:

Linking .pio/build/megaatmega2560/firmware.elf
/var/folders/q9/_5q0rfh55kvglfwwp04_7nsw0000gn/T//ccegpYP1.ltrans1.ltrans.o: In function `main':
<artificial>:(.text.startup+0x502): undefined reference to `Adafruit_LiquidCrystal::setCursor(unsigned char, unsigned char)'
<artificial>:(.text.startup+0x514): undefined reference to `Adafruit_LiquidCrystal::write(unsigned char)'
<artificial>:(.text.startup+0x56e): undefined reference to `Adafruit_LiquidCrystal::setCursor(unsigned char, unsigned char)'
<artificial>:(.text.startup+0x580): undefined reference to `Adafruit_LiquidCrystal::write(unsigned char)'
/var/folders/q9/_5q0rfh55kvglfwwp04_7nsw0000gn/T//ccegpYP1.ltrans10.ltrans.o: In function `global constructors keyed to 65535_0_adc.o.4226':
<artificial>:(.text.startup+0x16): undefined reference to `Adafruit_LiquidCrystal::Adafruit_LiquidCrystal(unsigned char)'

Looks to me like the library is not being built.

I realise more info is needed but rather than me send a flood tell me what’s you would like to see.

Thanks in advance, Ken.

Why? Assuming you want the library located at GitHub - adafruit/Adafruit_LiquidCrystal: A fork of my own LiquidCrystal library, which is registered under the name

and can thus be found in the registry at PlatformIO Registry, adding the library is done per

lib_deps =
     adafruit/Adafruit LiquidCrystal @ ^1.1.0

(see “Installation” tab in library registry)

The name AdafruitLiquidCrystal-1.1.0 is not a valid library name. Library versioning requirements is done with @ <semver expression>. The name before that should include the owner and the correct name of the library. This is documented here.

I don’t understand whats going on here, I’ve used platformio since just about day one on several projects with various libraries and its just worked so I’m a bit puzzled.

Thanks, understand the requirements having now looked at the examples.

After adding the correct lib_deps line the library dependancy finder attempted to install the library but pointed out it was already installed, the build failed at the linking stage.

Deleted the library from the project lib directory and ran build again. This time LDF announced “Found 1 compatible libraries”, did not try to install the library. this time the build failed with “src/lcd.cpp:13:36: fatal error: Adafruit_LiquidCrystal.h: No such file or directory”

Restored my manually installed library to lib, now the LDF behaves differently to the way it did on my first attempt, does not attempt to install, does not mention the library is already installed but indicates it has “Found 1 compatible libraries”, build fails at link time as before.

Each attempt was preceded by closing platformio and quitting VSC.

Using pio lib install -f “Adafruit LiquidCrystal” puts the library into .pio/llibdeps/megaatmega2560/, is this where the library should go and not lib?

Anyway the build fails with “src/lcd.cpp:13:36: fatal error: Adafruit_LiquidCrystal.h: No such file or directory” again.

Seems I have two problems, no object file created for the library and LDF not doing what it should (or is it?).

Thanks again, Ken.

If you declare the library’s usage via lib_deps and want to use the library registry, you should not put the library in lib/. I would advise to remove the contents of your lib/ folder (if no other libraries are in it too) and again remove the whole .pio folder. The LDF should then simply do its job, download the library and included it in the build process.

A platformio.ini of

[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
framework = arduino
lib_deps =
     adafruit/Adafruit LiquidCrystal @ ^1.1.0

with example code from the hello world example as src/main.cpp

#include <Arduino.h>
#include "Wire.h"
#include "Adafruit_LiquidCrystal.h"

// initialize the library with the numbers of the interface pins
Adafruit_LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
}

works just fine.

Processing megaatmega2560 (platform: atmelavr; board: megaatmega2560; framework: arduino)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/megaatmega2560.html
PLATFORM: Atmel AVR (3.0.0) > Arduino Mega or Mega 2560 ATmega2560 (Mega 2560)
HARDWARE: ATMEGA2560 16MHz, 8KB RAM, 248KB Flash
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES:
 - framework-arduino-avr 5.1.0
 - toolchain-atmelavr 1.50400.190710 (5.4.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 6 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <Adafruit LiquidCrystal> 1.1.0
|   |-- <Wire> 1.0
|-- <Wire> 1.0
Building in release mode
Compiling .pio\build\megaatmega2560\src\main.cpp.o
Compiling .pio\build\megaatmega2560\libb73\Wire\Wire.cpp.o
Compiling .pio\build\megaatmega2560\libb73\Wire\utility\twi.c.o
Compiling .pio\build\megaatmega2560\lib7b1\Adafruit LiquidCrystal\Adafruit_LiquidCrystal.cpp.o
Compiling .pio\build\megaatmega2560\lib7b1\Adafruit LiquidCrystal\utility\Adafruit_MCP23008.cpp.o
Archiving .pio\build\megaatmega2560\libFrameworkArduinoVariant.a
..
Building .pio\build\megaatmega2560\firmware.hex
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   3.5% (used 286 bytes from 8192 bytes)
Flash: [          ]   2.3% (used 5778 bytes from 253952 bytes)
================== [SUCCESS] Took 2.94 seconds ==================

Your example works for me too, however it uses “framework = arduino” in platformio.ini.

My project doesn’t use the arduino framework, if I delete the framework line from the example I get:

LDF: Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies…
No dependencies
Building in release mode
Compiling .pio/build/megaatmega2560/src/main.o
src/main.cpp:1:21: fatal error: Arduino.h: No such file or directory

Following your suggestions clearing out lib dir and deleting .pio in my project I get much the same error:

toolchain-atmelavr 1.50400.190710 (5.4.0)
LDF: Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies…
No dependencies
Building in release mode
Compiling .pio/build/megaatmega2560/src/adc.o
Compiling .pio/build/megaatmega2560/src/at_speed.o
Compiling .pio/build/megaatmega2560/src/command.o
Compiling .pio/build/megaatmega2560/src/debug_print.o
Compiling .pio/build/megaatmega2560/src/ee_prom.o
Compiling .pio/build/megaatmega2560/src/keypad.o
Compiling .pio/build/megaatmega2560/src/lcd.o
Compiling .pio/build/megaatmega2560/src/main.o
src/lcd.cpp:13:36: fatal error: Adafruit_LiquidCrystal.h: No such file or directory

Ken

o_O? Your project doesn’t use Arduino yet the first line is #include <Arduino.h>? The Adafruit LiquidCrystal also has Arduino as a dependecy, more specifically the Wire library, and other Arduino core functions, so it won’t work without it. It seems you want to do use this library without Arduino? Then you need to port it.

In that case I would suggest you remove the library from lib_deps, remove the .pio folder, copy the original version into the libs/ folder and start the porting work in that folder. The same goes for the sub-dependency Adafruit_MCP23008 (for LCDs operated over an I2C GPIO expander).

Or you find a different library, leightweight, working without Arduino, just on the raw chip registers / thin HAL between.

OK, I understand.

To be accurate your example uses Arduino, my project does not, and I did point that out in my first post.

Thanks for the help you’ve given, I’ve learnt gained muck knowledge.

Ken.

1 Like

Ah okay, well I read “moving a project away from an Arduino board to a custom board” as just wanting to run the same code on the same chip but placed on a custom PCB.

Well one possibility for porting that wouldn’t take much effort is to just copy-paste the needed routines from the Arduino core, like pinMode(), digitalWrite(), and the Wire library, which have no further sub-dependencies and directly operate on registers, into the project, as a kind of quick hacky way; my 2 cents.

The code for that would be in ArduinoCore-avr/cores/arduino/wiring_digital.c at master · arduino/ArduinoCore-avr · GitHub, ArduinoCore-avr/libraries/Wire/src at master · arduino/ArduinoCore-avr · GitHub (and generally spread around the core)

What prompted my wanting to remove Arduino from my prokect was Norman Dunbar’s Multi file blink, specifically at the end where “framework = arduino” is deleted from platformio.ini.

I’m having a bit of a rethink about it now but I’d still like to understand why the libraries in libs don’t get built.

I’ve used parts of arduino code in the past but are you suggesting I just put the required parts in src and include files and give up on libs?

I like the idea of building proper “.a” style libraries that are scanned at link time without “framework = arduino” in the platformio.ini file.

Is there a way to achieve this>

Ken

Hi @deadbeef,

Ok, at that very final stage in proceedings, you no longer have setup and loop etc, nor do you have the various, helpful, Arduino Language supplied functions like pinMode, digitalWrite etc. You are in plain C/C++ world and delving into registers and bits.

Can you zip up your project source and put it somewhere I can download it and I’ll have a look? Thanks.

Cheers,
Norm.

Hi,

Thank you for your kind offer, however I should mention my project is about 10,000 lines in 50 src and include files so you may wish to reconsider.

Let me know if you want me to proceed with the upload.

All my work is pure avr, no Arduino functions. I’m stuck at library linking as libraries are not compiled when I remove “framework = arduino”.

Ken

Aahh okay. Hm, that may be a very special case.

Have you tried that with a minimal library test folder as instructed in e.g. platform-atmelavr/examples/arduino-blink/lib at develop · platformio/platform-atmelavr · GitHub? Does that work?

If you have modded libraries which were originally Arduino libraries, be sure to put those libraries into lib/, while removing them from lib_deps and the .pio folder, and remove their library.json or library.properties file so that PlatformIO cannot extract the information regarding which framework and platform this library is compatible with anymore.

If including libraries from lib/ still doesn’t work without a framework at all with even the most basic example, that is a bug and should be filed at Issues · platformio/platformio-core · GitHub.

Hmm. I have written code in pure AVR too, and used libraries of my own making with no problems.

I think @maxgerhardt is on the ball in getting you to move the library source files and deleting the properties/json files – my theory is that without a framework, the libraries need to be held within the project source tree itself, or “globally” (as I do!) By dint of a lib_extra_dirs.

If you don’t get it working, yes, I’ll still take a look but obviously, a smaller test app showing the problem would make life easier! :wink:

Cheers,
Norm.

Hi and thank you both for your replies.

I’ll create an LCD Display based Arduino framework project, get that running and then de-arduino it.

Thanks, Ken.

Hi, I’ve uploaded to Dropbox “LCD_lib_test_No_Arduino” as requested.

https://www.dropbox.com/s/942ehqtwr3gl9iz/LCD_test.tar.gz?dl=0

Here’s main.cpp derived from LCD examples:

#include "Wire.h"
#include "Adafruit_LiquidCrystal.h"

// Connect via i2c, default address #0 (A0-A2 not jumpered)
Adafruit_LiquidCrystal lcd(0);

int main() {
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Hello World!");
  // set the cursor to column 0, line 1
  lcd.setCursor(0, 1);
  // print the number of seconds since 3h25m45s ago:
  lcd.print(12345);
  while (1) { ; }
}

And here’s platformio.ini:

[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
; framework = arduino
lib_ldf_mode = off
;lib_compat_mode = off
build_flags =
;     -I/Users/kt/.platformio/packages/framework-arduino-avr/cores/arduino
     -I/Users/kt/Documents/Projects/Platformio/LCD_lib_test_No_Arduino/lib/Adafruit_LiquidCrystal-1.1.0
     -I/Users/kt/Documents/Projects/Platformio/LCD_lib_test_No_Arduino/lib/Adafruit_LiquidCrystal-1.1.0/utility
     -I/Users/kt/.platformio/packages/framework-arduino-avr/cores/arduino
     -I/Users/kt/.platformio/packages/framework-arduino-avr/variants/mega
     -I/Users/kt/.platformio/packages/framework-arduino-avr/libraries/Wire/src
;lib_extra_dirs =
;     /Users/kt/Documents/Projects/Platformio/LCD_lib_test_No_Arduino/lib

I’ve had to set “lib_ldf_mode = off”, otherwise the LDF goes off and fetches Wire library but not Adafruit_LiquidCrystal. Left the evidence there of other things I’ve played with.

Wire and Adafruit_LiquidCrystal-1.1.0 are in libs in the uploaded archive.

As before linking fails as there is no attempt top compile the libraries.

Look forward to your comments.

Ken.

Hi Ken,

I’ve managed to compile your code, after a few false starts with paths to Arduino include files etc. here’s what I’ve found:

  • Although you don’t want to be using the Arduino framework, unfortunately, the Adafruit Liquid Crystal library needs the framework as it is using the Print class, specifically Print::print(char const*) and Print::print(int, int) which are part of the framework. (Used by Serial amongst others.)

  • Because you are not including the Arduino Framework, linking fails:

    Linking .pio/build/megaatmega2560/firmware.elf
    /tmp/ccaHkSNm.ltrans0.ltrans.o: In function `_GLOBAL__sub_I_lcd':
    <artificial>:(.text.startup+0x6): undefined reference to 
    `Adafruit_LiquidCrystal::Adafruit_LiquidCrystal(unsigned char)'
    /tmp/ccaHkSNm.ltrans0.ltrans.o: In function `main':
    <artificial>:(.text.startup+0x14): undefined reference to `Adafruit_LiquidCrystal::begin(unsigned char, unsigned char, unsigned char)'
    <artificial>:(.text.startup+0x20): undefined reference to `Print::print(char const*)'
    <artificial>:(.text.startup+0x2c): undefined reference to 
    `Adafruit_LiquidCrystal::setCursor(unsigned char, unsigned char)'
    <artificial>:(.text.startup+0x3c): undefined reference to `Print::print(int, int)'
    collect2: error: ld returned 1 exit status
    

If you need to use the Adafruit Liquid Crystal library then I’m afraid that you will have to do a little porting of, at least the Print class. :frowning_face:

HTH

Cheers,
Norm.

Hello Norman,

Was your compile done with the Adafruit_LiquidCrystal library in libs or src?

Have I got the wrong end of the stick here? I’ve assumed libraries get built as .a files and only the functions required are pulled in at link time. Putting the library in src defeats that.

From the compile/link time messages it seems libraries added with lib_deps behave correctly.

I only use a couple of functions in the LCD library so I can do a cut down non-arduino version in src, along with required bits of the dependancies. Although t’s starting to look like ‘de-Arduinoing’ is not worth the effort involved.

What is the lib directory for?

It appears to be a shortcoming not to be able to write a pure avr code and have it link with pure avr libraries of my(/your) creation.

Thanks for your assistance. Ken

Hi Ken

This is my source tree, based on what your download provided:

.
├── include
│   ├── Adafruit_LiquidCrystal.h
│   └── utility
│       └── Adafruit_MCP23008.h
├── lib
│   ├── Adafruit_LiquidCrystal-1.1.0
│   │   ├── Adafruit_LiquidCrystal.cpp
│   │   ├── Adafruit_LiquidCrystal.h
│   │   └── utility
│   │       ├── Adafruit_MCP23008.cpp
│   │       └── Adafruit_MCP23008.h
│   └── Wire
│       ├── Wire.cpp
│       └── Wire.h.xxx
├── platformio.ini
└── src
    └── main.cpp

Points to note:

  • To get a compilation, I had to move various header files into include. I could have added the path’s to the directories to the build_flags with a -I option, I suppose. I had to do that for the Arduino headers anyway.
  • lib/Wire/Wire.h is only renamed to determine where it’s being picked up from by the compiler.
  • Nothing touches the Adafruit library in the compilation process.
  • If lib is present, the compiler option -I lib/Wire is passed allowing for lib/Wire/Wire.h to be found. However, -I lib/Adafruit_LiquidCrystal-1.1.0 -I lib/Adafruit_LiquidCrystal-1.1.0/utility is never passed to the compiler. (Regardless of the lib_ldf_mode and lib_compatible_mode options used.
  • Renaming lib/Adafruit_LiquidCrystal-1.1.0 folder to lib/fred makes zero difference.

This is what I ended up with in my platformio.ini:

[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
build_flags =
    -I/home/norman/.platformio/packages/framework-arduino-avr/cores/arduino
    -I/home/norman/.platformio/packages/framework-arduino-avr/variants/standard
    -I/home/norman/.platformio/packages/framework-arduino-avr/libraries/Wire/src/

Ok, if I comment out the last one, relating to Wire, then Wire.h is loaded from lib/Wire but fails to compile as other headers are required from the Arduino packages. If I rename that Wire.h it obviously isn’t found, and if I add back the include path I commented out, it’s found in there as opposed to in lib – plus, all the other dependencies are also found.

Summary:

  • The code needs far too much from the Arduino packages to be considered Arduino free.
  • The Adafruit library is never mentioned or compiled.
  • The Adafruit headers are only found if I copy them to include.
  • If I manage to get a clean compile, the linker barfs because the core.a Arduino static library hasn’t been created, so the linker cannot find the Print class stuff it is requiring from within the Adafruit library.

That’s how it should work, yes. Normally the Arduino “stuff” is compiled into a core.a library and linked – but obviously only when you use the Arduino framework.

Not that Adafruit one! I cannot get a proper download. Unless, of course, the library dependency finder is looking at the project’s framework. If I change it to use the Arduino framework, it does download.

I often write code that has no Arduino stuff in it – basically to replace the Arduino stuff! I don;t appear to have had many major problems yet.

Ahem, libraries? :grin:

Your own libraries go in lib with each separate library having its own folder, named after the library but that’s not essential. At first build time, or after any code changes to the library files, they are compiled into a library, libXXXX.a where ‘XXXX’ is the library folder name, then linked at the end of the build.
I use the lib folder for all my own AVE C++ stuff. I’m writing another book so I have quite a few of my own build libraries which are usable from Arduino and plain AVR C++ as the code doesn’t need or use any Arduino Language.

Here’s a plain AVR C++ project of mine. It is used to replicate the millis() and micros() functions in the Arduino framework, but without needing to use the Arduino framework:

.
├── include
│   └── README
├── lib
│   ├── AVRmillis
│   │   ├── AVRmillis.cpp
│   │   ├── AVRmillis.h
│   │   └── defines.h
│   └── README
├── platformio.ini
├── src
│   └── main.cpp
└── test
    └── README

Platformio.ini:

[env:uno]
platform = atmelavr
board = uno

src/main.cpp:

// Test sketch for the AVRmillis class. This one 
// does the usual "flash the built in LED" every 1000
// milliseconds.
//
// Norman Dunbar.
// 4 January 2021.

#include "avr/interrupt.h"
#include "util/delay.h"
#include "AVRmillis.h"

// Toggle the LED every flashPeriod milliseconds.
const uint16_t flashPeriod = 1000;

int main() {
    // Interrupts on! (I always forget!)
    sei();

    // Pseudo Globals.
    uint32_t timeToggled = 0;


    //--------------------------------------------------------
    // SETUP:
    //--------------------------------------------------------

    // D13/PB5 = OUTPUT.
    DDRB |= (1 << DDB5);

    //--------------------------------------------------------
    // LOOP:
    //--------------------------------------------------------
    while (1) {
        // Grab current millis time.
        uint32_t timeNow = AVRmillis.millis();

        // Has the flashPeriod expired? If so,
        // toggle the LED and save when we toggled.
        if ((timeNow - timeToggled) >= flashPeriod) {
            PINB |= (1 << PINB5);
            timeToggled = timeNow;
        }
    }

    return 0;
}

Compilation:

CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/uno.html
PLATFORM: Atmel AVR (3.1.0) > Arduino Uno
HARDWARE: ATMEGA328P 16MHz, 2KB RAM, 31.50KB Flash
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES: 
 - toolchain-atmelavr 1.50400.190710 (5.4.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <AVRmillis>
Building in release mode
Compiling .pio/build/uno/src/main.o
Compiling .pio/build/uno/lib66f/AVRmillis/AVRmillis.o
Archiving .pio/build/uno/lib66f/libAVRmillis.a
Indexing .pio/build/uno/lib66f/libAVRmillis.a
Linking .pio/build/uno/firmware.elf
Checking size .pio/build/uno/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   0.4% (used 9 bytes from 2048 bytes)
Flash: [          ]   1.4% (used 442 bytes from 32256 bytes)

Building .pio/build/uno/firmware.hex

You can see from the above that libAVRmillis.a was successfully created. It was then linked (there are no linker errors) and after an upload, I have the obligatory flashing LED on my Uno.

Admittedly, this isn’t a massive project like your’s is, but I think the main problems here is:

  • You are trying to not use Arduino stuff;
  • You are, however, using a library that itself uses Arduino stuff;
  • I suspect that the LDF doesn’t download libraries that are flagged as “arduino” when you are not using that framework. (To be confirmed.)

If you want to see the rest of the code for the AVRmillis stuff, it’s aonline in my GitHub repository at GitHub - NormanDunbar/AVRmillis: PlatformIO example code to replace the Arduino `micros` and `millis` functions. Harnesses the Timer/counter 0 overflow interrupt in exactly the same manner as the Arduino does..

HTH

Cheers,
Norm.

Hello Norm,

Thanks for taking a look at this. You got a bit further than I did, I couldn’t get any action at all with files in the lib dir with or without appropriate additions to platformio.ini, hence the question.

I was hoping I could put the LCD library in libs, delete the #include Arduino.h line, compile and start fixing the errors, replacing the Arduino specifics with standard code. However that’s not to be.

I’ve not given up on this yet, I use two functions in LCD library. I will examine your GitHub code (when I figure out how to).

Another book? I lashed out and bought the first one out of appreciation for your contributions to this forum.

Ken

If you prefer a zip or gzip etc, let me know and I’ll “Dropbox” you a copy. Bear in mind it was only an example of using the lib for. It’s not specific to your problem.

Thank you very much! I hope you find it useful.

Cheers,
Norm.