mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-03-15 04:55:00 +00:00

In a Qt application, the QApplication object should be the first QObject that is created. However, the `Meta` class used to have a static member called `mp`, which means that this member gets initialized _before_ main() runs and therefore before the QApplication is created. This has caused an "Invalid nullptr in QObject::connect" warning somewhere in Qt's internals (since the move to Qt 6). The impact of this warning is unclear at this point. This commit makes the mp parameter a std::unique_ptr that gets explicitly initialized in the main function (more or less right after the QApplication object is created). This guarantees that the MetaParams object does not get created before the QApplication object, fixing the observed warning. It is worth noting that we do have a couple of other static QObject variables in the main translation unit, but these seem to be inconsequential (at least they don't seem to trigger a similar warning). Fixes #6669
202 lines
8.3 KiB
Python
Executable file
202 lines
8.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
# Copyright The Mumble Developers. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license
|
|
# that can be found in the LICENSE file at the root of the
|
|
# Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
|
|
import argparse
|
|
import re
|
|
from datetime import datetime
|
|
import os
|
|
|
|
def comment_remover(text):
|
|
def replacer(match):
|
|
s = match.group(0)
|
|
if s.startswith('/'):
|
|
return ""
|
|
else:
|
|
return s
|
|
pattern = re.compile(
|
|
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
|
|
re.DOTALL | re.MULTILINE
|
|
)
|
|
return re.sub(pattern, replacer, text)
|
|
|
|
def fix_lineEnding(text):
|
|
# Convert from Windows to Unix
|
|
text = text.replace("\r\n", "\n")
|
|
# Convert from old Mac to Unix
|
|
text = text.replace("\r", "\n")
|
|
|
|
return text
|
|
|
|
def create_disclaimerComment():
|
|
return "// This file was auto-generated by scripts/generateIceWrapper.py on " + datetime.now().strftime("%Y-%m-%d") + " -- DO NOT EDIT MANUALLY!\n"
|
|
|
|
def generateFunction(className, functionName, wrapArgs, callArgs):
|
|
function = "void ::MumbleServer::" + className + "I::" + functionName + "_async(" + (", ".join(wrapArgs)) + ") {\n"
|
|
function += "\t// qWarning() << \"" + functionName + "\" << ::Meta::mp->qsIceSecretRead.isNull() << ::Meta::mp->qsIceSecretRead.isEmpty();\n"
|
|
function += "#ifndef ACCESS_" + className + "_" + functionName + "_ALL\n"
|
|
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
|
|
function += "\tif (!::Meta::mp->qsIceSecretRead.isNull()) {\n"
|
|
function += "\t\tbool ok = !::Meta::mp->qsIceSecretRead.isEmpty();\n"
|
|
function += "#\telse\n"
|
|
function += "\tif (!::Meta::mp->qsIceSecretRead.isNull() || !::Meta::mp->qsIceSecretWrite.isNull()) {\n"
|
|
function += "\t\tbool ok = !::Meta::mp->qsIceSecretWrite.isEmpty();\n"
|
|
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
|
|
function += "\t\t::Ice::Context::const_iterator i = current.ctx.find(\"secret\");\n"
|
|
function += "\t\tok = ok && (i != current.ctx.end());\n"
|
|
function += "\t\tif (ok) {\n"
|
|
function += "\t\t\tconst QString &secret = u8((*i).second);\n"
|
|
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
|
|
function += "\t\t\tok = ((secret == ::Meta::mp->qsIceSecretRead) || (secret == ::Meta::mp->qsIceSecretWrite));\n"
|
|
function += "#\telse\n"
|
|
function += "\t\t\tok = (secret == ::Meta::mp->qsIceSecretWrite);\n"
|
|
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
|
|
function += "\t\t}\n"
|
|
function += "\n"
|
|
function += "\t\tif (!ok) {\n"
|
|
function += "\t\t\tcb->ice_exception(InvalidSecretException());\n"
|
|
function += "\t\t\treturn;\n"
|
|
function += "\t\t}\n"
|
|
function += "\t}\n"
|
|
function += "#endif // ACCESS_" + className + "_" + functionName + "_ALL\n"
|
|
function += "\n"
|
|
function += "\tExecEvent *ie = new ExecEvent(boost::bind(&impl_" + className + "_" + functionName + ", " + ", ".join(callArgs) + "));\n"
|
|
function += "\tQCoreApplication::instance()->postEvent(mi, ie);\n"
|
|
function += "}\n"
|
|
|
|
return function
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Generates the wrapper files needed for the ICE server-interface")
|
|
parser.add_argument("-i", "--ice-file", help="Path to the ICE specification file (*.ice)", metavar="PATH")
|
|
parser.add_argument("-g", "--generated-ice-header", help="Path to the header file that was generated by ICE", metavar="PATH")
|
|
parser.add_argument("-o", "--out-file", help="Path to the file to write the generated output to. If omitted, the content will be written to std::out", metavar="PATH")
|
|
parser.add_argument("-q", "--quiet", action="store_true", help="Don't display used file paths")
|
|
|
|
args = parser.parse_args()
|
|
|
|
scriptPath = os.path.realpath(__file__)
|
|
rootDir = os.path.dirname(os.path.dirname(scriptPath))
|
|
|
|
if args.ice_file is None:
|
|
# Try to figure out the path to the ice-file (MumbleServer.ice)
|
|
args.ice_file = os.path.join(rootDir, "src", "murmur", "MumbleServer.ice")
|
|
if args.generated_ice_header is None:
|
|
# Try to figure out path to the generated header file (in the build dir)
|
|
args.generated_ice_header = os.path.join(rootDir, "build", "src", "murmur", "MumbleServer.h")
|
|
|
|
if not args.quiet:
|
|
print("Using ICE-file at \"%s\"" % args.ice_file)
|
|
print("Using ICE-generated header file at \"%s\"" % args.generated_ice_header)
|
|
|
|
|
|
iceSpec = fix_lineEnding(open(args.ice_file, "r").read())
|
|
generatedIceHeader = fix_lineEnding(open(args.generated_ice_header, "r").read())
|
|
|
|
# remove comments from the iceSpec
|
|
iceSpec = comment_remover(iceSpec)
|
|
# Remove all tabs from iceSpec
|
|
iceSpec = iceSpec.replace("\t", "")
|
|
# Remove empty lines form iceSpec
|
|
iceSpec = iceSpec.replace("\n\n", "\n")
|
|
|
|
# Escape all special characters so that iceSpec can be used in a std::string ctor
|
|
iceSpec = iceSpec.replace("\"", "\\\"") # quotes
|
|
iceSpec = iceSpec.replace("\n", "\\n") # newlines
|
|
|
|
wrapperContent = create_disclaimerComment()
|
|
|
|
# Include boost-bind as we'll need it later
|
|
wrapperContent += "\n#include <boost/bind/bind.hpp>\n\n"
|
|
|
|
|
|
className = ""
|
|
for currentLine in generatedIceHeader.split("\n"):
|
|
currentLine = currentLine.strip()
|
|
|
|
if not currentLine:
|
|
# Skip empty lines
|
|
continue
|
|
|
|
# find class name
|
|
match = re.match(r"^class\s+AMD_(.+)\s+:\s+(?:public\svirtual|virtual\s+public)\s+::Ice(?:::AMDCallback|Util::Shared)", currentLine)
|
|
if match:
|
|
className = "AMD_" + match.group(1)
|
|
|
|
match = re.match(r"virtual\s+void\s+ice_response\\((.*)\\)\s+=\s+0;", currentLine)
|
|
if match:
|
|
if not className:
|
|
raise RuntimeError("Expected a className to be found at this time")
|
|
match = re.match(r"virtual\s+void\s+(.+)_async\(const\s+(.+?)&\s*\w*,(.*)\s+const\s+::Ice::Current&", currentLine)
|
|
if match:
|
|
functionName = match.group(1)
|
|
objectName = match.group(2)
|
|
arguments = match.group(3)
|
|
|
|
if functionName == "getSlice":
|
|
# getSlice is handled separately
|
|
continue
|
|
|
|
targetClass = "Server" if "AMD_Server" in objectName else "Meta"
|
|
|
|
wrapArgs = []
|
|
callArgs = []
|
|
argIndex = 0
|
|
|
|
wrapArgs.append("const %s &cb" % objectName)
|
|
callArgs.append("cb")
|
|
|
|
if targetClass == "Server":
|
|
callArgs.append("QString::fromStdString(current.id.name).toInt()")
|
|
else:
|
|
callArgs.append("current.adapter")
|
|
|
|
for currentArg in arguments.split(","):
|
|
if not currentArg:
|
|
# skip empty entries
|
|
continue
|
|
|
|
parts = currentArg.split()
|
|
if len(parts) > 1:
|
|
lastPart = parts[len(parts) - 1]
|
|
|
|
if not ":" in lastPart and not "&" in lastPart:
|
|
# Omit the last part as it is only a parameter name. We however want the parameters
|
|
# to be named p1, p2, ... which we'll do below
|
|
currentArg = " ".join(parts[:len(parts) - 1])
|
|
|
|
if len(currentArg.split()) == 1 and currentArg == "const":
|
|
# Failsafe in order for us to not only leave const as the type
|
|
# We have to include lastPart after all
|
|
currentArg += " " + lastPart
|
|
|
|
argIndex += 1
|
|
wrapArgs.append("%s p%d" % (currentArg, argIndex))
|
|
callArgs.append("p%d" % argIndex)
|
|
|
|
wrapArgs.append("const ::Ice::Current ¤t")
|
|
|
|
wrapperContent += generateFunction(targetClass, functionName, wrapArgs, callArgs) + "\n"
|
|
|
|
|
|
wrapperContent += "void ::MumbleServer::MetaI::getSlice_async(const ::MumbleServer::AMD_Meta_getSlicePtr &cb, const Ice::Current&) {\n"
|
|
wrapperContent += "\tcb->ice_response(std::string(\"" + iceSpec + "\"));\n"
|
|
wrapperContent += "}\n"
|
|
|
|
|
|
if args.out_file is None:
|
|
# Write to std::out
|
|
print(wrapperContent)
|
|
else:
|
|
# Write to file
|
|
outFile = open(args.out_file, "w")
|
|
outFile.write(wrapperContent)
|
|
|
|
|
|
|
|
main()
|