Browse Source

DatatypeGenerator: Allow to import additional types as dependency

Fixes #2896

Exemplary call for GDS:

```
    # Generate types and namespace for GDS
    ua_generate_datatypes(
        NAME "types_gds"
        TARGET_SUFFIX "types-gds"
        NAMESPACE_IDX 0
        FILE_CSV "${FILE_NS_DIRPREFIX}/GDS/OpcUaGdsModel.csv"
        FILES_BSD "${FILE_NS_DIRPREFIX}/GDS/Opc.Ua.Gds.Types.bsd"
        IMPORT_BSD "UA_TYPES#${FILE_NS_DIRPREFIX}/Schema/Opc.Ua.Types.bsd"
    )
```
Stefan Profanter 4 years ago
parent
commit
6418309cf5
2 changed files with 38 additions and 6 deletions
  1. 11 1
      tools/cmake/macros_public.cmake
  2. 27 5
      tools/generate_datatypes.py

+ 11 - 1
tools/cmake/macros_public.cmake

@@ -98,6 +98,10 @@ endfunction()
 #
 #   FILES_BSD        Path to the .bsd file containing the type definitions, e.g. 'Opc.Ua.Di.Types.bsd'. Multiple files can be
 #                   passed which will all combined to one resulting code.
+#   IMPORT_BSD      Combination of types array and path to the .bsd file containing additional type definitions referenced by
+#                   the FILES_BSD files. The value is separated with a hash sign, i.e.
+#                   'UA_TYPES#${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.Types.bsd'
+#                   Multiple files can be passed which will all be imported.
 #   [FILES_SELECTED] Optional path to a simple text file which contains a list of types which should be included in the generation.
 #                   The file should contain one type per line. Multiple files can be passed to this argument.
 #
@@ -105,7 +109,7 @@ endfunction()
 function(ua_generate_datatypes)
     set(options BUILTIN INTERNAL)
     set(oneValueArgs NAME TARGET_SUFFIX TARGET_PREFIX NAMESPACE_IDX OUTPUT_DIR FILE_CSV)
-    set(multiValueArgs FILES_BSD FILES_SELECTED)
+    set(multiValueArgs FILES_BSD IMPORT_BSD FILES_SELECTED)
     cmake_parse_arguments(UA_GEN_DT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
 
     if(NOT DEFINED open62541_TOOLS_DIR)
@@ -160,6 +164,11 @@ function(ua_generate_datatypes)
         set(BSD_FILES_TMP ${BSD_FILES_TMP} "--type-bsd=${f}")
     endforeach()
 
+    set(IMPORT_BSD_TMP "")
+    foreach(f ${UA_GEN_DT_IMPORT_BSD})
+        set(IMPORT_BSD_TMP ${IMPORT_BSD_TMP} "--import=${f}")
+    endforeach()
+
     # Make sure that the output directory exists
     if(NOT EXISTS ${UA_GEN_DT_OUTPUT_DIR})
         file(MAKE_DIRECTORY ${UA_GEN_DT_OUTPUT_DIR})
@@ -177,6 +186,7 @@ function(ua_generate_datatypes)
         --namespace=${UA_GEN_DT_NAMESPACE_IDX}
         ${SELECTED_TYPES_TMP}
         ${BSD_FILES_TMP}
+        ${IMPORT_BSD_TMP}
         --type-csv=${UA_GEN_DT_FILE_CSV}
         ${UA_GEN_DT_NO_BUILTIN}
         ${UA_GEN_DT_INTERNAL_ARG}

+ 27 - 5
tools/generate_datatypes.py

@@ -19,6 +19,7 @@ import json
 from nodeset_compiler.opaque_type_mapping import get_base_type_for_opaque as get_base_type_for_opaque_ns0
 
 types = OrderedDict() # contains types that were already parsed
+types_imported = OrderedDict() # contains types that were already parsed and marked as imported types (do not write to source code)
 typedescriptions = {} # contains type nodeids
 user_opaque_type_mapping = {} # contains user defined opaque type mapping
 
@@ -317,7 +318,7 @@ class StructType(Type):
 # Parse Typedefinitions #
 #########################
 
-def parseTypeDefinitions(outname, xmlDescription, namespace):
+def parseTypeDefinitions(outname, xmlDescription, namespace, addToTypes=None):
     def typeReady(element):
         "Are all member types defined?"
         for child in element:
@@ -364,15 +365,20 @@ def parseTypeDefinitions(outname, xmlDescription, namespace):
             if not typeReady(typeXml):
                 continue
             if name in builtin_types:
-                types[name] = BuiltinType(name)
+                newType = BuiltinType(name)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-                types[name] = EnumerationType(outname, typeXml, namespace)
+                newType = EnumerationType(outname, typeXml, namespace)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-                types[name] = OpaqueType(outname, typeXml, namespace, get_base_type_for_opaque(name)['name'])
+                newType = OpaqueType(outname, typeXml, namespace, get_base_type_for_opaque(name)['name'])
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-                types[name] = StructType(outname, typeXml, namespace)
+                newType = StructType(outname, typeXml, namespace)
             else:
                 raise Exception("Type not known")
+
+            types[name] = newType
+            if addToTypes is not None:
+                addToTypes[name] = newType
+
             del snippets[name]
 
 ##########################
@@ -492,6 +498,14 @@ parser.add_argument('-t', '--type-bsd',
                     default=[],
                     help='bsd file with type definitions')
 
+parser.add_argument('-i', '--import',
+                    metavar="<importBsds>",
+                    type=str,
+                    dest="import_bsd",
+                    action='append',
+                    default=[],
+                    help='combination of TYPE_ARRAY#filepath.bsd with type definitions which should be loaded but not exported/generated')
+
 parser.add_argument('outfile',
                     metavar='<outputFile>',
                     help='output file w/o extension')
@@ -512,6 +526,13 @@ for builtin in builtin_types:
 for f in args.opaque_map:
     user_opaque_type_mapping.update(json.load(f))
 
+for i in args.import_bsd:
+    (outname_import, file_import) = i.split("#")
+    outname_import = outname_import.lower()
+    if outname_import.startswith("ua_"):
+        outname_import = outname_import[3:]
+    parseTypeDefinitions(outname_import, file_import, args.namespace, addToTypes=types_imported)
+
 for f in args.type_bsd:
     parseTypeDefinitions(outname, f, args.namespace)
 
@@ -554,6 +575,7 @@ def iter_types(v):
         l = list(filter(lambda t: t.name in selected_types, l))
     if args.no_builtin:
         l = list(filter(lambda t: type(t) != BuiltinType, l))
+    l = list(filter(lambda t: t.name not in types_imported, l))
     return l
 
 ################