Visual Studio 2019 compile errors

Hi,

I’m trying to use the Visual Studio SDL LVGL Simulator project with the lvgl master from Github.

I get the following error for lv_color.h:482

“Error C4576 a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax”

The Problem is with the following define:
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(b8 >> 3) & 0x1FU, (g8 >> 2) & 0x3FU, (r8 >> 3) & 0x1FU}})

Is this a bug in LVGL or can I fix this somehow?

I just checked the simulator in Visual Studio, with the master branch (for main and subrepos), and it’s running normally.

Maybe check that you have updated (and checked out) the master branch in all submodules of the project?

Looks like it might an issue with Visual Studio’s C++ support. This feature appears to be unsupported in C++: https://stackoverflow.com/a/33271165

It works with GCC C++ compiler. It only throws this error when I’m compiling with VisualStudio. (We are using LVGL functions from C++).

Our G++ Version: gcc version 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437] (GNU Tools for ARM Embedded Processors 6-2017-q2-update).

The Error is only with LV_COLOR_MAKE. Maybe if we wrap it in a function so we don’t have it in the header?

I don’t think that will help, because it appears that Visual Studio doesn’t support this syntax at all in C++ mode. We might need to fix that. @kisvegabor?

Is there a way to initialize a struct in a C header file?

E.g. is it working?

#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){.ch.blue = (b8 >> 3) & 0x1FU, .ch.green = (g8 >> 2) & 0x3FU, .ch.red = (r8 >> 3) & 0x1FU})

@kisvegabor

Thank you for your reply.

Your suggestion does not work with VisualStudio C++ compiler. I’m going to switch to mingw or cygwin gcc/c++ compiler.

If you would like to keep using Visual Studio, I would suggest compiling these files as C files (and not C++ files). The rest of your program can still be C++; you just need to configure the IDE so that it does not treat LittlevGL as a C++ program.

We had previously discussed officially deprecating this mode of compilation (see these comments), because it relies on the assumption that C and C++ are the same language (and they are not). It also adds complexity to our testing as we have to test the code on both a C and C++ compiler.

@kisvegabor I just thought of something. Can the Arduino IDE compile LittlevGL as C source code or does it force C++?

@embeddedt

If you include the header lv_color.h in a CPP file then those Macros get compiled with the C++ compiler. Using LVGL with GCC/G++ works 100% but not with the Microsoft C++ compiler. The only issue is with VC++. If you configure The VisualStudio project to use GCC/G++ (MSYS2, Mingw, Cygwin etc) then you can use lv_color.h in C++ code.

Perhaps we should just condition the LV_COLOR_MAKE macro on the code being C and not C++, since it relies on behavior that is only standard in C99 (not C++).

Or we can just remove LV_COLOR_MAKE and use lv_color_make (function) instead. It would prevent to initialize global color variables, but I’m bot sure it’s an issue.

Yep. Just started using lvgl and ran into this issue. Can be fixed with:

#define LV_COLOR_MAKE(r8, g8, b8) lv_color_t({{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/
1 Like

This looks like a good solution for C++, except that it’s relying on the order of the members. It would be great if members could be assigned by name to help prevent bugs in the future.

As mentioned this is only good for C++.
I ran into this when wanting to create a VS 2017 project from scratch rather than use the lv_sim_visual_studio_sdl repo (in order to understand the moving parts). For anyone doing the same some points to note:

  • Use a console project template
  • Check your target is correct x64 vs x32 and link to the correct version of SDL
  • Change the file with main() in it to be .c. The default is .cpp and this is what caused the issue for me.
1 Like

I just did the same in my code with version 6, but now I have the same problem with version 7.0 into another function.
I think a good solution would be moving every function (or macro) using such problematic form of initializers to .c files.

This is how I could solve the problem in lv_color.h with version 6:

#define LV_COLOR_WHITE lv_color_make(0xFF, 0xFF, 0xFF)
#define LV_COLOR_SILVER lv_color_make(0xC0, 0xC0, 0xC0)
#define LV_COLOR_GRAY lv_color_make(0x80, 0x80, 0x80)
#define LV_COLOR_BLACK lv_color_make(0x00, 0x00, 0x00)
#define LV_COLOR_RED lv_color_make(0xFF, 0x00, 0x00)
#define LV_COLOR_MAROON lv_color_make(0x80, 0x00, 0x00)
#define LV_COLOR_YELLOW lv_color_make(0xFF, 0xFF, 0x00)
#define LV_COLOR_OLIVE lv_color_make(0x80, 0x80, 0x00)
#define LV_COLOR_LIME lv_color_make(0x00, 0xFF, 0x00)
#define LV_COLOR_GREEN lv_color_make(0x00, 0x80, 0x00)
#define LV_COLOR_CYAN lv_color_make(0x00, 0xFF, 0xFF)
#define LV_COLOR_AQUA LV_COLOR_CYAN
#define LV_COLOR_TEAL lv_color_make(0x00, 0x80, 0x80)
#define LV_COLOR_BLUE lv_color_make(0x00, 0x00, 0xFF)
#define LV_COLOR_NAVY lv_color_make(0x00, 0x00, 0x80)
#define LV_COLOR_MAGENTA lv_color_make(0xFF, 0x00, 0xFF)
#define LV_COLOR_PURPLE lv_color_make(0x80, 0x00, 0x80)
#define LV_COLOR_ORANGE lv_color_make(0xFF, 0xA5, 0x00)

#if (0)
/* Fix by rnnslv: Commented out because of error C4576*/
/* The most simple macro to create a color from R,G and B values */
#if LV_COLOR_DEPTH == 1
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){.full = (uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))})
#elif LV_COLOR_DEPTH == 8
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}})
#elif LV_COLOR_DEPTH == 16
#if LV_COLOR_16_SWAP == 0
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x3FU), (uint16_t)((r8 >> 3) & 0x1FU)}})
#else
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((g8 >> 5) & 0x7U), (uint16_t)((r8 >> 3) & 0x1FU), (uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x7U)}})
#endif
#elif LV_COLOR_DEPTH == 32
#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /Fix 0xff alpha/
#endif
#endif

static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
{
// return LV_COLOR_MAKE(r, g, b);
lv_color_t out;
#if LV_COLOR_DEPTH == 1
out.full = (b >> 7 | g >> 7 | r >> 7);
#elif LV_COLOR_DEPTH == 8
out.ch.blue = b >> 6;
out.ch.green = g >> 5;
out.ch.red = r >> 5;
#elif LV_COLOR_DEPTH == 16
#if LV_COLOR_16_SWAP == 0
out.ch.blue = b >> 3;
out.ch.green = g >> 2;
out.ch.red = r >> 3;
#else
out.ch.green_h = g >> 5;
out.ch.red = r >> 3;
out.ch.blue = b >> 3;
out.ch.green_l = (g >> 2) & 0x7;
#endif
#elif LV_COLOR_DEPTH == 32
out.ch.blue = b;
out.ch.green = g;
out.ch.red = r;
out.ch.alpha = 0xff; /Fix 0xff alpha/
#endif
return out;
}

But with version 7, I’m getting a new problem of the same kind inside the function “lv_color_mix_with_alpha”.

Any suggestion on how could I initialize the following vars in a legal and working way for all allowed color depths?

    static lv_color_t fg_color_save = {.full = 0};
    static lv_color_t bg_color_save = {.full = 0};
    static lv_color_t res_color_saved = {.full = 0};

Anyway I’d be glad if this issue was solved on the master version.

.full is presnet for all color depth so it should work with all LV_COLOR_DEPTH settings.

Yes, but that’s just what is causing compile error.

I tried the following form with 32 bit color depth and it seems to reset all members of the struct:

    static lv_color_t fg_color_save = { 0 };
    static lv_color_t bg_color_save = { 0 };
    static lv_color_t res_color_saved = { 0 };

My test was:

    lv_color_t test;
    test.full = 0xffffffff; // set all members dirty
    test = { 0 };            // clear all members

This is my version of lv_color.h compiling with Visual Studio in a C++ program:
Search for “Fix by rnnslv” to find all patches:

lv_color.h (22.5 KB)

I see. We added the .full = 0 because {0} caused warnings.

An ugly solution would be to move this variables out of the function and let the compiler to initialize them to zero.

Yeah that solution could be dangerous, because var initialization is not guaranteed by all compilers (mostly when building release version).

I think the best one, is moving all critical points (inline functions) to .c files, as you said before and then add a /Tc option for those files or, even better, building lvgl as a separate c library.