LLNL / shroud

Shroud: generate Fortran and Python wrappers for C and C++ libraries
BSD 3-Clause "New" or "Revised" License
91 stars 7 forks source link

Self-referential structure #327

Closed CarvFS closed 9 months ago

CarvFS commented 9 months ago

Hello,

I am working with a self referential structure, so I have my .yalm file as

library: test
format:
  F_filename_suffix: F90
cxx_header: test.hpp

declarations:
- decl: |
    struct timer_cpp{
      int sublevels;
      timer_cpp *parent;
      timer_cpp **child;
    };
  options:
    literalinclude: True
    F_struct_getter_setter: False

However, the generated wrapper .h file (in this case wraptest.h) contains:

// wraptest.h
// This file is generated by Shroud 0.12.2. Do not edit.
/**
 * \file wraptest.h
 * \brief Shroud generated wrapper for test library
 */
// For C users and C++ implementation

#ifndef WRAPTEST_H
#define WRAPTEST_H

#include "typestest.h"

// splicer begin CXX_declarations
// splicer end CXX_declarations

#ifdef __cplusplus
extern "C" {
#endif

struct s_TES_timer_cpp {
    int sublevels;
    TES_timer_cpp * parent;
    TES_timer_cpp * * child;
};
typedef struct s_TES_timer_cpp TES_timer_cpp;

// splicer begin C_declarations
// splicer end C_declarations

#ifdef __cplusplus
}
#endif

#endif  // WRAPTEST_H

It gives an error while compiling because inside the struct definition it should be s_TES_timer_cpp * parent instead of TES_timer_cpp * parent.

Is there a way of redefining the variable type inside the struct definition, so I can get the missing s_?

Thanks in advance! :)

ltaylor16 commented 9 months ago

If you're only interested in the Fortran wrapper, you can turn off the c wrapper for the struct and the file wraptest.h will not be created.

- decl: |
    struct timer_cpp{
      int sublevels;
      timer_cpp *parent;
      timer_cpp **child;
    };
  options:
    wrap_c: False

But to wrap it properly will require some changes to Shroud.

I tried turning on F_struct_getter_setter and see it has issues too. The intent is that the type(C_PTR) would be converted into a Fortran pointer to an array of timer_cpp structs. If I guess the meaning of the fields correctly, then creating the getter would (eventually) do the right thing.

 timer_cpp **child +dimension(sublevels)

The getter would return a Fortran type

type(timer_cpp), pointer :: child(:)
CarvFS commented 9 months ago

I take a look on Shroud source code and it seems that s_ in the struct name is hard coded, so I was looking for some way of adding a if statement while wrapping the struct to check whether the variable type is the same as the struct and add the s_ to it too. However I do not knowif this would be the best way of implementing it.

I need the c wrapper because I am working in a project which has a Fortran derived type defined and I need a twin version of it on C/C++. Thus, I need to copy the information the Fortran version into the C/C++ version. The way I am doing it is:

1- copy the information from Fortran derived type to the Fortran wrapper; 2- Use a function to send the values to C++ side.

In the second part I need the c wrapper, so I can have a function like cpy_f_2_c(timer_cpp timer). I could also use the setters, but in any case there would be this issue.

One solution could be using the splicers to define the struct and functions needed: I can use the ones created by shroud and only modify, inside the struct, from

    TES_timer_cpp * parent;
    TES_timer_cpp * * child;

to

    s_TES_timer_cpp * parent;
    s_TES_timer_cpp * * child;
ltaylor16 commented 9 months ago

The generated code will now compile. I reversed the order of the generated struct and typedef so the typedef name is available to the struct.

typedef struct s_TES_timer_cpp TES_timer_cpp;
struct s_TES_timer_cpp {
    int sublevels;
    TES_timer_cpp * parent;
    TES_timer_cpp * * child;
};

github automatically closed the issue. There is still work to do to make this fully functional with regards to getters and setters. Feel free to reopen if you need additional functionality.

CarvFS commented 9 months ago

Thank you very much! It is working fine now, and the solution was way simpler than I was thinking :)