We are currently trying to migrate from RTI DDS 5.0.0 to 5.1.0, and have observed some strange behavior in the C++ code that is generated by the rtiddsgen tool. The issue we are seeing is when we have an idl file that contains only a single enum definition, and it is included and used by another idl file. It appears as though there is a function, MyEnum_finalize_optional_members(...), which is declared but not defined in the generated code.
As an example, In our enum.idl file, we have the following:
enum MyEnum { ENUM_1 = 0, ENUM_2 = 1, ENUM_3 = 2, NUM_MY_ENUMS };
And in our struct.idl file, we have the following:
#include "enum.idl"
struct MyStruct { MyEnum my_enum; };
I then generated the C++ messages using the following commands on our Fedora 20 system:
/opt/rti/ndds.5.1.0/scripts/rtiddsgen -language C++ -namespace -ppDisable -replace -optimization 0 -inputIdl -verbosity 2 enum.idl
/opt/rti/ndds.5.1.0/scripts/rtiddsgen -language C++ -namespace -ppDisable -replace -optimization 0 -inputIdl -verbosity 2 struct.idl
In the generated struct.cxx file, there are two calls to MyEnum_finalize_*, but the problem is that MyEnum_finalize_optional_members is declared in enum.h, but not defined in enum.cxx. This obviosuly results in a linker error.
void MyStruct_finalize_w_params(
MyStruct* sample,
const struct DDS_TypeDeallocationParams_t * deallocParams)
{
...
MyEnum_finalize_w_params(&sample->my_enum, deallocParams);
...
}
void MyStruct_finalize_optional_members(
MyStruct* sample, RTIBool deletePointers)
{
...
MyEnum_finalize_optional_members(&sample->my_enum, deallocParams->delete_pointers);
...
}
The odd part is that if I move the MyStruct definition into the enum.idl file, the problem goes away because the MyStruct_finalize_optional_members function now wants to call MyEnum_finalize_w_params, which is defined.
void MyStruct_finalize_optional_members(
MyStruct* sample, RTIBool deletePointers)
{
...
MyEnum_finalize_w_params(&sample->my_enum, deallocParams);
...
}
Does anyone have any thoughts on what could be causing this issue?
Attachment | Size |
---|---|
enum.idl | 75 bytes |
struct.idl | 61 bytes |
I just stumbled upon something interesting...
If I use rtiddsgen2 instead of rtiddsgen, the MyEnum_finalize_optional_members(...) function is declared properly.
By adding "//@resolve-name false" to the end of my MyStruct definition:
struct MyStruct
{
MyEnum my_enum;
}; //@resolve-name false
And then invoking the following commands:
/opt/rti/ndds.5.1.0/scripts/rtiddsgen2 -language C++ -namespace -ppDisable -replace -inputIdl -verbosity 2 enum.idl
/opt/rti/ndds.5.1.0/scripts/rtiddsgen2 -language C++ -namespace -ppDisable -replace -inputIdl -verbosity 2 struct.idl
Everything seems to compile and link properly. This of course does not address the issue with rtiddsgen, and am wondering if it is a bug with rtiddsgen that happened to get implemented properly in rtiddsgen2.
Since things are pretty quiet as far as responses to the rtiddsgen 5.1.0 issue, let me ask another question...
Since rtiddsgen2 is only an Early Access Release (EAR), what risks would our program be assuming by using a beta version of the tool?
We would like to make the jump to RTI DDS 5.1.0, but if we can't get our auto-generated messages to compile/link without using a beta version of the message generation tool, I would like to know what risk we would be taking on in doing so.
Any assistance that could be provided would be greatly appreciated. Thank you.
-Chad
Hi Chad,
The problem in your first case, using rtiddsgen with 5.1.0 is that you are calling it with -ppDisable. This option disables the preprocessor, so it is not really parsing your included "enum.idl" file and it does not know that your type MyEnum is an enum, and it is generating code assuming it is a struct and that is why you find some errors compiling the generated code. So you have two options:
a) Run rtiddsgen with the preprocessor enabled i.e, without the -ppDisable option
b) Include your enum in the same file that the struct, if everything is in the same file you can disable the preprocessor.
In the case of rtiddsgen2, if you try to run it with -ppDisable it will probably show you an error saying that MyEnum wasn't defined (what it's true because you are not letting it parse the "enum.idl" file). I guess that is the reason you added the //@resolve-name false option.
That option what is doing is telling rtiddsgen that does not need to take care of the resolution of the types that are within the struct, and it will assume that are an unkeyed structs (what in your case is not true either). So that "solution" is not a good one for your use-case.
You can find more information about @resolve-name directive here.
In version 5.2.0 rtiddsgen2 becomes the default Code Generator.
Let me know if that solves your problem.
Aida,
Thank you for the detailed explanation. I was hoping for another hidden rtiddsgen option, but it looks like this issue will be a bit more difficult to solve. :-)
For reasons beyond this discussion, we need to use the "-ppDisable" option, and we are also unable to co-locate the enum definition with the struct(s), since the enum is common code included in several files. So with that being said, it looks like rtiddsgen (5.1.0) will not work for us under any circumstances.
After reading the documentation on "//@resolve-name" that you provided, it looks as though this was intended to be used only on structs/unions and not enums, correct? Even if using "//@resolve-name" on an enum is not a correct solution, will it still work? If not, would our only solution be to include the enum definition in every file in which we need to use it? As much as I would hate to do that, it may be our only solution if my "//@resolve-name" "solution" is not valid.
I do like the fact the rtiddsgen2 runs much faster, especially in server mode, so I would definitely like to move in that direction if at all possible. It just seems like our use of "-ppDisable" has backed us into a corner, but remain optimistic that we can find a proper solution to this issue.
-Chad @ Lockheed Martin
Hi Chad,
Sorry for the delay in the response.
I'd encourage you to use the preprocessor if possible, you will have a better user-experience and also can take advantage of other preprocessor adventages, not only including files. But if you don't want to use the preprocessor the only solution is to add the enums in the same file you need them. As you said the "//@resolve-name" on an enum is not expected, and therefore the generated code may be wrong or not even compile (as it is happening for you in 5.1.0). This is valid for both rtiddsgen and rtiddsgen2
If you want to move to rtiddsgen2 you should upgrade to 5.2.0 version, where it is the default code generator, as in 5.1.0 is just an EAR cannot be used for productions.
Regards,
Aída