Files
qt-migration-legatus/qt5-before/dlbo/Lts/Common/CodeGen/codegen_simple.py
T
torstenandCopilot 7173785915 Qt6 Migration: Complete migration with DDS/RTI support and build validation
Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list

Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF

Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
  - Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
  - Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)

Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified

Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-15 18:20:26 +00:00

478 lines
20 KiB
Python
Executable File

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# $Id$
# $HeadURL$
# $Author$
#
from __future__ import print_function
import xml.etree.ElementTree as ET
import os
import re
import string
import sys
import time
class FtData(object):
def __init__( self ):
self.name = ''
self.namespace = ''
self.requestTopicType = ''
self.requestTopicName = ''
self.replyTopicType = ''
self.replyTopicName = ''
def fqnVar( self, name ):
if name.find('::') < 0:
name = self.namespace + '::' + name
return name
def stripNamespace( self, str ):
return str.split('::')[-1]
def getReplyTopicName( self ):
return 'LTS_' + self.stripNamespace( self.replyTopicName ).replace( '::', '_' )
def getReplyTopicNameType( self, withNamespace = True ):
var = self.replyTopicName
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
def getRequestTopicName( self ):
return 'LTS_' + self.stripNamespace( self.requestTopicName ).replace( '::', '_' )
def getRequestTopicNameType( self, withNamespace = True ):
var = self.requestTopicName
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
def getReplyTopicType( self ):
return self.fqnVar( self.replyTopicType )
def getRequestTopicType( self ):
return self.fqnVar( self.requestTopicType )
def needReplyTopicTypedef( self ):
return self.getReplyTopicNameType() != self.getReplyTopicType()
def needRequestTopicTypedef( self ):
return self.getRequestTopicNameType() != self.getRequestTopicType()
class GuiPluginRights(object):
def __init__( self ):
self.name = ''
self.offset = 0
self.groups = []
class GuiPluginRightsGroup(object):
def __init__( self ):
self.name = ''
self.desc = ''
self.values = []
class FileParser(object):
def __init__( self ):
self.filename = ''
self.service_abbr = ''
self.module_name = ''
self.struct_names = []
self.ft_enums = []
self.ft_replies = []
self.ft_data = dict()
self.op_right_offset = 0
self.op_rights = []
def build(self, path):
""" Parse the whole stuff ... """
self.filename = path
self.read_file_xml(self.filename)
def read_file_xml(self, filename):
""" Read the given xml service file"""
"""print >> sys.stdout, 'Reading xml file %s' % filename"""
xmlTree = ET.parse(filename)
root = xmlTree.getroot()
self.module_name = root.attrib['namespace']
self.service_abbr = root.attrib['abbreviation'].lower()
for child in root.iter('topicType'):
struct_name = child.attrib['name']
if 'isDataObject' in child.attrib and int(child.attrib['isDataObject']) != 0:
self.struct_names.append(struct_name)
for child in root.iter('functionTopic'):
ft_name = child.attrib['name']
self.ft_enums.append(ft_name) # solange es noch entityModel.idl gibt ...
ft_data = FtData()
ft_data.name = ft_name
ft_data.namespace = self.module_name
ft_data.requestTopicType = child.attrib['requestTopicType']
ft_data.requestTopicName = child.attrib['requestTopicName']
ft_data.replyTopicType = child.attrib['replyTopicType']
ft_data.replyTopicName = child.attrib['replyTopicName']
self.ft_data[ft_name] = ft_data
for child in root.iter('operatorRights'):
self.op_right_offset = int(child.attrib['offset'])
for pluginChild in child.iter('guiPlugin'):
r = GuiPluginRights()
r.name = pluginChild.attrib['name']
r.offset = int(pluginChild.attrib['offset'])
r.groups = [];
for groups in pluginChild.iter('operatorRightGroup'):
g = GuiPluginRightsGroup();
g.name = groups.attrib['name']
g.desc = groups.attrib['description'] if 'description' in groups.attrib else ''
for right in groups.iter('operatorRight'):
desc = right.attrib['description'] if 'description' in right.attrib else ''
g.values.append((right.attrib['right'], int(right.attrib['value']), desc))
r.groups.append(g)
self.op_rights.append(r)
def outputHeader( outfile, parser, description, with_dds_include = True, with_pragma = True ):
outfile.write('\n')
outfile.write('/**\n')
outfile.write('* %s definitions\n' % description)
outfile.write('*/\n')
outfile.write('\n')
outfile.write('// warning: this file is generated with command\n')
outfile.write('// %s\n' % ( " ".join(sys.argv) ))
outfile.write('// at %s\n' % time.strftime( '%c' ))
outfile.write('// it will be overwritten by next run - do not modify!\n')
outfile.write('\n')
if with_pragma:
outfile.write('#pragma once\n')
outfile.write('\n')
if with_dds_include:
outfile.write('#include "%s.hpp"\n' % ( parser.service_abbr ))
class DtsGenerator(object):
def generate( self, outfile, parser ):
outputHeader( outfile, parser, 'DTS' )
outfile.write('\n')
outfile.write('/**\n')
outfile.write(' * Type definitions \n')
outfile.write(' * => DataWriterObjects (DWOs)\n')
outfile.write(' * => DataTopicServers (DTSs)\n')
outfile.write(' */\n')
outfile.write('\n')
outfile.write('namespace DDSGeneric\n')
outfile.write('{\n')
outfile.write('template <typename T>\n')
outfile.write('class GenericDataWriter;\n')
outfile.write('}\n')
outfile.write('\n')
outfile.write('namespace DTS\n')
outfile.write('{\n')
outfile.write(' template<typename T> class GenericDts;\n')
outfile.write(' template<typename T> class GenericDtsImpl;\n')
outfile.write('\n')
for struct_name in sorted(parser.struct_names):
# Add ProjectName (from idl file)
topic_name = "%s::%s" % ( parser.module_name, struct_name )
dwo_name = "Dwo%s" % ( struct_name )
outfile.write(' // Topic %s\n' % ( topic_name ))
outfile.write(' // Interface\n')
outfile.write(' using %s = GenericDts<%s>;\n' % ( struct_name, topic_name ))
outfile.write(' // Interface impl\n')
outfile.write(' using %s = DDSGeneric::GenericDataWriter<%s>;\n' % ( dwo_name, topic_name ))
outfile.write(' using %sImpl = GenericDtsImpl<%s>;\n' % ( struct_name, dwo_name ))
outfile.write('\n')
outfile.write('} // namespace DTS\n')
outfile.write('\n')
class DtcGenerator(object):
def generate( self, outfile, parser ):
outputHeader( outfile, parser, 'DTC' )
outfile.write('\n')
outfile.write('/**\n')
outfile.write(' * Type definitions \n')
outfile.write(' * => DataTopicClients (DTCs)\n')
outfile.write(' */\n')
outfile.write('\n')
outfile.write('namespace DDSGeneric\n')
outfile.write('{\n')
outfile.write('template <typename T>\n')
outfile.write('class GenericDataReader;\n')
outfile.write('template <typename T>\n')
outfile.write('class GenericDataReaderContentFilter;\n')
outfile.write('class DynamicDataReader;\n')
outfile.write('}\n')
outfile.write('\n')
outfile.write('namespace DTC\n')
outfile.write('{\n')
outfile.write(' template<typename T> class GenericDtc;\n')
outfile.write(' template<typename T> class GenericDtcImpl;\n')
outfile.write(' template<typename T> class GenericDtcSampleInfo;\n')
outfile.write(' template<typename T> class GenericDtcImplSampleInfo;\n')
outfile.write('\n')
for struct_name in sorted(parser.struct_names):
# Add ProjectName (from idl file)
topic_name = "%s::%s" % ( parser.module_name, struct_name )
dro_name = "Dro%s" % ( struct_name )
dro_name_cf = "Dro%sCF" % ( struct_name )
outfile.write(' // Topic %s\n' % ( topic_name ))
outfile.write(' using %s = DDSGeneric::GenericDataReader<%s>;\n' % ( dro_name, topic_name ))
outfile.write(' using %s = GenericDtc<%s>;\n' % ( struct_name, dro_name ))
outfile.write(' using %sImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name ))
outfile.write(' using %s = DDSGeneric::GenericDataReaderContentFilter<%s>;\n' % ( dro_name_cf, topic_name ))
outfile.write(' using %sCF = GenericDtc<%s>;\n' % ( struct_name, dro_name_cf ))
outfile.write(' using %sCFImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name_cf ))
outfile.write(' namespace SampleInfo {\n')
outfile.write(' using %s = GenericDtcSampleInfo<%s>;\n' % ( struct_name, dro_name ))
outfile.write(' using %sImpl = GenericDtcImplSampleInfo<%s>;\n' % ( struct_name, dro_name ))
outfile.write(' }\n')
outfile.write('\n')
outfile.write('} // namespace DTC\n')
outfile.write('\n')
def printFtTopicTypeNames( outfile, ft_data ):
outfile.write(' template<> struct TopicNames<%s>' % ft_data.name)
outfile.write(' {\n')
outfile.write(' static constexpr const char *functionTopicName() { return "%s"; }\n' % ft_data.name)
outfile.write(' static constexpr const char *replyTopicName() { return "%s"; }\n' % ft_data.getReplyTopicName())
outfile.write(' static constexpr const char *replyTopicTypeName() { return "%s"; }\n' % ft_data.getReplyTopicNameType( True ))
outfile.write(' static constexpr const char *requestTopicName() { return "%s"; }\n' % ft_data.getRequestTopicName())
outfile.write(' static constexpr const char *requestTopicTypeName() { return "%s"; }\n' % ft_data.getRequestTopicNameType( True ))
outfile.write(' };\n')
def printFtTypedefs( outfile, ft_data ):
if ft_data.needRequestTopicTypedef():
outfile.write(' using %s = %s;\n' % ( ft_data.getRequestTopicNameType( False ), ft_data.getRequestTopicType() ))
if ft_data.needReplyTopicTypedef():
outfile.write(' using %s = %s;\n' % ( ft_data.getReplyTopicNameType( False ), ft_data.getReplyTopicType() ))
class FtsGenerator(object):
def generate( self, outfile, parser):
outputHeader( outfile, parser, 'FTS' )
outfile.write('\n')
outfile.write('namespace FTS\n')
outfile.write('{\n')
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtsImpl;\n')
outfile.write('template<typename GENERIC_FTS> struct TopicNames;\n')
outfile.write('}\n')
outfile.write('namespace %s\n' % ( parser.module_name ))
outfile.write('{\n')
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
for ft_name in sorted(parser.ft_enums):
printFtTypedefs( outfile, parser.ft_data[ft_name] )
outfile.write('} // namespace %s\n' % ( parser.module_name ))
outfile.write('\n')
outfile.write('\n')
outfile.write('namespace FTS\n')
outfile.write('{\n')
outfile.write(' // TypeDefinitions for GenericFtsImpl\n')
for ft_name in sorted(parser.ft_enums):
ft_data = parser.ft_data[ft_name]
dummy = '%sTemplateHelperDummy' % ft_data.name;
outfile.write(' class %s;\n' % dummy)
outfile.write(' using %s = GenericFtsImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
printFtTopicTypeNames( outfile, ft_data )
outfile.write('\n')
outfile.write('} // namespace FTS\n')
outfile.write('\n')
class FtcGenerator(object):
def generate( self, outfile, parser ):
outputHeader( outfile, parser, 'FTC' )
outfile.write('\n')
outfile.write('namespace FTC\n')
outfile.write('{\n')
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtcImpl;\n')
outfile.write('template<typename GENERIC_FTC> struct TopicNames;\n')
outfile.write('}\n')
outfile.write('namespace %s\n' % ( parser.module_name ))
outfile.write('{\n')
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
for ft_name in sorted(parser.ft_enums):
printFtTypedefs( outfile, parser.ft_data[ft_name] )
outfile.write('} // namespace %s\n' % ( parser.module_name ))
outfile.write('\n')
outfile.write('\n')
outfile.write('namespace FTC\n')
outfile.write('{\n')
outfile.write(' // TypeDefinitions for GenericFtcImpl\n')
for ft_name in sorted(parser.ft_enums):
ft_data = parser.ft_data[ft_name]
dummy = '%sTemplateHelperDummy' % ft_data.name;
outfile.write(' class %s;\n' % dummy)
outfile.write(' using %s = GenericFtcImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
printFtTopicTypeNames( outfile, ft_data )
outfile.write('\n')
outfile.write('} // namespace FTC\n')
outfile.write('\n')
class OperatorRights(object):
def generate( self, outfile, parser ):
outputHeader( outfile, parser, 'Operator Rights', False )
outfile.write('namespace %s \n' % parser.module_name)
outfile.write('{\n')
outfile.write(' static const int Offset = %s; \n' % parser.op_right_offset)
outfile.write('}\n\n')
outfile.write('namespace OperatorRights\n')
outfile.write('{\n')
globalOffset = parser.op_right_offset << 24
for r in parser.op_rights:
outfile.write('enum %s\n' % r.name)
outfile.write('{\n')
offsetPlugin = globalOffset + (r.offset << 16)
groupCount = -1
for group in r.groups:
groupCount = groupCount + 1
groupOffset = offsetPlugin + (groupCount << 8)
for k,v,d in group.values:
v += groupOffset
outfile.write(' %s = %s,\n' % (k, hex(v)))
outfile.write('};\n')
outfile.write('\n')
outfile.write('enum Groups_%s\n' % parser.module_name)
outfile.write('{\n')
pattern = re.compile('[\W]+')
for r in parser.op_rights:
offsetPlugin = globalOffset + (r.offset << 16)
for group in r.groups:
groupOffset = offsetPlugin + (groupCount << 8)
name = pattern.sub('', group.name)
outfile.write(' Group%s = %s,\n' % (name, hex(groupOffset)))
outfile.write('};\n')
outfile.write('\n')
outfile.write('enum Plugins_%s\n' % parser.module_name)
outfile.write('{\n')
for r in parser.op_rights:
offsetPlugin = globalOffset + (r.offset << 16)
name = pattern.sub('', r.name)
outfile.write(' Plugin%s = %s,\n' % (name, hex(offsetPlugin)))
outfile.write('};\n')
outfile.write('} // namespace OperatorRights\n')
class OperatorRightsCpp(object):
def generate( self, outfile, parser ):
outputHeader( outfile, parser, 'Operator Rights (source)', False, False )
outfile.write('#include "%s_operator_rights.h"\n' % parser.service_abbr)
outfile.write('#include <QCoreApplication>\n\n\n')
if len(parser.op_rights) == 0:
return
outfile.write('\nvoid doNothing()\n{\n const char * txt[] {\n')
disamb = 'OperatorRights'
globalOffset = parser.op_right_offset << 24
for r in parser.op_rights:
offsetPlugin = globalOffset + (r.offset << 16)
groupCount = -1
for group in r.groups:
groupCount = groupCount + 1
groupOffset = offsetPlugin + (groupCount << 8)
if group.name != '':
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.name))
if group.desc != '':
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.desc))
for aclName, aclId, aclDescr in group.values:
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, aclDescr))
outfile.write(' };\n Q_UNUSED(txt);\n}\n')
class OperatorRightsSql(object):
def generate( self, outfile, parser ):
outfile.write('BEGIN;\n')
globalOffset = parser.op_right_offset << 24
if globalOffset > 0:
outfile.write('--- Offset: %s = %s\n' % (globalOffset, hex(globalOffset)))
groupId = globalOffset;
for r in parser.op_rights:
offsetPlugin = globalOffset + (r.offset << 16)
groupCount = -1
for group in r.groups:
groupCount = groupCount + 1
groupOffset = offsetPlugin + (groupCount << 8)
outfile.write('\n--- %s - %s = %s\n' % (group.name, hex(groupOffset), groupOffset))
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 4, false);\n"
outfile.write(str % (groupOffset, group.name, group.desc))
for aclName, aclId, aclDescr in group.values:
aclId += groupOffset
outfile.write('--- Base: %s, %s - %s = %s\n' % (groupOffset, aclName, aclId, hex(aclId)))
str = "INSERT INTO opm.opm_access_control_level (id, name, description) VALUES (%s, '%s', '%s');\n";
outfile.write(str % (aclId, aclName, aclDescr));
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 1, true);\n";
outfile.write(str % (groupId, aclName, aclDescr));
str = "INSERT INTO opm.opm_acl_allow (group_id, acl_id) VALUES (%s, %s); -- group_id is: %s = %s\n";
outfile.write(str % (groupId, aclId, groupId, hex(groupId)));
str = "INSERT INTO opm.opm_group_group (group_id, is_member_of_group_id) VALUES (%s, %s); -- %s\n"
outfile.write(str % (groupOffset, groupId, group.name))
groupId = groupId + 1
outfile.write('\n')
outfile.write('END;\n')
def generate( parser, generator, out_filename ):
try:
outfile = open(out_filename, 'w')
except:
print("Could not open %s for writing" % out_filename, file=sys.stderr)
sys.exit(4)
generator.generate(outfile, parser)
outfile.close()
def usage( error ):
print(error, file=sys.stderr)
print("Usage: %s DTS|DTC|FTS|FTC|SQL <service_file.xml> <outfile> " % sys.argv[0], file=sys.stderr)
print(" %s ALL <service_file.xml> <outdir> " % sys.argv[0], file=sys.stderr)
print("i.e.: %s DTS exm_service.xml DtsTypeDefinitions.h" % sys.argv[0], file=sys.stderr)
print("call: '%s'" % " ".join(sys.argv), file=sys.stderr)
sys.exit(1)
def main():
if len(sys.argv) != 4:
usage("Invalid argument count")
option_str = sys.argv[1]
xml_filename = sys.argv[2]
parser = FileParser()
parser.build(xml_filename)
if option_str == "DTS":
generate(parser, DtsGenerator(), sys.argv[3])
elif option_str == "DTC":
generate(parser, DtcGenerator(), sys.argv[3])
elif option_str == "FTS":
generate(parser, FtsGenerator(), sys.argv[3])
elif option_str == "FTC":
generate(parser, FtcGenerator(), sys.argv[3])
elif option_str == "SQL":
out_dir = sys.argv[3]
generate(parser, OperatorRightsSql(), os.path.join(out_dir, parser.service_abbr + '_operator_rights.sql'))
elif option_str == "ALL":
out_dir = sys.argv[3]
fn = parser.service_abbr + '_%s_types.h'
generate(parser, DtsGenerator(), fn % 'dts')
generate(parser, DtcGenerator(), fn % 'dtc')
generate(parser, FtsGenerator(), fn % 'fts')
generate(parser, FtcGenerator(), fn % 'ftc')
generate(parser, OperatorRights(), parser.service_abbr + '_operator_rights.h')
generate(parser, OperatorRightsCpp(), parser.service_abbr + '_operator_rights.cpp')
else:
usage("invalid option '%s'" % option_str)
sys.exit(0)
if __name__ == "__main__":
main()