IDF Arduino as a Component Error: "undefined reference to"

DreadNaught
Posts: 8
Joined: Thu May 09, 2024 1:17 am

IDF Arduino as a Component Error: "undefined reference to"

Postby DreadNaught » Thu May 09, 2024 1:40 am

I think this is a C/C++ difference issue, but don't know enough about C/C++ to know what to do :(

I am working with the Arduino library: https://github.com/miwagner/ESP32-Arduino-CAN
The example program in "esp32can_basic.ino" compiles without errors and runs in the Arduino IDE.

I have brought this into IDF using "Arduino as a Component" and have added the required files/additions in arduino/CMakeLists.txt

When "idf.py build" is run, this is the result:
(cut down to reduce clutter and save space)

Code: Select all

...arduino/libarduino.a(ESP32CAN.cpp.obj):(.literal._ZN8ESP32CAN7CANInitEv+0x0): undefined reference to `CAN_init'
..arduino/libarduino.a(ESP32CAN.cpp.obj):(.literal._ZN8ESP32CAN13CANWriteFrameEPK11CAN_frame_t+0x0): undefined reference to `CAN_write_frame'
.../arduino/libarduino.a(ESP32CAN.cpp.obj): in function `ESP32CAN::CANInit()':
...arduino/libraries/ESP32-Arduino-CAN/src/ESP32CAN.cpp:9: undefined reference to `CAN_init'
.../libarduino.a(ESP32CAN.cpp.obj): in function `ESP32CAN::CANWriteFrame(CAN_frame_t const*)':
...arduino/libraries/ESP32-Arduino-CAN/src/ESP32CAN.cpp:13: undefined reference to `CAN_write_frame'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
ninja failed with exit code 1
This is the ESP32CAN.h

Code: Select all

#ifndef ESP32CAN_H
#define ESP32CAN_H

#include "CAN_config.h"
#include "CAN.h"

class ESP32CAN
{
    public: 
        int CANInit();
		int CANConfigFilter(const CAN_filter_t* p_filter);
        int CANWriteFrame(const CAN_frame_t* p_frame);
        int CANStop();
};

extern ESP32CAN ESP32Can;
#endif
and here is the example program:

Code: Select all


#include <Arduino.h>
#include <ESP32CAN.h>
#include <CAN_config.h>


CAN_device_t CAN_cfg;               // CAN Config
unsigned long previousMillis = 0;   // will store last time a CAN Message was send
const int interval = 1000;          // interval at which send CAN Messages (milliseconds)
const int rx_queue_size = 10;       // Receive Queue size

void setup(void) {
  Serial.begin(115200);
  Serial.println("Basic Demo - ESP32-Arduino-CAN");
  CAN_cfg.speed = CAN_SPEED_125KBPS;
  CAN_cfg.tx_pin_id = GPIO_NUM_5;
  CAN_cfg.rx_pin_id = GPIO_NUM_4;
  CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
  // Init CAN Module
  ESP32Can.CANInit();
}

void loop(void) {

  CAN_frame_t rx_frame;

  unsigned long currentMillis = millis();

  // Receive next CAN frame from queue
  if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3 * portTICK_PERIOD_MS) == pdTRUE) {

    if (rx_frame.FIR.B.FF == CAN_frame_std) {
      printf("New standard frame");
    }
    else {
      printf("New extended frame");
    }

    if (rx_frame.FIR.B.RTR == CAN_RTR) {
      printf(" RTR from 0x%08X, DLC %d\r\n", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
    }
    else {
      printf(" from 0x%08X, DLC %d, Data ", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
      for (int i = 0; i < rx_frame.FIR.B.DLC; i++) {
        printf("0x%02X ", rx_frame.data.u8[i]);
      }
      printf("\n");
    }
  }
  // Send CAN Message
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    CAN_frame_t tx_frame;
    tx_frame.FIR.B.FF = CAN_frame_std;
    tx_frame.MsgID = 0x001;
    tx_frame.FIR.B.DLC = 8;
    tx_frame.data.u8[0] = 0x00;
    tx_frame.data.u8[1] = 0x01;
    tx_frame.data.u8[2] = 0x02;
    tx_frame.data.u8[3] = 0x03;
    tx_frame.data.u8[4] = 0x04;
    tx_frame.data.u8[5] = 0x05;
    tx_frame.data.u8[6] = 0x06;
    tx_frame.data.u8[7] = 0x07;
    ESP32Can.CANWriteFrame(&tx_frame);
  }
}
I do understand that IDF/TWAIN is a better solution, but knowing how to fix this will help me with other projects I want to bring into IDF.

Any suggestion or thoughts on what I can try to resolve this?
Thank you in advance!

MicroController
Posts: 1702
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: IDF Arduino as a Component Error: "undefined reference to"

Postby MicroController » Thu May 09, 2024 8:39 pm

CAN_init() and CAN_write_frame() are defined in CAN.c. Looks like that file may not be included in the build (via CMakeLists.txt), hence the linker cannot find the functions.

DreadNaught
Posts: 8
Joined: Thu May 09, 2024 1:17 am

Re: IDF Arduino as a Component Error: "undefined reference to"

Postby DreadNaught » Fri May 10, 2024 2:48 pm

Thanks for your suggestions.

I went back the next day and had a close look.
You were right, I missed CAN.c.
I renamed it CAN.cpp and added it to the CMakeLists.txt.

All is working well now!
Thanks you!

MicroController
Posts: 1702
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: IDF Arduino as a Component Error: "undefined reference to"

Postby MicroController » Mon May 13, 2024 8:09 am

Glad you got it working.

FWIW, to be able to call C functions from C++ code the C functions need to be declared 'extern "C"'.
The standard approach to make functions available to both C and C++ is to wrap their declarations in the header file in

Code: Select all

#ifdef __cplusplus
extern "C"
{
#endif

// C function declarations

#ifdef __cplusplus
} // extern "C"
#endif
See e.g. https://embeddedartistry.com/blog/2017/ ... -extern-c/

DreadNaught
Posts: 8
Joined: Thu May 09, 2024 1:17 am

Re: IDF Arduino as a Component Error: "undefined reference to"

Postby DreadNaught » Tue Jun 18, 2024 4:19 pm

Thanks for this!
I've seen this on a few programs and will now spend some time to understand it better.

Who is online

Users browsing this forum: No registered users and 84 guests