CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

machiel
Posts: 4
Joined: Wed Oct 09, 2019 1:29 pm

CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

Postby machiel » Mon May 02, 2022 1:58 pm

Hello, I'm facing a problem when I try to compile my basic CPP project with a component written in C but it failed to build.
Previously I was using Platform IO environment but recently I switched to esp-idf (version 4.4.1) environment. This will come with new opportunities and challenges. What I’m trying to do is making my own esp32 project with C++ (not C), and make use of some external C components. The problem is that the linker, not the compiler, can’t build my solution. The Espressif Build System with CMake is new for me and I guess that I do something wrong here. I've made the code as small as possible to get it back to the essence of the issue. Could anyone tell me what I’m missing here?

The error is as follow:
in function `app_main': …main/test.cpp:6: undefined reference to `say_hello()' collect2.exe: error: ld returned 1 exit status

20220502_vsc_project.png
20220502_vsc_project.png (13.3 KiB) Viewed 4959 times
CMakeLists.txt

Code: Select all

cmake_minimum_required(VERSION 3.8)
set(CMAKE_CXX_STANDARD 17)
set(EXTRA_COMPONENT_DIRS src include lib components)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test)
main\test.cpp

Code: Select all

/* main program */
#include <stdio.h>
#include "my_component.h"

extern "C" void app_main(void) {
    say_hello();
    printf("app_main\n");
}
main\CMakeLists.txt

Code: Select all

idf_component_register(SRCS ${srcs} "test.cpp"
                        INCLUDE_DIRS ${include_dirs} "."
                        REQUIRES my_component)
components\my_component\my_component.c

Code: Select all

#include <stdio.h>
#include "my_component.h"

void say_hello(void) {
    printf("Hello CPP\n");
}
components\my_component\my_component.h

Code: Select all

void say_hello(void);
components\my_component\CMakeLists.txt

Code: Select all

idf_component_register(SRCS "my_component.c" INCLUDE_DIRS ".")
link to all project files:
20220429_blink.zip
(20.96 KiB) Downloaded 307 times

ESP_Sprite
Posts: 9759
Joined: Thu Nov 26, 2015 4:08 am

Re: CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

Postby ESP_Sprite » Tue May 03, 2022 1:29 am

You need to add 'extern "C"' guards to all C headers you include from a C++ file. Your my_component.h doesn.t have that. This works:

Code: Select all

#ifdef __cplusplus
extern "C" {
#endif

void say_hello(void);

#ifdef __cplusplus
}
#endif

machiel
Posts: 4
Joined: Wed Oct 09, 2019 1:29 pm

Re: CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

Postby machiel » Tue May 03, 2022 9:54 am

Thanks, this absolutely works, now this example project builds perfectly. Hopefully your answer will also help other people with the same issue, to prevent them from spending many hours just like me :D

In this case I write my own tiny component, but in practice I will use external (mostly published on github) C components. Does this mean that I need to change this 'external' code to make it CPP compatible, or are there other ways?

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

Postby ESP_igrr » Tue May 03, 2022 11:27 pm

You can also wrap include statements if a third party library header doesn't have C++ guards:

Code: Select all

extern "C" {
#include "external_lib.h"
}

glrtheil
Posts: 61
Joined: Tue Dec 07, 2021 2:48 pm

Re: CMake build issue ‘undefined reference’ – Linker CPP main failed to link C component

Postby glrtheil » Wed May 04, 2022 8:06 pm

I'm so thankful this happens to be discussed today. This is actually the solution to a problem I've been facing since yesterday, and I was here taking a break to try and answer some questions if I could, then was going to get back to working on the problem.

I'm implementing the Azure middleware SDK into a project that is mostly C++, but all the middleware stuff is C, including their ESP32 sample. There's a single component that I kept getting this exact linker error for functions in a component (sample-azure-iot, which contains several connection algorithms including TLS socket configuration). Including the header files in an extern "C" was the solution. Very convenient.

Code: Select all

extern "C"
{ 
    /* Exponential backoff retry include. */
    #include "backoff_algorithm.h"

    /* Transport interface implementation include header for TLS. */
    #include "transport_tls_socket.h"

    /* Crypto helper header. */
    #include "crypto.h"
}

Who is online

Users browsing this forum: No registered users and 119 guests