How to be compatible with C++ on the STM32 platform?

Description

All use C, and the storage occupied by global variables used by the business is too large,So I want to take CPP to complete it.

When C99 is checked, many errors are prompted when compiling the cpp file. After canceling C99, compiling lv_color.h file prompts many errors.

How to be compatible with C++ on the STM32 platform?

What MCU/Processor/Board and compiler are you using?

STM32F429,ARM Compiler V5

What LVGL version are you using?

V7.3.0

What do you want to achieve?

Using arm compiler V5, I can compile littlevgl and C++.

What have you tried so far?

Code to reproduce

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

Compile LVGL as C code and the rest of your code as C++. We don’t support compiling LVGL files as C++, but including its headers in a C++ file should work without problems.

Please make sure you are using the latest version of LVGL from release/v7 or master - there have been fixes for C++ builds in the recent past.

I just tried it with lvgl V7.5.0, in the CPP file #include “lvgl.h”, some errors will be reported

The lvgl.h in lvgl-master folder.

image

In this CPP file, I only used the method in lv_mem.h

Change to include “src/lv_misc/lv_mem.h” and there is no problem.

But in the place where the widget is displayed, I cannot avoid this problem

Looking like you use an old version of c++ standard, try to change ARM Compiler version to 6 on page “Target” and language for C++ on page “C/C++ (AC)” to c++11 or newer

Also, I’ll make my macro _LV_COLOR_MAKE_TYPE_HELPER more compatible with Keil c++98 compiler. But to fix other errors you need change ARM Compiler version from 5 to 6

Thanks~

In order to be compatible with C++98, I also modified LV_COLOR_MAKE.The code I modified is not very good

Upgrade to v6, some compilation instructions also need to be changed…And I am also worried that the file compiled by v6 is larger than V5.

By the way, how do you set the event callback function elegantly in CPP?

Like this?

class CWnd
{
public:
static void CWnd_defEventCB(lv_obj_t * obj, lv_event_t e);
};

You can check my pull request https://github.com/lvgl/lvgl/pull/1788
There fixed compilation with ARM Compiler version 6.

About callbacks, for example usage of lv_task_create:
C++ 98 way:

class SomeClass
{
public:
  void someFunction()
  {
    lv_task_create(&SomeClass::taskCallback, 500, LV_TASK_PRIO_MID, this);
  }

private:
  void makeSomething()
  {
    printf("something");
  }

  static void taskCallback(lv_task_t* task)
  {
    SomeClass* self = reinterpret_cast<SomeClass*>(task->user_data);
    self->makeSomething();
  }
};

C++11 way using lambda:

class SomeClassCpp11
{
public:
  void someFunction()
  {
    lv_task_create([](auto task)
    {
      auto self = reinterpret_cast<SomeClassCpp11*>(task->user_data);
      self->makeSomething();
    }, 500, LV_TASK_PRIO_MID, this);
  }

private:
  void makeSomething()
  {
    printf("something");
  }
};

Thanks for your reply.Got it!
1.Class’s static member function~
2.pass “this” to “user data” when creating the task…

But the event call back of the control(eg:button) is a bit different.

Event callback for the control is similar:

class ButtonWrapper
{
public:
  ButtonWrapper()
  {
    button_ = lv_btn_create(lv_scr_act(), NULL);
    lv_obj_set_event_cb(button_, &ButtonWrapper::buttonCallback);
    lv_obj_set_user_data(button_, this);
  }

  ~ButtonWrapper()
  {
    lv_obj_del(button_);
  }
  

private:
  void eventHandler(lv_event_t event)
  {
    switch(event)
    {
      case LV_EVENT_PRESSED:
      printf("ButtonWrapper pressed\n");
      break;
    }
  }

  static void buttonCallback(lv_obj_t* obj, lv_event_t event)
  {
    ButtonWrapper* self = reinterpret_cast<ButtonWrapper*>(lv_obj_get_user_data(obj));
    self->eventHandler(event);
  }

private:
  lv_obj_t* button_;
};
1 Like

Thanks again
:+1:

Hi! I am using LVGL version 8.3.1 and after my “adapting” the code, I get an error:

argument of type "void(*)(lv_obj_t *obj, lv_event_t *event)" incompatible with the "lv_event_cb_t" type parameter
class ButtonWrapper
{
public:
	ButtonWrapper()
	{
		button_ = lv_btn_create(lv_scr_act());
		lv_obj_add_event_cb(button_, &ButtonWrapper::buttonCallback, LV_EVENT_VALUE_CHANGED, NULL); // <----------- The error is here
		lv_obj_set_user_data(button_, this);
	}

	~ButtonWrapper()
	{
		lv_obj_del(button_);
	}

private:
	void eventHandler(lv_event_t *e)
	{
		lv_event_code_t code = lv_event_get_code(e);
		switch (code)
		{
		case LV_EVENT_PRESSED:
			printf("ButtonWrapper pressed\n");
			break;
		}
	}

	static void buttonCallback(lv_obj_t *obj, lv_event_t *event)
	{
		ButtonWrapper *self = reinterpret_cast<ButtonWrapper *>(lv_obj_get_user_data(obj));
		self->eventHandler(event);
	}

private:
	lv_obj_t *button_;
};

Please help to adapt the code.

1st:

class ButtonWrapper
{
public:
    ButtonWrapper()
    {
        button_ = lv_btn_create(lv_scr_act());
        lv_obj_add_event_cb(button_, &ButtonWrapper::buttonCallback, LV_EVENT_VALUE_CHANGED, NULL);
        lv_obj_set_user_data(button_, this);
    }

    ~ButtonWrapper()
    {
        lv_obj_del(button_);
    }

private:
    void eventHandler(lv_event_t* e)
    {
        lv_event_code_t code = lv_event_get_code(e);
        switch (code)
        {
        case LV_EVENT_PRESSED:
            printf("ButtonWrapper pressed\n");
            break;
        }
    }

    static void buttonCallback(lv_event_t* e)
    {
        lv_obj_t* obj = lv_event_get_target(e);
        ButtonWrapper* self = reinterpret_cast<ButtonWrapper*>(lv_obj_get_user_data(obj));
        self->eventHandler(e);
    }

private:
    lv_obj_t* button_;
};

2nd:

class ButtonWrapper
{
public:
    ButtonWrapper()
    {
        button_ = lv_btn_create(lv_scr_act());
        lv_obj_add_event_cb(button_, &ButtonWrapper::buttonCallback, LV_EVENT_VALUE_CHANGED, this);
    }

    ~ButtonWrapper()
    {
        lv_obj_del(button_);
    }

private:
    static void eventHandler(lv_event_t* e)
    {
        lv_event_code_t code = lv_event_get_code(e);
        switch (code)
        {
        case LV_EVENT_PRESSED:
            printf("ButtonWrapper pressed\n");
            break;
        }
    }

    static void buttonCallback(lv_event_t* e)
    {
        ButtonWrapper* self = reinterpret_cast<ButtonWrapper*>(lv_event_get_user_data(e));
        self->eventHandler(e);
    }

private:
    lv_obj_t* button_;
};