C library linkage fail in C++

User avatar
urbanze
Posts: 301
Joined: Sat Jun 10, 2017 9:55 pm
Location: Brazil

C library linkage fail in C++

Postby urbanze » Mon Nov 18, 2019 4:52 pm

I trying to use "tinyexpr" library (C) in my main.cpp file but even with 'extern "C" {}', link can't completed. However, when I change my file to main.c, link can be completed. https://github.com/codeplea/tinyexpr

1. Here, is my real ambient (main.cpp file), trying to include tinyexpr C library. Yes, I need to declare app_main() as extern to compile .cpp. I believe the problem is here, but I can't remove extern "C" of app_main() .I've done dozens of tests, removing extern, including .c and so on...

Code: Select all

extern "C"
{
    #include "tinyexpr/tinyexpr.h"
}

extern "C" void app_main()
{
    printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

2. Here, is my test ambient (main.c file) and work nicelly. I made this test only to know if library work.

Code: Select all

#include "tinyexpr/tinyexpr.h"
#include "tinyexpr/tinyexpr.c"

void app_main()
{
    printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

Output error when main.cpp:

Code: Select all

/build/main/libmain.a(main.o):(.literal.app_main+0x10): undefined reference to `te_interp'
/build/main/libmain.a(main.o): In function `app_main':
/main/main.cpp:9878: undefined reference to `te_interp'
collect2: error: ld returned 1 exit status
make: *** [/esp-idf/make/project.mk:517: /build/esp32.elf] Error 1

nvannote
Posts: 51
Joined: Thu Nov 14, 2019 10:42 pm

Re: C library linkage fail in C++

Postby nvannote » Tue Nov 19, 2019 5:52 pm

While I did not flash a device to do a test run (I am sure it will work fine); This works perfectly fine for me (both as C and as C++).

Code: Select all

#include <stdio.h>
#include <tinyexpr.h>


#ifdef __cplusplus
extern "C"
#endif
void app_main() {
  printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}
I suspect what is happening in your case is that the tinyexpr.h is declaring the tinyexpr functions linkage as extern “C” during a C++ compile (which it will) and then you included the C source file into your C++ source, which will just result in the C source being compiled as C++. Hence the linker cannot resolve the extern “C” tinyexpr functions.

I would just allow tinyexpr.c be compiled as C standalone and all should be good.

What I did in my test harness was create a project local “components” directory and threw a symbolic link pointing to the tinyexpr directory (elsewhere where I keep third-party "stuff") along with an appropriately wired component.mk file.

My apologies if any of that wasn’t clear.

Regards,

Neil

User avatar
urbanze
Posts: 301
Joined: Sat Jun 10, 2017 9:55 pm
Location: Brazil

Re: C library linkage fail in C++

Postby urbanze » Wed Nov 20, 2019 11:27 am

nvannote wrote:
Tue Nov 19, 2019 5:52 pm
While I did not flash a device to do a test run (I am sure it will work fine); This works perfectly fine for me (both as C and as C++).

Code: Select all

#include <stdio.h>
#include <tinyexpr.h>


#ifdef __cplusplus
extern "C"
#endif
void app_main() {
  printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}
I suspect what is happening in your case is that the tinyexpr.h is declaring the tinyexpr functions linkage as extern “C” during a C++ compile (which it will) and then you included the C source file into your C++ source, which will just result in the C source being compiled as C++. Hence the linker cannot resolve the extern “C” tinyexpr functions.

I would just allow tinyexpr.c be compiled as C standalone and all should be good.

What I did in my test harness was create a project local “components” directory and threw a symbolic link pointing to the tinyexpr directory (elsewhere where I keep third-party "stuff") along with an appropriately wired component.mk file.

My apologies if any of that wasn’t clear.

Regards,

Neil
Yes, tinyexpr.h use extern "C". I made some tests and none worked, see all:

1. NO

Code: Select all

#include "tinyexpr/tinyexpr.h"

#ifdef __cplusplus
extern "C" {
#endif

void app_main()
{
	printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

#ifdef __cplusplus
}
#endif
2. NO

Code: Select all

extern "C"
{
	#include "tinyexpr/tinyexpr.h"
}

#ifdef __cplusplus
extern "C" {
#endif

void app_main()
{
	printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

#ifdef __cplusplus
}
#endif
Now, I removed extern "C" in tinyexpr.h library:

Code: Select all

#ifdef __cplusplus
extern "C" {
#endif
......
#ifdef __cplusplus
}
#endif

3. Same then test 1, NO.

4. Same then test 2, NO.

What hell I need to do, I tryed all of my tips? :LOL:

PS: My main file is .cpp

PeterR
Posts: 621
Joined: Mon Jun 04, 2018 2:47 pm

Re: C library linkage fail in C++

Postby PeterR » Wed Nov 20, 2019 7:45 pm

You cannot remove:

Code: Select all

extern "C" void app_main()
The ESP32 wants to call you and so your app_main() must be declared as "C" call style.
You can still stuff your app_main() full of vectors, maps etc but you must do as above (don't use { with app_main()).
& I also believe that IDF CAN should be fixed.

nvannote
Posts: 51
Joined: Thu Nov 14, 2019 10:42 pm

Re: C library linkage fail in C++

Postby nvannote » Wed Nov 20, 2019 8:00 pm

urbanze wrote:
Wed Nov 20, 2019 11:27 am
nvannote wrote:
Tue Nov 19, 2019 5:52 pm
While I did not flash a device to do a test run (I am sure it will work fine); This works perfectly fine for me (both as C and as C++).

Code: Select all

#include <stdio.h>
#include <tinyexpr.h>


#ifdef __cplusplus
extern "C"
#endif
void app_main() {
  printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}
I suspect what is happening in your case is that the tinyexpr.h is declaring the tinyexpr functions linkage as extern “C” during a C++ compile (which it will) and then you included the C source file into your C++ source, which will just result in the C source being compiled as C++. Hence the linker cannot resolve the extern “C” tinyexpr functions.

I would just allow tinyexpr.c be compiled as C standalone and all should be good.

What I did in my test harness was create a project local “components” directory and threw a symbolic link pointing to the tinyexpr directory (elsewhere where I keep third-party "stuff") along with an appropriately wired component.mk file.

My apologies if any of that wasn’t clear.

Regards,

Neil
Yes, tinyexpr.h use extern "C". I made some tests and none worked, see all:

1. NO

Code: Select all

#include "tinyexpr/tinyexpr.h"

#ifdef __cplusplus
extern "C" {
#endif

void app_main()
{
	printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

#ifdef __cplusplus
}
#endif
2. NO

Code: Select all

extern "C"
{
	#include "tinyexpr/tinyexpr.h"
}

#ifdef __cplusplus
extern "C" {
#endif

void app_main()
{
	printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
}

#ifdef __cplusplus
}
#endif
Now, I removed extern "C" in tinyexpr.h library:

Code: Select all

#ifdef __cplusplus
extern "C" {
#endif
......
#ifdef __cplusplus
}
#endif

3. Same then test 1, NO.

4. Same then test 2, NO.

What hell I need to do, I tryed all of my tips? :LOL:

PS: My main file is .cpp

Hard to say, it could be any number of things.

Perhaps you compiled tinyexpr.c as a C++ source at one point and its object file is still floating around in your build directory; or perhaps tinyexpr.c is not getting built and included in the link at all?

I really don’t know how you have your project setup, what esp-idf and toolchain you’re using, or how you’re kicking off the build (make/cmake/manually). But I do know if you follow my reply above, it will work as C or C++, no problem.

I would start by getting a clean copy of tinyexpr as it doesn’t need modification (as far as I can tell), clear your build directory and start clean.

Regards,

Neil

User avatar
urbanze
Posts: 301
Joined: Sat Jun 10, 2017 9:55 pm
Location: Brazil

Re: C library linkage fail in C++

Postby urbanze » Wed Nov 20, 2019 11:33 pm

PeterR wrote:
Wed Nov 20, 2019 7:45 pm
You cannot remove:

Code: Select all

extern "C" void app_main()
The ESP32 wants to call you and so your app_main() must be declared as "C" call style.
You can still stuff your app_main() full of vectors, maps etc but you must do as above (don't use { with app_main()).
Well, I drag the exact same code, no work (same error)

Image of code and terminal output (https://drive.google.com/file/d/1nGyyAd ... sp=sharing).
Ps: Ignore compiler/ulp versions warnings from my raspberry, it always worked to all codes.

Error (always the same):

Code: Select all

In function `app_main':
undefined reference to `te_interp'

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: C library linkage fail in C++

Postby ESP_Angus » Thu Nov 21, 2019 1:19 am

It looks like maybe your main component.mk doesn't add the "tinyexpr" subdirectory to COMPONENT_SRCDIRS?

This means the tinyexpr.c file is never compiled as part of the build. The hack where you #include "tinyexpr/tinyexpr.c" main.c works, because now the files are compiled as part of main.c.

Check your project's main/component.mk has some line like this:

Code: Select all

COMPONENT_SRCDIRS := . tinyexpr

User avatar
urbanze
Posts: 301
Joined: Sat Jun 10, 2017 9:55 pm
Location: Brazil

Re: C library linkage fail in C++

Postby urbanze » Thu Nov 21, 2019 7:44 pm

ESP_Angus wrote:
Thu Nov 21, 2019 1:19 am
It looks like maybe your main component.mk doesn't add the "tinyexpr" subdirectory to COMPONENT_SRCDIRS?

This means the tinyexpr.c file is never compiled as part of the build. The hack where you #include "tinyexpr/tinyexpr.c" main.c works, because now the files are compiled as part of main.c.

Check your project's main/component.mk has some line like this:

Code: Select all

COMPONENT_SRCDIRS := . tinyexpr
Well, this worked! I just need to drag source files of library in the same folder of main.cpp and add "COMPONENT_SRCDIRS := . tinyexpr" to .mk

Thanks guys! I really needed this library to be included in our product.

Who is online

Users browsing this forum: No registered users and 109 guests