# Nested IDL

5 posts / 0 new
Offline
Last seen: 4 years 4 months ago
Joined: 03/02/2015
Posts: 2
Nested IDL

I would like to be able to re-use types in multiple IDL files and use rtiddsgen. For example

File message1.idl

struct message1 { header h; ...}

File message2.idl

However, rtiddsgen only appears to generate code and a makefile for the last idl file passed to it, e.g. if I give it header.idl and message1.idl, I will not get code generated for for the header.

I could run rtiddsgen on header and message1 separately, but would then need to hand craft a makefile for compiling and linking the two.

The alternative is to replicate the idl of the header inside each of message1 and message2, which would make maintenance difficult.

Am I missing something, or is this really the case? If so, are there better ways of achieving what I want.

Keywords:
Offline
Last seen: 3 months 4 weeks ago
Joined: 06/02/2010
Posts: 594

Hello,

What Language are you generating code for? This answer assumes C/C++ if it was Java maybe some of the problems I mention would not manifest themselves.

Yes, you need to run rtiddsgen separately on each IDL file. As you noted, rtiddsgen does not automatically generate code for the included IDLs. The reason is that if we did this it would be easy to get in a situation where code for the same IDL would be generated multiple times or in multiple files. This would happen for example if the same IDL file was included from multiple other IDLs.

It would not be a good idea to replicate the typs in header.idl into both message1.idl and message2.idl. Aside from being messy and hard to maintain you can easily run into "duplicate symbol" problems.

The model is that each IDL has its own associated generate code that should be managed along with that IDL.  Typically the result of this is also a library that contains the associated generated type-specific generated files (but not the example files). Other IDLs files that include that IDL would also have to link the library that was generated from the IDL.

In your example: where header.idl is included both from message1.idl and message2.idl the approach would be.

2. Run rtiddsgen on message1.idl  --> get Message1-defined TypeSypport, TypePlugin and Type files. --> Link then into a library   message1.lib
3. Run rtiddsgen on message2.idl  --> get Message2-defined TypeSypport, TypePlugin and Type files. --> Link then into a library   message2.lib

Depending on the types used by your final application you would link different subsets of these libraries. For example:

• An application using types from message1.idl would link message1.lib and header.lib
• An application using types from message2.idl would link message2.lib and header.lib
• An application using message1.idl and message2.idl would link message1.lib, message2.lib and header.lib

Note that if we had generated the code for the types in header.idl as a result of running rtiddsgen on message1.lib, then these "header-types code" would also appear inside message2.lib and when you tried to link both message1.lib and message2.lib you would get duplicated symbols.

Unfortunately this means you need to manually edit any auto-generated makefiles/projects. The autogenerated makefiles/projects are intended for simple examples it would hard to make them generic without making them complicated which would confict with their main purpose as examples. So the more "real world" scenarios you describe require manual modification of the makefiles/projects.

Hope this helps,

Gerardo

Offline
Last seen: 4 years 4 months ago
Joined: 03/02/2015
Posts: 2

Yes it is C++ we are using and you give a very comprehensive answer that is the same conclusion I was coming to.

Offline
Last seen: 4 years 10 months ago
Joined: 04/01/2016
Posts: 1

Is this possible with Managed C++/CLI and can someone point me to an example? I'm having trouble attempting to use the example code generated with rtiddsgen.

Visual Studio 2013
Windows 10 64 bit
RTI Connext DDS 5.2.0 (Professional if that matters)

Here is what I have:

C:\test\foo\foo.idl#ifndef FOO_IDL
#define FOO_IDL
struct Foo { long data; };
#endif

C:\test\bar\bar.idl#ifndef BAR_IDL
#define BAR_IDL
#include "foo.idl"
struct Bar { Foo foo; };
#endif

I first run rtiddsgen on foo.idl and then compile the generated foo-type project (and the publisher/subscriber coincidentally) using the following:

C:\test\foo\>rtiddsgen -language C# -example x64Win64VS2013 foo.idlINFO com.rti.ndds.nddsgen.Main Running rtiddsgen version 2.3.0, please wait ...
rtiddsgen20_7341046294903150386.cc
INFO com.rti.ndds.nddsgen.Main Done

C:\test\foo>devenv foo-64-csharp.sln /build release
<skipping most of the visual studio output for brevity>
1> foo_type-64-dotnet4.5.1.vcxproj -> C:\test\foo\bin\x64\Release-VS2013\foo_type.dll
2> foo_publisher-64-csharp -> C:\test\foo\bin\x64\Release-VS2013\foo_publisher.exe
3> foo_subscriber-64-csharp -> C:\test\foo\bin\x64\Release-VS2013\foo_subscriber.exe
========== Build: 3 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Running foo_publisher.exe and foo_subscriber.exe works as expected.

I repeat for bar.idl, while passing in the path to foo.idl as an additional argument:

C:\test\bar>rtiddsgen -language C# -example x64Win64VS2013 -I ..\foo bar.idlINFO com.rti.ndds.nddsgen.Main Running rtiddsgen version 2.3.0, please wait ...rtiddsgen20_4442684579607075862.ccINFO com.rti.ndds.nddsgen.Main Done

From here, I open the generated bar-64-csharp.sln and try the following:

1) Compile bar_type project. Compile error is it cannot find "foo.h" in the project.
2) I add the path to foo.h via: bar_type > Properties > C/C++ > General > Additional Include Directories > Add C:\test\foo

3) Compile again and it works this time. Now, I get linking errors, specifically error LNK2001: unresolved external symbol "struct DDS_TypeCode * __cdecl Foo_get_typecode(void)" ([email protected]@[email protected]@XZ)
4) I add a reference to foo_type.dll via: bar_type > Properties > Common Properties > Add New Reference > point to foo_type.dll

5) Compile once more and I get various errors:

Error 1 error C2011: 'Foo' : 'class' type redefinition C:\test\foo\foo.h 19 1 bar_type
Error 2 error C2011: 'FooSeq' : 'class' type redefinition C:\test\foo\foo.h 48 1 bar_type
Error 12 error C2664: 'bool BarPlugin::serialize(DDS::TypePluginDefaultEndpointData ^,Bar ^,DDS::CdrStream %,bool,unsigned short,bool,System::Object ^)' : cannot convert argument 2 from 'Foo ^' to 'Bar ^' C:\test\bar\barPlugin.cpp 87 1 bar_type
Error 14 error C2664: 'bool BarPlugin::deserialize_sample(DDS::TypePluginDefaultEndpointData ^,Bar ^,DDS::CdrStream %,bool,bool,System::Object ^)' : cannot convert argument 2 from 'Foo ^' to 'Bar ^' C:\test\bar\barPlugin.cpp 132 1 bar_type
Error 19 error C2664: 'unsigned int BarPlugin::get_serialized_sample_size(DDS::TypePluginDefaultEndpointData ^,bool,unsigned short,unsigned int,Bar ^)' : cannot convert argument 5 from 'Foo ^' to 'Bar ^' C:\test\bar\barPlugin.cpp 287 1 bar_type
Error 24 error C2027: use of undefined type 'Foo' C:\test\bar\bar.cpp 28 1 bar_type
and more

Am I missing something obvious? I have no trouble doing this with C++.

Thanks for any help!

Offline
Last seen: 2 years 7 months ago
Joined: 10/05/2015
Posts: 13

Hi,

Your issue seems to be that Visual Studio is trying to compile the same files that are in the Foo library. You can avoid this situation by using a macro suffix in all your base types (in this case foo). Please, try with the following steps:

1) Generate the Foo library with a macro suffix:
C:\test\foo>rtiddsgen -language c# -example x64Win64VS2013 -dllExportMacroSuffix FOO foo.idl
C:\test\foo>devenv foo-64-csharp.sln /build release

2) Generate the Bar type files:
C:\test\bar>rtiddsgen -language c# -example x64Win64VS2013 -I ..\foo bar.idl

3) Edit the bar_type project properties:
3.1) In "Configuration Properties -> C/C++ -> General -> Additional Include Directories" add the path to the Foo type files:
3.3) In "Configuration Properties -> Linker -> General -> Additional Library Directories" add the Foo library path: C:\test\foo\bin\x64\Release-VS2013