qt4, qt5 modules: Improve moc/uic/rcc detection
Instead of blindly searching in PATH, use Qt5Dependency.compilers_detect() (same for qt4) to get moc/uic/rcc. This is much more robust, and it improves the chances that the correct ones will be found. We still manually verify for now because the fallback in dependencies.py for searching is stll to look in PATH for backwards-compat, and because people probably have setups like that. Also sync the qt4 module with the qt5 module w.r.t. resource compilation and make the compiled qrc.cpp file unique in terms of the framework version used (4 vs 5). This is needed for the test to work properly, which now covers both Qt4 and 5.
This commit is contained in:
parent
a72740a0d1
commit
19a06d9033
|
@ -12,26 +12,27 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from .. import dependencies, mlog
|
|
||||||
import os, subprocess
|
import os, subprocess
|
||||||
|
from .. import mlog
|
||||||
from .. import build
|
from .. import build
|
||||||
from ..mesonlib import MesonException
|
from ..mesonlib import MesonException
|
||||||
|
from ..dependencies import Qt4Dependency
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
class Qt4Module():
|
class Qt4Module():
|
||||||
def __init__(self):
|
tools_detected = False
|
||||||
mlog.log('Detecting Qt tools.')
|
|
||||||
# The binaries have different names on different
|
def _detect_tools(self, env):
|
||||||
# distros. Joy.
|
if self.tools_detected:
|
||||||
self.moc = dependencies.ExternalProgram('moc-qt4', silent=True)
|
return
|
||||||
if not self.moc.found():
|
mlog.log('Detecting Qt4 tools')
|
||||||
self.moc = dependencies.ExternalProgram('moc', silent=True)
|
# FIXME: We currently require Qt4 to exist while importing the module.
|
||||||
self.uic = dependencies.ExternalProgram('uic-qt4', silent=True)
|
# We should make it gracefully degrade and not create any targets if
|
||||||
if not self.uic.found():
|
# the import is marked as 'optional' (not implemented yet)
|
||||||
self.uic = dependencies.ExternalProgram('uic', silent=True)
|
kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true'}
|
||||||
self.rcc = dependencies.ExternalProgram('rcc-qt4', silent=True)
|
qt4 = Qt4Dependency(env, kwargs)
|
||||||
if not self.rcc.found():
|
# Get all tools and then make sure that they are the right version
|
||||||
self.rcc = dependencies.ExternalProgram('rcc', silent=True)
|
self.moc, self.uic, self.rcc = qt4.compilers_detect()
|
||||||
# Moc, uic and rcc write their version strings to stderr.
|
# Moc, uic and rcc write their version strings to stderr.
|
||||||
# Moc and rcc return a non-zero result when doing so.
|
# Moc and rcc return a non-zero result when doing so.
|
||||||
# What kind of an idiot thought that was a good idea?
|
# What kind of an idiot thought that was a good idea?
|
||||||
|
@ -80,6 +81,7 @@ class Qt4Module():
|
||||||
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
|
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
|
||||||
else:
|
else:
|
||||||
mlog.log(' rcc:', mlog.red('NO'))
|
mlog.log(' rcc:', mlog.red('NO'))
|
||||||
|
self.tools_detected = True
|
||||||
|
|
||||||
def parse_qrc(self, state, fname):
|
def parse_qrc(self, state, fname):
|
||||||
abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
|
abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
|
||||||
|
@ -115,6 +117,7 @@ class Qt4Module():
|
||||||
if not isinstance(srctmp, list):
|
if not isinstance(srctmp, list):
|
||||||
srctmp = [srctmp]
|
srctmp = [srctmp]
|
||||||
sources = args[1:] + srctmp
|
sources = args[1:] + srctmp
|
||||||
|
self._detect_tools(state.environment)
|
||||||
err_msg = "{0} sources specified and couldn't find {1}, " \
|
err_msg = "{0} sources specified and couldn't find {1}, " \
|
||||||
"please check your qt4 installation"
|
"please check your qt4 installation"
|
||||||
if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
|
if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
|
||||||
|
@ -122,16 +125,18 @@ class Qt4Module():
|
||||||
if len(rcc_files) > 0:
|
if len(rcc_files) > 0:
|
||||||
if not self.rcc.found():
|
if not self.rcc.found():
|
||||||
raise MesonException(err_msg.format('RCC', 'rcc-qt4'))
|
raise MesonException(err_msg.format('RCC', 'rcc-qt4'))
|
||||||
rcc_kwargs = {'output' : '@BASENAME@.cpp',
|
|
||||||
'arguments' : ['@INPUT@', '-o', '@OUTPUT@']}
|
|
||||||
rcc_gen = build.Generator([self.rcc], rcc_kwargs)
|
|
||||||
rcc_output = build.GeneratedList(rcc_gen)
|
|
||||||
qrc_deps = []
|
qrc_deps = []
|
||||||
for i in rcc_files:
|
for i in rcc_files:
|
||||||
qrc_deps += self.parse_qrc(state, i)
|
qrc_deps += self.parse_qrc(state, i)
|
||||||
rcc_output.extra_depends = qrc_deps
|
basename = os.path.split(rcc_files[0])[1]
|
||||||
[rcc_output.add_file(os.path.join(state.subdir, a)) for a in rcc_files]
|
name = 'qt4-' + basename.replace('.', '_')
|
||||||
sources.append(rcc_output)
|
rcc_kwargs = {'input' : rcc_files,
|
||||||
|
'output' : name + '.cpp',
|
||||||
|
'command' : [self.rcc, '-o', '@OUTPUT@', '@INPUT@'],
|
||||||
|
'depend_files' : qrc_deps,
|
||||||
|
}
|
||||||
|
res_target = build.CustomTarget(name, state.subdir, rcc_kwargs)
|
||||||
|
sources.append(res_target)
|
||||||
if len(ui_files) > 0:
|
if len(ui_files) > 0:
|
||||||
if not self.uic.found():
|
if not self.uic.found():
|
||||||
raise MesonException(err_msg.format('UIC', 'uic-qt4'))
|
raise MesonException(err_msg.format('UIC', 'uic-qt4'))
|
||||||
|
|
|
@ -12,27 +12,27 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from .. import dependencies, mlog
|
|
||||||
import os, subprocess
|
import os, subprocess
|
||||||
|
from .. import mlog
|
||||||
from .. import build
|
from .. import build
|
||||||
from ..mesonlib import MesonException
|
from ..mesonlib import MesonException
|
||||||
|
from ..dependencies import Qt5Dependency
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
class Qt5Module():
|
class Qt5Module():
|
||||||
|
tools_detected = False
|
||||||
|
|
||||||
def __init__(self):
|
def _detect_tools(self, env):
|
||||||
mlog.log('Detecting Qt tools.')
|
if self.tools_detected:
|
||||||
# The binaries have different names on different
|
return
|
||||||
# distros. Joy.
|
mlog.log('Detecting Qt5 tools')
|
||||||
self.moc = dependencies.ExternalProgram('moc-qt5', silent=True)
|
# FIXME: We currently require Qt5 to exist while importing the module.
|
||||||
if not self.moc.found():
|
# We should make it gracefully degrade and not create any targets if
|
||||||
self.moc = dependencies.ExternalProgram('moc', silent=True)
|
# the import is marked as 'optional' (not implemented yet)
|
||||||
self.uic = dependencies.ExternalProgram('uic-qt5', silent=True)
|
kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true'}
|
||||||
if not self.uic.found():
|
qt5 = Qt5Dependency(env, kwargs)
|
||||||
self.uic = dependencies.ExternalProgram('uic', silent=True)
|
# Get all tools and then make sure that they are the right version
|
||||||
self.rcc = dependencies.ExternalProgram('rcc-qt5', silent=True)
|
self.moc, self.uic, self.rcc = qt5.compilers_detect()
|
||||||
if not self.rcc.found():
|
|
||||||
self.rcc = dependencies.ExternalProgram('rcc', silent=True)
|
|
||||||
# Moc, uic and rcc write their version strings to stderr.
|
# Moc, uic and rcc write their version strings to stderr.
|
||||||
# Moc and rcc return a non-zero result when doing so.
|
# Moc and rcc return a non-zero result when doing so.
|
||||||
# What kind of an idiot thought that was a good idea?
|
# What kind of an idiot thought that was a good idea?
|
||||||
|
@ -87,6 +87,7 @@ class Qt5Module():
|
||||||
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
|
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
|
||||||
else:
|
else:
|
||||||
mlog.log(' rcc:', mlog.red('NO'))
|
mlog.log(' rcc:', mlog.red('NO'))
|
||||||
|
self.tools_detected = True
|
||||||
|
|
||||||
def parse_qrc(self, state, fname):
|
def parse_qrc(self, state, fname):
|
||||||
abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
|
abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
|
||||||
|
@ -122,6 +123,7 @@ class Qt5Module():
|
||||||
if not isinstance(srctmp, list):
|
if not isinstance(srctmp, list):
|
||||||
srctmp = [srctmp]
|
srctmp = [srctmp]
|
||||||
sources = args[1:] + srctmp
|
sources = args[1:] + srctmp
|
||||||
|
self._detect_tools(state.environment)
|
||||||
err_msg = "{0} sources specified and couldn't find {1}, " \
|
err_msg = "{0} sources specified and couldn't find {1}, " \
|
||||||
"please check your qt5 installation"
|
"please check your qt5 installation"
|
||||||
if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
|
if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
|
||||||
|
@ -138,9 +140,8 @@ class Qt5Module():
|
||||||
'command' : [self.rcc, '-o', '@OUTPUT@', '@INPUT@'],
|
'command' : [self.rcc, '-o', '@OUTPUT@', '@INPUT@'],
|
||||||
'depend_files' : qrc_deps,
|
'depend_files' : qrc_deps,
|
||||||
}
|
}
|
||||||
res_target = build.CustomTarget(basename.replace('.', '_'),
|
name = 'qt5-' + basename.replace('.', '_')
|
||||||
state.subdir,
|
res_target = build.CustomTarget(name, state.subdir, rcc_kwargs)
|
||||||
rcc_kwargs)
|
|
||||||
sources.append(res_target)
|
sources.append(res_target)
|
||||||
if len(ui_files) > 0:
|
if len(ui_files) > 0:
|
||||||
if not self.uic.found():
|
if not self.uic.found():
|
||||||
|
|
|
@ -1,41 +1,45 @@
|
||||||
project('qt5 build test', 'cpp')
|
project('qt4 and 5 build test', 'cpp')
|
||||||
|
|
||||||
qt5 = import('qt5')
|
foreach qt : ['qt4', 'qt5']
|
||||||
qt5dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets'])
|
qtdep = dependency(qt, modules : ['Core', 'Gui', 'Widgets'], required : qt == 'qt5')
|
||||||
|
if qtdep.found()
|
||||||
|
qtmodule = import(qt)
|
||||||
|
|
||||||
# The following has two resource files because having two in one target
|
# The following has two resource files because having two in one target
|
||||||
# requires you to do it properly or you get linker symbol clashes.
|
# requires you to do it properly or you get linker symbol clashes.
|
||||||
|
|
||||||
prep = qt5.preprocess(
|
prep = qtmodule.preprocess(
|
||||||
moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use.
|
moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use.
|
||||||
ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol.
|
ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol.
|
||||||
qresources : ['stuff.qrc', 'stuff2.qrc'], # Resource file for rcc compiler.
|
qresources : ['stuff.qrc', 'stuff2.qrc'], # Resource file for rcc compiler.
|
||||||
)
|
)
|
||||||
|
|
||||||
q5exe = executable('qt5app',
|
qexe = executable(qt + 'app',
|
||||||
sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
|
sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
|
||||||
prep],
|
prep],
|
||||||
dependencies : qt5dep)
|
dependencies : qtdep)
|
||||||
|
|
||||||
# We need a console test application because some test environments
|
# We need a console test application because some test environments
|
||||||
# do not have an X server.
|
# do not have an X server.
|
||||||
|
|
||||||
qt5core = dependency('qt5', modules : 'Core')
|
qtcore = dependency(qt, modules : 'Core')
|
||||||
|
|
||||||
qt5coreapp = executable('q5core', 'q5core.cpp',
|
qtcoreapp = executable(qt + 'core', 'q5core.cpp',
|
||||||
dependencies : qt5core)
|
dependencies : qtcore)
|
||||||
|
|
||||||
test('qt5test', qt5coreapp)
|
test(qt + 'test', qtcoreapp)
|
||||||
|
|
||||||
# The build system needs to include the cpp files from
|
# The build system needs to include the cpp files from
|
||||||
# headers but the user must manually include moc
|
# headers but the user must manually include moc
|
||||||
# files from sources.
|
# files from sources.
|
||||||
manpreprocessed = qt5.preprocess(
|
manpreprocessed = qtmodule.preprocess(
|
||||||
moc_sources : 'manualinclude.cpp',
|
moc_sources : 'manualinclude.cpp',
|
||||||
moc_headers : 'manualinclude.h')
|
moc_headers : 'manualinclude.h')
|
||||||
|
|
||||||
q5maninclude = executable('q5maninclude',
|
qtmaninclude = executable(qt + 'maninclude',
|
||||||
sources : ['manualinclude.cpp', manpreprocessed],
|
sources : ['manualinclude.cpp', manpreprocessed],
|
||||||
dependencies : qt5core)
|
dependencies : qtcore)
|
||||||
|
|
||||||
test('q5maninclude', q5maninclude)
|
test(qt + 'maninclude', qtmaninclude)
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
Loading…
Reference in New Issue