Wireloom.Dds.Generator
0.5.0
dotnet add package Wireloom.Dds.Generator --version 0.5.0
NuGet\Install-Package Wireloom.Dds.Generator -Version 0.5.0
<PackageReference Include="Wireloom.Dds.Generator" Version="0.5.0" />
<PackageVersion Include="Wireloom.Dds.Generator" Version="0.5.0" />
<PackageReference Include="Wireloom.Dds.Generator" />
paket add Wireloom.Dds.Generator --version 0.5.0
#r "nuget: Wireloom.Dds.Generator, 0.5.0"
#:package Wireloom.Dds.Generator@0.5.0
#addin nuget:?package=Wireloom.Dds.Generator&version=0.5.0
#tool nuget:?package=Wireloom.Dds.Generator&version=0.5.0
Wireloom.Dds.Generator
Wireloom.Dds.Generator is a Roslyn source generator and MSBuild integration for
generating C# types from the RTI Connext DDS IDL subset. Add it to a .NET
project that owns DDS data contracts; the package generates source during the
normal build and does not invoke Java, native tooling, or rtiddsgen.
Consumer projects can target .NET 8 and higher using C# 12 or later. Support is feature-specific and evidence-driven; successful compilation of one IDL shape is not a blanket claim of RTI or wire compatibility.
Quick start
Create a .NET console project and add the generator, the RTI runtime, and an IDL root to its project file:
dotnet new console --name WireloomQuickStart --framework net10.0
cd WireloomQuickStart
Replace WireloomQuickStart.csproj with:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Rti.ConnextDds" Version="7.7.0" />
<PackageReference Include="Wireloom.Dds.Generator" Version="0.5.0" PrivateAssets="all" />
<DdsIdl Include="Telemetry.idl" />
</ItemGroup>
</Project>
Create Telemetry.idl beside the project file:
module Telemetry {
struct Sample {
long id;
string<64> label;
};
};
Build the project to generate and compile Telemetry.Sample:
dotnet build
The generator runs during the normal build; there is no separate code generation command. To run communicating publisher and subscriber processes, follow the Hello World guide, which also covers RTI runtime and license prerequisites.
The example above uses a .NET 10 target and the latest C# version. Current package integration evidence builds that target using the repository-pinned .NET 10 SDK; the Roslyn hosts in older SDKs are not all qualified. RTI Connext 7.7.0 is the tested runtime baseline.
For a project replacing existing RTI-generated C#, follow the
migration guide. It maps
common rtiddsgen options, identifies known API differences, and gives a
validation and rollback procedure.
Find your task
- Build and run Hello World with a publisher and subscriber.
- Install the package and declare an IDL root.
- Share compiled contracts between applications.
- Understand IDL-to-C# mappings.
- Configure generation settings, defaults, and overrides.
- Inspect generated source.
- Look up annotations, diagnostics, and effective limits.
- Troubleshoot generation.
Install
Add the generator and the RTI runtime explicitly. The generator package does
not add Rti.ConnextDds transitively because the application owns its runtime
version and configuration.
Running the DDS application also requires the RTI runtime's native assets and a valid license for the NuGet.org distribution. Follow RTI's license setup and the Hello World prerequisites.
<ItemGroup>
<PackageReference Include="Rti.ConnextDds" Version="7.7.0" />
<PackageReference Include="Wireloom.Dds.Generator" Version="0.5.0" PrivateAssets="all" />
</ItemGroup>
The generator selects its API profile from the resolved Rti.ConnextDds
assembly. Versions 7.3.1 through versions below 7.7.0 select the 7.3.1
profile; 7.7.0 and later select the 7.7.0 profile. Missing references and
versions below 7.3.1 produce DDSG0003. Only exact 7.3.1 and 7.7.0 LTS
versions are qualification targets; intermediate and later versions are mapped
but not individually qualified. The consumer project must resolve the RTI
version whose API and generated contracts it intends to use.
In the implementation, profile identifiers use the matching rtiddsgen
version: Rtiddsgen431 represents RTI 7.3.1, and Rtiddsgen470 represents
RTI 7.7.0. Runtime assembly versions still select the profile, while the
profile's separate version fields identify both the runtime documentation and
the code-generator API being matched.
The 7.7.0 profile is selected automatically for a 7.7.0 reference. There is
no public profile override because selecting older API code while compiling
against a newer RTI package can produce incorrect contracts. Rebuild and review
generated code when changing between profiles. See the support and
compatibility guide.
The generator itself targets netstandard2.0 for Roslyn host compatibility.
The repository's .NET 10 build and test defaults do not impose a .NET 10
requirement on consumer applications.
Declare an IDL generation root
Declare each file that starts generation with a DdsIdl item:
<ItemGroup>
<DdsIdl Include="Contracts\Telemetry.idl" />
</ItemGroup>
The IDL root can include other files. Included files are tracked inputs and are not independently generated as roots.
module Telemetry {
struct Sample {
long id;
string<64> label;
sequence<float, 8> values;
};
};
The generated API follows the IDL module structure. For the example above, the
consumer can use the generated Telemetry.Sample data type and, when the
selected feature shape has type support, Telemetry.SampleSupport:
var sample = new Telemetry.Sample
{
id = 42,
label = "temperature"
};
sample.values.Add(20.5F);
sample.values.Add(21.0F);
var typeSupport = Telemetry.SampleSupport.Instance;
For ordinary typed DDS code, use the generated data type with RTI's normal participant, topic, and writer APIs:
using Rti.Dds.Domain;
using Rti.Dds.Topics;
using var participant = DomainParticipantFactory.Instance.CreateParticipant(domainId: 0);
using var topic = participant.CreateTopic<Telemetry.Sample>("Telemetry");
using var writer = participant.ImplicitPublisher.CreateDataWriter(topic);
var sample = new Telemetry.Sample { id = 42, label = "temperature" };
sample.values.Add(20.5F);
writer.Write(sample);
RTI's typed topic API locates the generated type support for Telemetry.Sample.
Use Telemetry.SampleSupport.Instance directly when application code needs
its utilities, such as DynamicType, a serializer, or formatted output. The
support instance does not create a topic or publish data. This example shows
the API handoff; it still requires the RTI runtime, its deployment/licensing
prerequisites, matching topic/type/QoS on a peer, and a running DDS domain.
See RTI's C# publication examples
for the broader publish/subscribe lifecycle.
Generated types include the managed data contract and the RTI-specific support surface where the IDL shape is supported: native companions, type support, interpreted plugins, and DynamicType metadata.
Share generated contracts
For types used by several applications, put the DdsIdl roots in one class
library and reference that library from each application. The library's build
compiles generated C# into its assembly; consumers of the compiled library do
not need the generator package unless they also declare their own IDL roots.
<ItemGroup>
<PackageReference Include="Rti.ConnextDds" Version="7.7.0" />
<PackageReference Include="Wireloom.Dds.Generator" Version="0.5.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<DdsIdl Include="Contracts\Telemetry.idl" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Company.Contracts" Version="1.0.0" />
<PackageReference Include="Rti.ConnextDds" Version="7.7.0" />
</ItemGroup>
The normal Rti.ConnextDds reference in the contracts project is a package
dependency when that project is packed. Applications can rely on that
dependency or reference the runtime explicitly to control resolution. The
generator reference uses PrivateAssets="all", so the contracts package does
not configure source generation for downstream projects. Generated .g.cs
documents are build intermediates; the compiled contracts assembly is the
shareable artifact. Check the contracts package's target frameworks against
the application before publishing it.
Common IDL-to-C# mappings
These examples show the public C# API generated by Wireloom and compare it with the retained RTI Connext 7.7.0 C# oracle. The comparison is about generated source shape. Wireloom emits the C# contracts and adapters; RTI supplies the sequence types and DDS runtime. See RTI documentation for behavior owned by its runtime. The effective-limits section describes how bounds relate to mutation and DDS processing.
| IDL declaration | Wireloom C# API and use | RTI C# comparison | Evidence |
|---|---|---|---|
long id; |
int id { get; set; }<br>Assign with sample.id = 42;. |
Same member type and accessors. | RTI · generated |
typedef sequence<long, 4> BoundedLongs; |
ISequence<int> Value with [Bound(4)].<br>Use var bounded = new BoundedLongs(); bounded.Value.Add(17);. |
Same generated public shape. | RTI · generated |
@optional sequence<long, 4> values;<br>@optional long items[2]; |
ISequence<int>? values; int[]? items.<br>Set items = [1, 2]; set values = new Sequence<int> { 17 } or null for absence. |
Optional metadata matches. Wireloom adds nullable C# annotations absent from the retained RTI source. | RTI · generated |
typedef long Scalar;<br>typedef sequence<Scalar> Scalars; |
ISequence<Scalar> preserves the scalar wrapper. |
API difference: RTI exposes ISequence<int>. Callers using that shape must adapt to Scalar. |
RTI · generated · C136 |
union Choice switch(Kind) { case Number: long number; ... }; |
int number; assigning selects the branch. Reading an inactive branch throws InvalidOperationException. |
Same generated branch API and guard. | RTI · generated · runtime test |
This is a quick reference, not a complete mapping catalog. Consult the feature coverage matrix for case-level status and evidence. A difference in generated C# shape does not by itself establish a difference in DDS wire behavior. The runtime contract coverage matrix indexes tested copy, ownership, optional-presence, union, and native-round-trip behavior.
Configure includes and preprocessing
The configuration reference covers all generation settings, defaults, scopes, precedence, and examples, including sequence-array mapping, diagnostics, and generated-file output.
Use project properties for defaults shared by roots, or root-item metadata for the project-wide generation batch:
<PropertyGroup>
<DdsIdlIncludeDirectories>
$(MSBuildProjectDirectory)\Contracts\Shared
</DdsIdlIncludeDirectories>
</PropertyGroup>
<ItemGroup>
<DdsIdl Include="Contracts\Telemetry.idl"
IncludeDirectories="$(MSBuildProjectDirectory)\Contracts\Telemetry"
Defines="ENABLE_DIAGNOSTICS;PRODUCT_VARIANT=Enterprise"
Undefines="LEGACY_LAYOUT"
Strict="true" />
</ItemGroup>
Preprocessing and validation settings:
| Setting | Scope | Meaning |
|---|---|---|
DdsIdlIncludeDirectories |
Project | Semicolon-separated directories searched for configured includes and tracked for invalidation |
IncludeDirectories |
Root-item metadata collected for the batch | Additional include directories available to the generation batch |
Defines |
Root-item metadata collected for the batch | Semicolon-separated preprocessor symbols |
Undefines |
Root-item metadata collected for the batch | Semicolon-separated symbols removed before preprocessing |
Strict |
Root-item metadata collected for the batch | Enables strict validation for the generation batch when any root sets it |
DdsIdlEnableEscapeChar |
Project | Removes one leading underscore from each IDL identifier across the generation batch |
The current compiler combines these settings across all generating roots. It does not provide isolated preprocessing or validation settings per root.
Quoted relative includes resolve from the including file's directory. Angle includes use the configured include directories. Keep a shared file as an included input unless it is intentionally a separate generation root.
Project-level include directories are added before root-item directories. Include directories are deduplicated by path, keeping the first occurrence. Quoted includes search the including file's directory first, then the combined include directories; angle includes search the combined directories only. If two search directories contain the same include name, the first matching path wins.
Defines and Undefines are pooled across the generation roots. All external
defines seed each root's preprocessor, then all external undefines are applied;
an external undefine therefore removes a name even if another root defines it.
Each root starts with that same external macro state, so in-file #define and
#undef changes do not carry from one root to the next. Avoid assigning
different values to the same define in separate roots; per-root values are not
isolated. Split variants into separate projects or separate builds when they
need different IDL macro or strict-validation settings.
Strict defaults to false. Case-variant keywords and same-scope case-only
names report DDSG0108 and generate code by default. Setting Strict="true"
on any root rejects those names and new keys in derived aggregates before
emission. Exact reserved keywords fail in declarations, including interface
bodies. Ordinary interface bodies retain RTI's acceptance of case-only names;
@service("DDS") bodies apply the warning and strict rules. Interface bindings
remain omitted with DDSG0103. See the
configuration reference
for examples, warning exemptions, and differences from RTI's strict mode.
DdsIdlEnableEscapeChar defaults to false. When enabled, Wireloom removes
one leading underscore from each IDL identifier after preprocessing.
Declarations, references, macro-expanded names, and generated type metadata
use the normalized name; string literals are unchanged. The setting is
project-wide because all roots and includes share one symbol table. Names that
collide after normalization fail before emission. Normalized names also affect
implicit @autoid(HASH) IDs.
Large inputs may hit deterministic preprocessing safety limits. They are not configurable through MSBuild; see preprocessor limits.
Multiple roots and shared IDL
Use multiple roots when one project owns several types that include shared declarations. For example:
Contracts/
Telemetry.idl
Commands.idl
Shared/
Common.idl
// Shared/Common.idl
#ifndef WIRELOOM_SHARED_COMMON_IDL
#define WIRELOOM_SHARED_COMMON_IDL
module Shared {
struct Identity { long id; };
};
#endif
// Telemetry.idl
#include <Common.idl>
module Telemetry { struct Sample { Shared::Identity source; long value; }; };
// Commands.idl
#include <Common.idl>
module Commands { struct Request { Shared::Identity source; long action; }; };
Configure the include directory and declare only the two roots:
<PropertyGroup>
<DdsIdlIncludeDirectories>$(MSBuildProjectDirectory)\Contracts\Shared</DdsIdlIncludeDirectories>
</PropertyGroup>
<ItemGroup>
<DdsIdl Include="Contracts\Telemetry.idl" />
<DdsIdl Include="Contracts\Commands.idl" />
</ItemGroup>
The shared file is a tracked input and contributes Shared.Identity to the
same generated assembly. Identical shared include output is emitted once for
that project. For types used by several application projects, put the roots in
one contracts project and reference its assembly from each application. If
separate projects independently generate a shared type, each assembly owns a
copy with that type's fully qualified name; avoid referencing both copies from
the same consumer. Macro-selected variants require separate builds because
root metadata is batch-wide.
Choose the array-of-sequences mapping
See the configuration reference for the complete setting and precedence rules with before/after examples.
Direct arrays of sequences have two mappings. RtiCSharp is the default: it
matches RTI C# by flattening the outer array and reporting DDSG0105. Select
Idl to preserve the fixed array and each independently sized sequence in
the generated API, native storage, and wire type metadata:
<PropertyGroup>
<DdsIdlSequenceArrayMapping>Idl</DdsIdlSequenceArrayMapping>
</PropertyGroup>
<ItemGroup>
<DdsIdl Include="Contracts/Telemetry.idl" />
<DdsIdl Include="Contracts/Legacy.idl" SequenceArrayMapping="RtiCSharp" />
</ItemGroup>
Set SequenceArrayMapping="Idl" on a DdsIdl item to opt in one file without
changing the project default. Explicit file metadata takes precedence over
the project property. Values are case-insensitive; invalid values report
DDSG0001 and prevent generation.
The setting belongs to declarations physically in that file. A root's override
does not flow into included files: they use their own AdditionalFiles
metadata or the project default. For example:
<ItemGroup>
<AdditionalFiles Include="Contracts/Shared.idl" Generate="false" SequenceArrayMapping="Idl" />
</ItemGroup>
For struct Sample { sequence<long, 4> values[2]; }; and a union branch such
as default: sequence<long, 4> values[2];, the Idl mapping generates a fixed
array of sequence wrappers (Sample_valuesSequence[] or
Choice_valuesSequence[]). Each wrapper exposes its mutable sequence through
Value:
var sample = new Sample();
sample.values[0].Value.Add(10);
sample.values[0].Value.Add(20);
sample.values[1].Value.Add(30);
The same access pattern applies to a selected union branch:
var choice = new Choice();
choice.values[0].Value.Add(10);
choice.values[1].Value.Add(20);
The array has two elements; each sequence has its own length and maximum of four elements. Generated wrapper names gain trailing underscores if they conflict with existing declarations or generated companions. The enclosing wire metadata describes an array of anonymous sequences, without introducing a struct or synthetic alias into the member's wire schema.
Switching modes intentionally changes affected generated properties and wire
types. Idl targets the IDL structure used by RTI C++ and Java; it does not
interoperate with flattened RTI C#/Python direct-form bindings. Ordinary
sequences, other arrays, and explicit sequence typedefs retain their mappings.
Both supported RTI profiles have typed runtime coverage. The retained C149
Idl corpus case also passes all 16 focused Wireloom/C++ live DDS exchanges on
each exact RTI 7.3.1 and 7.7.0 release; see the
verification summary.
These results qualify the recorded fixtures and peer scope. Recursive direct
sequence arrays are rejected in Idl mode with DDSG0001. Existing effective
limits for unbounded sequences and strings still apply.
Recursive type support
Direct recursive sequence members serialize and exchange bidirectionally
for the direct self-recursive shape between Wireloom-generated C# and typed RTI
C++ peers on RTI 7.3.1 and 7.7.0
with the documented TypeObject v1 participant configuration. RTI 7.3.1's
generated C++ TypeCode needs the documented module-qualification correction.
RTI 7.7.0's default TypeObject v2 profile rejects recursive SCC types during
registration; use a nonzero type_object_max_serialized_length and enable only
SERVICE_REQUEST_CHANNEL. Mutual recursive struct graphs remain unqualified.
Recursive sequence typedefs, including self- and mutually recursive forms,
are rejected with DDSG0001. RTI's standard C++11 rtiddsgen -unboundedSupport output does not compile for these forms on RTI 7.3.1 or
7.7.0. Wireloom requires a normal RTI C++ interoperability path before
supporting them; this rejection does not claim that the IDL forms are illegal.
Programmatic compiler callers can pass IdlSequenceArrayMapping.Idl to the
IdlInput overload. sequenceSize and stringSize constructor arguments set
effective limits for unbounded types in that input. The defaults remain 100 and
255, respectively. Set enableEscapeChar: true on every generation root to
normalize leading-underscore identifiers across the batch; included inputs
inherit the setting.
Inspect generated source
Roslyn exposes generated documents through the IDE. To also write physical
generated files under obj, use the standard compiler options:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
The package does not create a separate command-line output directory or run a pre-generation step.
Preprocessor limits
Wireloom applies finite deterministic limits to each IDL input. Exceeding a limit stops generation and reports a source-located generation error. These limits have no MSBuild override:
| Limit | Maximum |
|---|---|
| Preprocessed output | 4,194,304 UTF-16 code units per input |
| Macro expansion work | 100,000 operations per input |
| Macro expansion depth | 64 nested expansions |
| Conditional expression depth | 256 nested expressions |
| Include nesting | 128 levels |
| Source-origin alignment work | 100,000 work units per expanded line |
To reduce a failure, simplify or split large IDL inputs, trim unused macro expansions, reduce conditional-expression and macro nesting, and simplify deep include chains. Splitting helps only when each resulting input and its preprocessed output stay within the per-input limits. The preprocessor feature matrix describes which preprocessing forms are implemented or partial.
Annotation reference
This is a reference to behaviors implemented and exercised by the current corpus, not a claim that every OMG or RTI annotation is supported. Annotation effects often appear in RTI DynamicType metadata rather than in the managed C# member signature.
| Annotation or group | Current behavior and scope | Evidence |
|---|---|---|
@topic |
Marks a struct as a DDS topic data type in generated documentation. It does not create a topic or publish samples. | 10-annotations.idl |
@key |
Marks a member as a DDS instance key and is reflected in type support metadata. Key identity is distinct from equality of complete C# samples. | 08-keys.idl, 10-annotations.idl |
@optional |
Marks optional members in type support and produces nullable C# members for supported optional shapes. An optional union branch is ignored because a union always selects one branch. | 09-optional-collections.idl, 09-optional-aggregate-member.idl |
@id, @hashid, @autoid(HASH) |
Set explicit or hash-derived DDS member IDs in supported aggregate contexts. Other @autoid mappings are not separately qualified here. |
09-id-gaps.idl, 09-autoid-hash.idl |
@final, @appendable, @mutable |
Set the corresponding extensibility kind in generated DynamicType metadata for covered declarations. | 09-extensibility.idl |
@default, @min, @max, @range, @unit |
Supported on primitive/enum members as applicable. Defaults initialize supported values; ranges and units are represented in generated type support annotations. Ranges require primitive members; defaults also support enums. | 09-defaults-ranges.idl, 10-annotations-rti.idl |
@value, @default_literal |
Set explicit enum numeric values and the default enum literal for covered enum shapes. | 03-enum-values-prefix.idl, 09-defaults-ranges.idl |
@must_understand |
Preserved as a member property in generated DynamicType metadata with the 7.7.0 profile. The 7.3.1 profile reports DDSG0004 and emits no code because that RTI release does not support the annotation. |
09-autoid-hash.idl |
@external |
Accepted in the tested annotation case but does not create a distinct managed C# member shape. Check runtime/wire evidence before relying on any external-member serialization effect. | 10-annotations-rti.idl |
@language_binding, @transfer_mode, @data_representation, @allowed_data_representation, @nested, @default_nested, @resolve_name |
Recognized/consumed syntax, but not all have an effect in emitted C# or generated DynamicType. The corpus comparisons establish only the listed case outcomes; do not rely on these annotations to configure wire representation or naming without separate runtime/wire evidence. FLAT_DATA is ignored for C# generation. |
10-annotations-rti.idl, 09-data-representation.idl, 09-allowed-data-representation.idl, 10-flat-data-binding.idl |
| Unknown annotation | Emits warning DDSG0101 and continues while ignoring the annotation. Verify that ignoring it does not change the contract you need. |
12-unknown-annotation.idl |
@position, @bit_bound; invalid @service target |
Recognized but unsupported uses emit DDSG0102 and reject generation. A @service("DDS") interface is instead ignored with DDSG0103; interfaces do not become C# types. |
10-unsupported-annotations.idl, 10-service-annotation.idl |
For enum arrays, @default_literal initializes generated managed and native
array elements from the declared enum member. See the
10-default-literal-enum-array corpus case.
Unresolved names used as array, sequence, string, or wstring bounds are rejected before C# emission. The C143–C146 corpus cases record the diagnostics and RTI profile outcomes.
An annotation accepted by RTI is not automatically implemented by Wireloom. For a declaration not listed here, check the exact corpus case and diagnostic; use an unknown-annotation warning as a prompt to verify the generated contract, not as evidence that the annotation is harmless.
Diagnostics
| ID | Meaning | Typical action |
|---|---|---|
DDSG0001 |
IDL generation failed | Fix the source-located parse, include, semantic, or unsupported-feature error |
DDSG0002 |
C# 12 or later is required | Set the consumer's language version to C# 12 or later |
DDSG0003 |
A compatible RTI runtime was not found | Add an explicit Rti.ConnextDds reference at version 7.3.1 or later |
DDSG0004 |
An IDL feature is unavailable in the selected RTI API profile | Remove the unsupported feature or use a compatible RTI version; @must_understand requires 7.7.0 or later |
DDSG0101 |
An unknown IDL annotation was ignored | Verify the annotation is supported by the managed generator if it affects the generated contract |
DDSG0102 |
A recognized but unsupported annotation use was reported | Remove the annotation or use a supported declaration context; this warning accompanies rejected generation |
DDSG0103 |
An IDL interface was ignored because no C# interface type is emitted | Names are checked before bindings are omitted; ordinary and DDS-service body rules differ |
DDSG0104 |
A function-like macro was invoked with the wrong number of arguments | Correct the macro invocation; RTI-compatible expansion continues after the warning |
DDSG0105 |
A direct array of sequences may not preserve IDL semantics | Use a sequence typedef or opt into SequenceArrayMapping="Idl" |
DDSG0106 |
An active #warning directive was encountered |
Review the warning in the IDL or included file; preprocessing and generation continue |
DDSG0107 |
An active #pragma message directive was encountered |
Review the informational message in the IDL or included file; generation continues |
DDSG0108 |
An IDL name conflicts with a keyword or another name ignoring case | Rename the identifier or exempt the default warning; strict validation rejects the declaration |
DDSG0109 |
An escaped identifier normalizes to TRUE or FALSE |
Rename it to avoid ambiguity with IDL boolean literals; Wireloom still resolves it as an identifier |
Diagnostics are owned by the generator and use the original IDL/include
location where one is available. Review the table's typical actions before
adoption; ignored annotations or interfaces and mappings flagged as potentially
lossy can affect the generated contract. Configure an individual diagnostic's
severity through the consumer's .editorconfig, for example:
[*.idl]
dotnet_diagnostic.DDSG0101.severity = error
The default severities are grouped by diagnostic family: DDSG0001–DDSG0004
are errors, DDSG0101–DDSG0106 and DDSG0108–DDSG0109 are warnings, and DDSG0107
is informational. Warnings do not all mean generation continues: DDSG0102
reports an unsupported annotation use and is followed by a generation error.
DDSG0101, DDSG0103,
DDSG0104, DDSG0105, DDSG0106, DDSG0108, and DDSG0109 report cases where
generation continues in default mode. The diagnostics table describes the
action for each one.
Diagnostics point to the originating IDL file, including when the problem is
inside an included file. For example, if Contracts/Telemetry.idl contains:
#include "shared/Shared.idl"
and Contracts/shared/Shared.idl contains:
struct Shared {
long values[0];
};
the DDSG0001 error reports that Array dimensions must be a positive
Int32, at the array bound in Shared.idl. If the same declaration is placed
directly in Telemetry.idl, the error points to the root file instead. Start
from the reported path and line, correct the bound, and rebuild; the build
fails while a generation error remains.
Supported boundary
The current corpus exercises modules, structs, nested declarations, aliases, enums, unions, constants, primitive values, narrow and wide strings, bounded strings, sequences, arrays, include graphs, conditional preprocessing, keys, annotations, and extensibility. Several of these are supported only for the specific shapes covered by the retained RTI oracle evidence.
Before adopting a feature, consult the diagnostics table, feature coverage matrix, and corpus rules.
Effective limits for unbounded values
Wireloom assigns effective limits to unbounded IDL values: 255 UTF-8 bytes
for narrow strings, 255 UTF-16 code units for wide strings, and 100
elements for sequences by default. Set project properties
DdsIdlSequenceSize and DdsIdlStringSize to change those defaults.
SequenceSize and StringSize metadata on a DdsIdl or AdditionalFiles
item override the project values for declarations in that file. All settings
must be positive Int32 values; explicit IDL bounds take precedence. See the
configuration reference
for examples and scope details. For example, 128 copies of é use 256 UTF-8
bytes, so they exceed the narrow-string limit even though the C# string
contains only 128 characters.
Generated string properties do not enforce their bounds when assigned, and
sequence members expose mutable containers whose Add operations do not cap
the element count. RTI uses the bound in type metadata when processing DDS data.
The runtime contract suite
verifies native round trips at the effective limits. It does not establish
exactly where or how an over-limit value fails, so consumers should validate
values before DDS processing rather than rely on assignment-time checks.
The compatibility corpus compares source-generation behavior and generated C# shape. It does not automatically prove serialization-byte equivalence, live DDS behavior, or C++ interoperability.
What this package does not do
- It does not provide the RTI DDS runtime, transport, or serialization engine.
- It does not invoke or forward arbitrary arguments to
rtiddsgen. - It does not implicitly generate every
.idlfile in a project; roots are explicitDdsIdlitems. - It does not promise complete Connext IDL coverage or universal drop-in compatibility with RTI-generated C#.
- It does not silently omit unsupported declarations; accepted exceptions that ignore annotations or interfaces are reported with diagnostics.
Troubleshooting
When generation appears not to run, start with a clean command-line build and follow the symptom table. IDE behavior can depend on its Roslyn host; current package integration evidence covers command-line builds, not every IDE/SDK combination.
| Symptom | Check and next step |
|---|---|
| Build succeeds but no generated types appear | Confirm the project references Wireloom.Dds.Generator and declares the intended roots as DdsIdl items. Other .idl files are tracked includes, not roots. |
| Generator package is present but has no effect | Restore the project, inspect the resolved package version and analyzer/build assets, then run dotnet build from the project directory. If the build reports an analyzer load or Roslyn assembly error, verify the SDK/compiler host; older SDK hosts are not all qualified. |
DDSG0002 |
Set <LangVersion>12.0</LangVersion> or later. This diagnostic is reported when the generator loads and the compiler language version is too old. |
DDSG0003 |
Add an explicit Rti.ConnextDds reference at a version accepted by the guard; the generator package does not add the runtime transitively. |
DDSG0001 |
Read the diagnostic text and source location. Check IDL syntax, include resolution, semantic rules, and feature coverage. This is also the generation-failure diagnostic for preprocessing limits. |
| Generated documents are absent in the IDE | First confirm the command-line build succeeds. Roslyn generated documents appear in the IDE; to inspect files on disk, enable EmitCompilerGeneratedFiles and set CompilerGeneratedFilesOutputPath as described in Inspect generated source. |
| Build works but the IDE shows stale generated code | Rebuild and reload the project, then check the IDE's selected SDK and analyzer diagnostics. Do not infer an IDE-host compatibility result from a command-line build. |
| Compiler reports duplicate generated type definitions | Remove exported generated .g.cs files from explicit <Compile> items. The generator already adds its documents to compilation; do not compile the same emitted source twice. |
The generator reports DDSG0003
Add the runtime package to the consuming project. The generator package is
private build tooling; the application must reference Rti.ConnextDds itself.
An include cannot be resolved
Check whether the include is quoted or angle-bracketed. Quoted includes are
resolved relative to the including file. For angle includes, add the directory
to DdsIdlIncludeDirectories or the root's IncludeDirectories metadata.
A shared file is generated twice
Keep the shared file as an included input and declare only the intended root in
DdsIdl. A physical IDL file should normally have one generation identity per
consumer project.
A feature is rejected
Read the source-located DDSG0001 diagnostic, then check the feature coverage
matrix. Rejection is intentional when the current managed compiler does not
have evidence for a safe generated contract.
Learn more
- Wireloom repository
- Architecture overview
- Corpus compliance tests
- Package integration test
- Generated value semantics
- Release qualification records
RTI-generated reference material in the repository is retained under the applicable RTI license and review rules. It is not redistributed by this NuGet package.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.