aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2018-02-26 15:48:30 +0100
committerAlexandru Croitor <alexandru.croitor@qt.io>2018-03-02 20:34:32 +0000
commitb83eb9e389b0b9501c18dcc123d1957bd7246815 (patch)
tree083055d246dc69fe149292fb1aaae7c6eed34b37
parent6c0a0d70305cd6e12260a352099e74d34f3c239e (diff)
Improve QtInfo class
Previously the class would do a qmake process invocation for each qmake -query property, after this change only a single invocation is done to get all the query properties. In addition another new invocation is done to find all mkspecs variable, in order to find what kind of Qt build is being used: a debug build, release build, or debug_and_release build. This information is useful for packaging purposes, to know which files should be copied or ignored. Change-Id: If1ee4d19e0cc550e40dc568d1256030c8928c4e5 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--qtinfo.py135
-rw-r--r--setup.py36
2 files changed, 136 insertions, 35 deletions
diff --git a/qtinfo.py b/qtinfo.py
index e85b322e2..1c95f9638 100644
--- a/qtinfo.py
+++ b/qtinfo.py
@@ -1,22 +1,26 @@
-import os, sys
-import subprocess
+import os, sys, re, subprocess
from distutils.spawn import find_executable
class QtInfo(object):
def __init__(self, qmake_command=None):
+ self.initialized = False
+
if qmake_command:
self._qmake_command = qmake_command
else:
self._qmake_command = [find_executable("qmake"),]
- self._dict = {}
- # bind all variables early at __init__ time.
- for thing in self.__class__.__dict__:
- getattr(self, thing)
+
+ # Dict to cache qmake values.
+ self._query_dict = {}
+ # Dict to cache mkspecs variables.
+ self._mkspecs_dict = {}
+ # Initialize the properties.
+ self._initProperties()
def getQMakeCommand(self):
qmake_command_string = self._qmake_command[0]
for entry in self._qmake_command[1:]:
- qmake_command_string += " %s" %(entry)
+ qmake_command_string += " {}".format(entry)
return qmake_command_string
def getVersion(self):
@@ -52,21 +56,118 @@ class QtInfo(object):
def getQmlPath(self):
return self.getProperty("QT_INSTALL_QML")
- def _getProperty(self, prop_name):
- cmd = self._qmake_command + ["-query", prop_name]
+ def getBuildType(self):
+ """ Return value is either debug, release, debug_release, or None. """
+ return self.getProperty("BUILD_TYPE")
+
+ def getSrcDir(self):
+ """ Return path to Qt src dir or None.. """
+ return self.getProperty("QT_INSTALL_PREFIX/src")
+
+ def getProperty(self, prop_name):
+ if prop_name not in self._query_dict:
+ return None
+ return self._query_dict[prop_name]
+
+ def getProperties(self):
+ return self._query_dict
+
+ def getMkspecsVariables(self):
+ return self._mkspecs_dict
+
+ def _getQMakeOutput(self, args_list = []):
+ cmd = self._qmake_command + args_list
proc = subprocess.Popen(cmd, stdout = subprocess.PIPE, shell=False)
- prop = proc.communicate()[0]
+ output = proc.communicate()[0]
proc.wait()
if proc.returncode != 0:
return None
if sys.version_info >= (3,):
- return str(prop, 'ascii').strip()
- return prop.strip()
+ output = str(output, 'ascii').strip()
+ else:
+ output = output.strip()
+ return output
+
+ def _parseQueryProperties(self, process_output):
+ props = {}
+ if not process_output:
+ return props
+ lines = [s.strip() for s in process_output.splitlines()]
+ for line in lines:
+ if line and ':' in line:
+ key, value = line.split(':', 1)
+ props[key] = value
+ return props
+
+ def _getQueryProperties(self):
+ output = self._getQMakeOutput(['-query'])
+ self._query_dict = self._parseQueryProperties(output)
+
+ def _parseQtBuildType(self):
+ key = 'QT_CONFIG'
+ if key not in self._mkspecs_dict:
+ return None
- def getProperty(self, prop_name):
- if prop_name not in self._dict:
- self._dict[prop_name] = self._getProperty(prop_name)
- return self._dict[prop_name]
+ qt_config = self._mkspecs_dict[key]
+ if 'debug_and_release' in qt_config:
+ return 'debug_and_release'
+
+ split = qt_config.split(' ')
+ if 'release' in split and 'debug' in split:
+ return 'debug_and_release'
+
+ if 'release' in split:
+ return 'release'
+
+ if 'debug' in split:
+ return 'debug'
+
+ return None
+
+ def _getOtherProperties(self):
+ # Get the src property separately, because it is not returned by qmake unless explicitly
+ # specified.
+ key = 'QT_INSTALL_PREFIX/src'
+ result = self._getQMakeOutput(['-query', key])
+ self._query_dict[key] = result
+
+ # Get mkspecs variables and cache them.
+ self._getQMakeMkspecsVariables()
+
+ # Figure out how Qt was built: debug mode, release mode, or both.
+ build_type = self._parseQtBuildType()
+ if build_type:
+ self._query_dict['BUILD_TYPE'] = build_type
+
+ def _initProperties(self):
+ self._getQueryProperties()
+ self._getOtherProperties()
+
+ def _getQMakeMkspecsVariables(self):
+ # Create empty temporary qmake project file.
+ temp_file_name = 'qmake_fake_empty_project.txt'
+ open(temp_file_name, 'a').close()
+
+ # Query qmake for all of its mkspecs variables.
+ qmakeOutput = self._getQMakeOutput(['-E', temp_file_name])
+ lines = [s.strip() for s in qmakeOutput.splitlines()]
+ pattern = re.compile(r"^(.+?)=(.+?)$")
+ for line in lines:
+ found = pattern.search(line)
+ if found:
+ key = found.group(1).strip()
+ value = found.group(2).strip()
+ self._mkspecs_dict[key] = value
+
+ # We need to clean up after qmake, which always creates a .qmake.stash file after a -E
+ # invocation.
+ qmake_stash_file = os.path.join(os.getcwd(), ".qmake.stash")
+ if os.path.exists(qmake_stash_file):
+ os.remove(qmake_stash_file)
+
+ # Also clean up the temporary empty project file.
+ if os.path.exists(temp_file_name):
+ os.remove(temp_file_name)
version = property(getVersion)
bins_dir = property(getBinsPath)
@@ -80,3 +181,5 @@ class QtInfo(object):
headers_dir = property(getHeadersPath)
docs_dir = property(getDocsPath)
qml_dir = property(getQmlPath)
+ build_type = property(getBuildType)
+ src_dir = property(getSrcDir)
diff --git a/setup.py b/setup.py
index eb7b1646e..8bbbd8eaf 100644
--- a/setup.py
+++ b/setup.py
@@ -471,6 +471,18 @@ def prepareSubModules():
print("Submodule %s has branch %s checked out" % (module_name, module_version))
os.chdir(script_dir)
+# Single global instance of QtInfo to be used later in multiple code paths.
+qtinfo = QtInfo(QMAKE_COMMAND)
+
+def get_qt_version():
+ qt_version = qtinfo.version
+
+ if not qt_version:
+ log.error("Failed to query the Qt version with qmake %s" % self.qtinfo.qmake_command)
+ sys.exit(1)
+
+ return qt_version
+
def prepareBuild():
if os.path.isdir(".git") and not OPTION_IGNOREGIT and not OPTION_ONLYPACKAGE and not OPTION_REUSE_BUILD:
prepareSubModules()
@@ -490,24 +502,10 @@ def prepareBuild():
pkg_dir = os.path.join(script_dir, pkg)
os.makedirs(pkg_dir)
# locate Qt sources for the documentation
- qmakeOutput = run_process_output([OPTION_QMAKE, '-query', 'QT_INSTALL_PREFIX/src'])
- if qmakeOutput:
+ qt_src_dir = qtinfo.src_dir
+ if qt_src_dir:
global qtSrcDir
- qtSrcDir = qmakeOutput[0].rstrip()
-
-def get_qt_version(computed_qtinfo = None):
- if not computed_qtinfo:
- qtinfo = QtInfo(QMAKE_COMMAND)
- else:
- qtinfo = computed_qtinfo
-
- qt_version = qtinfo.version
-
- if not qt_version:
- log.error("Failed to query the Qt version with qmake %s" % self.qtinfo.qmake_command)
- sys.exit(1)
-
- return qt_version
+ qtSrcDir = qt_src_dir
class pyside_install(_install):
def __init__(self, *args, **kwargs):
@@ -817,9 +815,9 @@ class pyside_build(_build):
log.error("Failed to locate a dynamic Python library, using %s"
% py_library)
- self.qtinfo = QtInfo(QMAKE_COMMAND)
+ self.qtinfo = qtinfo
qt_dir = os.path.dirname(OPTION_QMAKE)
- qt_version = get_qt_version(self.qtinfo)
+ qt_version = get_qt_version()
# Update the PATH environment variable
update_env_path([py_scripts_dir, qt_dir])