cancel
Showing results for 
Search instead for 
Did you mean: 

How to configure STM32CubeIDE to support C++ development?

TLeaf
Associate II

1. How to configure the IDE to use g++ compiler to compile all the files includes "*.c" files in the project?

Current it compiles the .c files by using gcc and .cpp by using g++ ...

2. If I rename main.c to main.cpp, the cube code generator will create a new main.c file instead of using main.cpp. Any sulotions for this?

Becasue main.c is .c file, so the IDE use gcc to compile this file, and this caused that I can't use any objects in it. But if I changed the main.c to main.cpp, the cube can't generate code into it...:face_screaming_in_fear:

45 REPLIES 45

You might find the example I just gave to be more comprehensive, I'd hope so. Feel free to ask questions, of course.

The more complex the program, the (somewhat) trickier the answer is to your question.

Main.c calls CPP_LINK, which then calls APPLICATION_init, which sets up and starts the application task. The application task needs to find stuff. If main.c never calls it, then main.c doesn't need to know where it is. The global variables are in the application part that's called by CPP_LINK.

I had almost gone on to a more complex explanation, but it's dependent on the rest of the structure of your program.

The program I have is rather complex, lots of tasks, and is graphics touch-screen driven, which is generally not the average example program. It might be doing things you don't need to do when you're working with the HAL example programs.

I could give you an example with I2C (which I use a lot), but it may not fit your needs. Do feel free to ask.

Thanks. Its clear now. However, I got this dumb newbie question, since I have trouble handle it. How do you create global variables without editing main.c?

I'm going to assume that you have main.c, which then calls another function in a CPP program, lets call it a(), in a file app.cpp, and you have another file called other.cpp with routines in it.

First: any routine in other.cpp has a corresponding definition in other.hpp, so you get to the routines like that.

Second: any variable in other.cpp that isn't in a function, ex: int mine; can be declared external in app.cpp, and declared outside any function: example: extern int mine; It can be accessed from app.cpp. You do this with classes, too, so if you have a class MYCLASS declared in other.hpp, you can have an instance of it in other.cpp example: MYCLASS myclass; and that can be accessed in app.cpp by doing: #include "other.hpp" and on the next line: extern MYCLASS myclass;

Establish a naming convention for yourself so that you can tell the difference between the class declaration and an instance of the class. Since C++ is case sensitive, one way is to have the class declaration in caps, and the instance in lower case. There's lots of different opinions on this, pick whatever you'd like.

A second way would be to establish another file: globals.hpp, put globals in that, and then include that in your files. I do this with structure definitions that have to be in many different files (example: graphics objects to be drawn need the basic definitions for graphics for each) Again, there are many different program structures and ideas about what you put where, whether or not you should ever have a global variable, and so on.

TMaia.1
Associate II

I did run some tests and it works. I replaced the init function with an application class.

Application app;
app.init();
//APPLICATION_init();

But still, I have many doubts.

1- I was sure that I was about to get compilation error only calling

cpp_link();

as you mentioned. However, I only got a warning which is gone after inserting

#include "CPP_LINK.hpp"

How does the compiler found cpp_link function without the header?

2- I also need to add

#include "main.h"

inside Application.cpp. Otherwise, It can't find HAL functions.

3- The global variables still are my concern. Ex: main.c has

UART_HandleTypeDef huart2;

created by Configuration Tool. I can't use it inside application. Any suggestion?

The reason for the app_init was that the application wasn't a class, I didn't need one. I generally prefer to have a class when I'm thinking possible derivatives of that class or need inheritance. Didn't see a need for that in the main application. So that's nothing major.

As far as CPP_LINK.hpp is concerned, compilers hate surprises. In any file, when you come across any reference to anything, it either has to be a part of the language or it's already been defined. It's traditional to put those definitions in the .h or .hpp files. If you have a function completely declared in a file, and only use it afterwards, then you don't need it in the .hpp/.h file. If that same function is ever called from outside the file, then you have to have the definition available to the file in which it is called. Most people include the .h or the .hpp file. CPP_LINK.hpp was a separate file. CPP_LINK.cpp was a separate file. They never changed and never needed to change as long as your application had the same name.

I didn't give you the whole application file. Not only is it too big, but you have pretty much the parts you need to see how the C and C++ parts go.

Inside your application.cpp file, you declare the following:

// this is for another board, you'll need to put your own board definitions in here. Look to main.c for the proper includes

  #include "stm32f7xx.h"             // 144 pin processor, NUCLEO-144 board, $23.00
 
  #include "stm32f7xx_hal.h"         // HAL drivers
 
 

// then add:

extern  UART_HandleTypeDef  huart2;
 

You've already put in main.h which copies pin definitions from the CubeMX program.

You shouldn't need much more.

You can always go to the main.c program, look to see what's included, then see where it's defined. That may help a bit.

But with the right files (check the contents of the equivalent files

LOliv.2
Associate II

I may understand the workaround proposed, but I am still not sure if implementing it.

I am currently exploring the STM32 universe to see if it can suit our needs and the fact that C++ is not natively supported seems very strange. To be honest, I don't understand where is the problem, it's in CubeMX that doesn't check if the user renamed main.c into main.cpp?

Or the problem is deeper into the project structure?

I'm asking because we will need to integrate C++ code in our projects and I am not comfortable to push the company on a new ecosystem that doesn't support C++. For this reason I'm asking, trying to understand if it's something that is a matter of a point release to fix or it's a deliberate choice by ST

Thanks, any opinion is appreciated

My experiences are with CubeMX, then CubeMX with FreeRTOS added, then CubeMX with C++ and with FreeRTOS.

While FreeRTOS is not C++, and may never be, CubeMX may eventually be, but since I do not and cannot speak for ST, I can't say anything about that.

Remember that while a C++ program can call C programs directly, the reverse is not true without help. There are others who have put C++ wrappers around C programming, but the particular approach I used requires that to be done once. Since CubeMX does not see or respect a main.cpp file (would be easy enough to do), you need a workaround. Renaming the main.c to main.cpp is bothersome, and easy to forget to do, since you must rename main.cpp back to main.c if you want CubeMX to deal nicely with it. (solution had been suggested)

What I have is not an ideal structure, but it does work. There are limits to how the code interacts. For instance, callback routines from .c programs are not happy with trying to access .cpp routines, so there's a limit to what you can do with callbacks. Fortunately, if you use FreeRTOS, the FreeRTOS functions are in C, can be called, and you can use a semaphore as a signal flag when needed (or equivalent). If you're writing a single byte/word/uint32_t variable, something the processor does in one write cycle, then you need not worry. Pointers are likely ok by the same reasoning.

You can (and I do and have) generate C++ programs that will work within the CubeMX ecosystem. They may contain some workaround, especially with some class instances, but they do work. The code will not likely satisfy a C++ purist, though.

I've no experience with any other microcontroller operating system other than FreeRTOS, other than one I wrote for the AVR 8 bit series. That was in C++, so with no CubeMX, everything was in C++.

From what I understand, FreeRTOS does things in a way that C++ would break, if used. ST has C++ compatibility wrappers for all the functions, but there are still problems, as I mentioned. Will they ever go to C++? no idea.

The code I have is considerably more complex than the average example program, so yes, you can do it. Gracefully? for certain values of grace....

RFlec.1
Associate II

I'm a bit surprised, since this toppic seems to be so old and CubeMX still does not respect your CubeIDE Project settings. I'm currently struggling with exactly the same problem. I created a C++ Project with CubeIDE and for me the only reason to use Eclipse is the ST Integration of all those tools that make STM32 Development so much easier. But CubeMX stoically insists on creating a c-File and this is obviously not compiled by a C++ Compiler since I get the error that it doesn't know the class keyword. Is it really so hard to implement this properly? Is there any setting to just compile everything with the C++ Compiler regardless of the file extension? All those solutions where you try to call C++ from C and renaming the main.c file to cpp are nothing more than ugly hacks.

Pavel A.
Evangelist III

Supporting code generation in C++ will double and triple amount of testing with various C++ compilers and emerging new flavors of C++.

While ST still suffers with plain C.

Again - not all C code can be safely compiled in C++ mode.

No, there's no need to rename main.c. No, calling C++ from C isn't ugly hack. It's opinion against an opposite opinion.

>  Is there any setting to just compile everything with the C++ Compiler regardless of the file extension?

Yes there is. Use on your own risk.

We need CLM movement here - "C programmers' lives matter".

-- pa

If you know about the config option to always use the c++ compiler, would you please be so kind as to explain where?