PMunch / futhark

Automatic wrapping of C headers in Nim
MIT License
393 stars 21 forks source link

How to deal with C source libraries with `static inline` header functions? #77

Open arkanoid87 opened 1 year ago

arkanoid87 commented 1 year ago

I was trying to wrap LVGL and implement original hello_world.c in Nim.

#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LABEL

/**
 * Basic example to create a "Hello world" label
 */
void lv_example_get_started_1(void)
{
    /*Change the active screen's background color*/
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x003a57), LV_PART_MAIN);

    /*Create a white label, set its text and align it to the center*/
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello world");
    lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}

#endif

This library is intended to be compiled with the project source, and has many static inline functions in header files, for example lv_color_hex

inlined functions are skipped by futhark and never wrapped, and it makes generally sense when linking, but what should I do when the project importing the library is meant to call static inline header functions?

I tried, just for quick test, commenting out if node["inlined"].getBool: return Compiling this file:

import futhark

importc:
  path "../lvgl"
  path "../lvgl/src/misc"
  path "../lvgl/src/core"
  "lvgl.h"
  "lv_color.h"
  "lv_obj_style_gen.h"

Resulted in clang complaining many redefinitions

Error: Opir exited with non-zero exit code 255.
Opir output: 
Warning: Possible failure to include lv_conf.h, please read the comment in this file if you get errors
Error: redefinition of 'lv_obj_get_style_width'
Error: redefinition of 'lv_obj_get_style_min_width'
Error: redefinition of 'lv_obj_get_style_max_width'
Error: redefinition of 'lv_obj_get_style_height'
Error: redefinition of 'lv_obj_get_style_min_height'
Error: redefinition of 'lv_obj_get_style_max_height'
Error: redefinition of 'lv_obj_get_style_x'
Error: redefinition of 'lv_obj_get_style_y'
Error: redefinition of 'lv_obj_get_style_align'
Error: redefinition of 'lv_obj_get_style_transform_width'
Error: redefinition of 'lv_obj_get_style_transform_height'
Error: redefinition of 'lv_obj_get_style_translate_x'
Error: redefinition of 'lv_obj_get_style_translate_y'
Error: redefinition of 'lv_obj_get_style_transform_zoom'
Error: redefinition of 'lv_obj_get_style_transform_angle'
Error: redefinition of 'lv_obj_get_style_transform_pivot_x'
Error: redefinition of 'lv_obj_get_style_transform_pivot_y'
Error: redefinition of 'lv_obj_get_style_pad_top'
Error: redefinition of 'lv_obj_get_style_pad_bottom'
Fatal: too many errors emitted, stopping now

Is there a designed way to apply Futhark in this context?

PMunch commented 1 year ago

The reason inlined weren't generated to begin with is because it makes no sense when dynamically linking. I don't quite remember if this was a matter of actually finding these in a header meant for dynamic linking, or if this was just me being cautious. But for compiling together with the sources it doesn't make sense to omit them.

I've pushed a new version 0.9.3 which adds the -d:generateInline flag. Along with this code:

import futhark

importc:
  path "../lvgl"
  "lvgl.h"

lvObjSetStyleBgColor(lvScrAct(), lvColorHex(0x003a57), LV_PART_MAIN.lvStyleSelectorT)

it now fails on the C building step (because I didn't tell it how to actually link with lvgl). If you get something set up with LVGL I would love to see the results :)

arkanoid87 commented 1 year ago

Thank you for addressing this

I can confirm that using -d:generateInline I end up with linking errors, but the errors are about linker not finding inlined functions in header, for example:

@mtest_lvgl.nim.c:(.text+0xee): undefined reference to `lv_scr_act'

defined in src/disp/lv_disp.h https://github.com/lvgl/lvgl/blob/1c1b59988004622de564b2655af56757ece00182/src/disp/lv_disp.h#L373

Afaik compiling LVGL C files into a static or dynamic library file is not the way, as inlined functions wont be there anyway. I'd guess that the right way is to add the header pragma to inlined functions

I've tried (using outputPath) to manually add it to generate lv_scr_act function:

  proc lvscract*(): ptr lvobjt_469762759 {.cdecl, header: "../lvgl/src/core/lv_disp.h", importc: "lv_scr_act".}

but I get conflicting types

test_lvgl_d/@mtest_lvgl.nim.c:83:15: error: conflicting types for ‘lv_obj_set_style_bg_color’; have ‘void(tyObject_structlvobjt469762586__9bfZUyxszOQcFM5H1JhlJQw *, tyObject_lvcolor16t469762490__J1gTOGAA6so8WXGapvAg1w,  NU32)’ {aka ‘void(tyObject_structlvobjt469762586__9bfZUyxszOQcFM5H1JhlJQw *, tyObject_lvcolor16t469762490__J1gTOGAA6so8WXGapvAg1w,  unsigned int)’}
   83 | N_CDECL(void, lv_obj_set_style_bg_color)(tyObject_structlvobjt469762586__9bfZUyxszOQcFM5H1JhlJQw* obj, tyObject_lvcolor16t469762490__J1gTOGAA6so8WXGapvAg1w value, NU32 selector);

Am I missing something? How are inlined functions in .h files supposed to be used/imported in Nim code, without Futhark?

PMunch commented 1 year ago

Hmm, header should remove the declaration. Maybe having both cdecl and header confuses it. Try removing cdecl and see if that helps.

PMunch commented 1 year ago

Did you ever get a chance to test this?

EDIT: Just did some quick and dirty testing with a hand written Nim file and .h file. I can't get it to create any definition for my procedure when using the header pragma. Maybe this is a bug fixed in recent versions of Nim, which version are you running?