refactor(tools): Simplify code generation in nodeset injector

This commit is contained in:
Noel Graf 2025-05-06 13:01:08 +02:00 committed by Julius Pfrommer
parent eedd7e8998
commit 2f80c19b85
3 changed files with 43 additions and 154 deletions

View File

@ -1273,8 +1273,6 @@ add_custom_target(open62541-code-generation DEPENDS open62541-generator-types
open62541-generator-namespace)
# Generate Nodeset injector source files
# TODO: Forward UA_INFORMATION_MODEL_AUTOLOAD to generate_nodesetinjector.py, so
# it knows which nodesets to load
if(UA_ENABLE_NODESET_INJECTOR)
message(STATUS "Nodesetinjector feature enabled")
set(UA_NODESETINJECTOR_SOURCE_FILES "") # List is appended from within ua_generate_nodeset

View File

@ -10,8 +10,12 @@ import argparse
parser = argparse.ArgumentParser()
parser.add_argument('outfile', help='outfile w/o extension')
parser.add_argument('nodesets', nargs='+', help='List of Nodesets')
args = parser.parse_args()
# Normalize to lower case letters
nodesets = [ns.lower().replace('-', '_') for ns in args.nodesets]
fh = open(args.outfile + ".h", "w", encoding='utf8')
fc = open(args.outfile + ".c", "w", encoding='utf8')
@ -52,14 +56,48 @@ printc('''
* Any manual changes will be overwritten. */
#include "nodesetinjector.h"
//<
''')
# Includes for each nodeset
for ns in nodesets:
printc(f'#include <open62541/namespace_{ns}_generated.h>')
# Special case: PADIM requires IRDI beforehand
if 'padim' in nodesets:
printc('#include <open62541/namespace_irdi_generated.h>')
printc('''
UA_StatusCode UA_Server_injectNodesets(UA_Server *server) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Attaching the AUTOLOAD Nodesets to the server!");
//>
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Attaching the AUTOLOAD Nodesets to the server!");
''')
return retval;
# Function calls for each nodeset
for ns in nodesets:
# Special handling: Insert IRDI before PADIM
if ns == 'padim':
printc('''
/* namespace_irdi_generated */
retval |= namespace_irdi_generated(server);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the namespace_irdi_generated failed. Please check previous error output.");
return retval;
}
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The namespace_irdi_generated successfully added.");
''')
printc(f'''
/* namespace_{ns}_generated */
retval |= namespace_{ns}_generated(server);
if(retval != UA_STATUSCODE_GOOD) {{
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the namespace_{ns}_generated failed. Please check previous error output.");
return retval;
}}
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The namespace_{ns}_generated successfully added.");
''')
printc('''
return retval;
}
''')

View File

@ -1,147 +0,0 @@
#!/usr/bin/env python3
### This Source Code Form is subject to the terms of the Mozilla Public
### License, v. 2.0. If a copy of the MPL was not distributed with this
### file, You can obtain one at http://mozilla.org/MPL/2.0/.
### Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
import argparse
import re
import os
import platform
parser = argparse.ArgumentParser()
parser.add_argument('outfile', help='outfile w/o extension')
parser.add_argument('namespace', help='namespace')
args = parser.parse_args()
include_line_counter = 0
code_line_counter = 0
existing_namespaces = []
data = []
def is_unix():
try:
# Check if the os.uname() function is available
os.uname()
return True
except:
return False
def windows_exec():
import msvcrt
global include_line_counter
global code_line_counter
global existing_namespaces
global data
# Open the file in read-write mode
with open(args.outfile + ".c", "r+", encoding='utf8') as file:
# Lock the file
msvcrt.locking(file.fileno(), msvcrt.LK_LOCK, 1)
# Write to the file
write_code_generation(file)
# Unlock the file
msvcrt.locking(file.fileno(), msvcrt.LK_UNLCK, 1)
def unix_exec():
import fcntl
global include_line_counter
global code_line_counter
global existing_namespaces
global data
with open(args.outfile + ".c", "r+", encoding='utf8') as file:
# Acquire a lock on the file
fcntl.flock(file, fcntl.LOCK_EX)
# Write to the file
write_code_generation(file)
# Release the lock on the file
fcntl.flock(file, fcntl.LOCK_UN)
def print_include(string):
data[include_line_counter] = string
def print_function_call(string):
data[code_line_counter] = string
def generate_code():
#########################
# Print the header file #
#########################
print_include('''
#include <open62541/{namespace}.h>
//<
'''.format(namespace=args.namespace))
#########################
# Print the source file #
#########################
print_function_call('''
/* {namespace} */
retval |= {namespace}(server);
if(retval != UA_STATUSCODE_GOOD) {{
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the {namespace} failed. Please check previous error output.");
return retval;
}}
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The {namespace} successfully added.");
//>
'''.format(namespace=args.namespace))
def write_code_generation(file):
global include_line_counter
global code_line_counter
global existing_namespaces
global data
# Write to the file
lines = file.readlines()
line_counter = 0
# List which contains the existing namespaces
existing_namespaces = []
for line in lines:
namespaces = re.findall(r"namespace_.*_generated\(.*\)", line)
if namespaces:
namespaces = namespaces[0].split("(")[0]
existing_namespaces.append(namespaces)
if re.search("//<", line):
include_line_counter = line_counter
if re.search("//>", line):
code_line_counter = line_counter
line_counter += 1
if args.namespace not in existing_namespaces:
# Set the file descriptor to the beginning of the file
file.seek(0)
# read a list of lines into data
data = file.readlines()
generate_code()
# Set the file descriptor to the beginning of the file and delete content
file.seek(0)
file.truncate(0)
file.writelines(data)
if platform.system == "Linux":
unix_exec()
else:
if is_unix():
unix_exec()
else:
windows_exec()