Merge pull request #3491 from jeandet/qt_private_headers

Qt private headers
pull/3639/head
Jussi Pakkanen 7 years ago committed by GitHub
commit cc3e0bc469
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      docs/markdown/Qt5-module.md
  2. 1
      docs/markdown/Reference-manual.md
  3. 70
      mesonbuild/dependencies/ui.py
  4. 2
      mesonbuild/interpreter.py
  5. 5
      test cases/frameworks/4 qt/main.cpp
  6. 2
      test cases/frameworks/4 qt/meson.build

@ -20,6 +20,7 @@ This method generates the necessary targets to build translation files with lrel
- `install_dir` directory to install to (optional).
- `build_by_default` when set to true, to have this target be built by default, that is, when invoking plain ninja; the default value is false (optional).
## Example
A simple example would look like this:
```meson
@ -38,3 +39,10 @@ executable('myprog', 'main.cpp', 'myclass.cpp', moc_files,
The 'modules' argument is used to include Qt modules in the project.
See the Qt documentation for the [list of modules](http://doc.qt.io/qt-5/qtmodules.html).
## private headers (since v0.47.0)
**private_headers** keyword argument has been added to [dependency](Reference-manual.md#dependency) method to allow Qt's modules private headers usage.
Setting this optional argument to true will add private include path of the given module to the compiler flags.
**Note** that using private headers in your project is a bad idea, do it at your own risks.

@ -347,6 +347,7 @@ otherwise. This function supports the following keyword arguments:
`>1.0.0`, `<=2.3.5` or `3.1.4` for exact matching. (*Added 0.37.0*)
You can also specify multiple restrictions by passing a list to this
keyword argument, such as: `['>=3.14.0', '<=4.1.0']`.
- `private_headers`, only available with Qt modules see [documentation](Qt5-module.md#private_headers).
If dependency_name is '', the dependency is always not found. So with
`required: false`, this always returns a dependency object for which the

@ -147,6 +147,47 @@ class GnuStepDependency(ConfigToolDependency):
return version
def _qt_get_private_includes(mod_inc_dir, module, mod_version):
# usually Qt5 puts private headers in /QT_INSTALL_HEADERS/module/VERSION/module/private
# except for at least QtWebkit and Enginio where the module version doesn't match Qt version
# as an example with Qt 5.10.1 on linux you would get:
# /usr/include/qt5/QtCore/5.10.1/QtCore/private/
# /usr/include/qt5/QtWidgets/5.10.1/QtWidgets/private/
# /usr/include/qt5/QtWebKit/5.212.0/QtWebKit/private/
# on Qt4 when available private folder is directly in module folder
# like /usr/include/QtCore/private/
if int(mod_version.split('.')[0]) < 5:
return tuple()
private_dir = os.path.join(mod_inc_dir, mod_version)
# fallback, let's try to find a directory with the latest version
if not os.path.exists(private_dir):
dirs = [filename for filename in os.listdir(mod_inc_dir)
if os.path.isdir(os.path.join(mod_inc_dir, filename))]
dirs.sort(reverse=True)
for dirname in dirs:
if len(dirname.split('.')) == 3:
private_dir = dirname
break
return (private_dir,
os.path.join(private_dir, 'Qt' + module))
class QtExtraFrameworkDependency(ExtraFrameworkDependency):
def __init__(self, name, required, path, env, lang, kwargs):
super().__init__(name, required, path, env, lang, kwargs)
self.mod_name = name[2:]
def get_compile_args(self, with_private_headers=False, qt_version="0"):
if self.found():
mod_inc_dir = os.path.join(self.path, self.name, 'Headers')
args = ['-I' + mod_inc_dir]
if with_private_headers:
args += ['-I' + dirname for dirname in _qt_get_private_includes(mod_inc_dir, self.mod_name, qt_version)]
return args
return []
class QtBaseDependency(ExternalDependency):
def __init__(self, name, env, kwargs):
super().__init__(name, env, 'cpp', kwargs)
@ -158,9 +199,8 @@ class QtBaseDependency(ExternalDependency):
self.qtpkgname = self.qtname
self.root = '/usr'
self.bindir = None
mods = kwargs.get('modules', [])
if isinstance(mods, str):
mods = [mods]
self.private_headers = kwargs.get('private_headers', False)
mods = extract_as_list(kwargs, 'modules')
if not mods:
raise DependencyException('No ' + self.qtname + ' modules specified.')
type_text = 'cross' if env.is_cross_build() else 'native'
@ -174,7 +214,7 @@ class QtBaseDependency(ExternalDependency):
if DependencyMethods.PKGCONFIG in self.methods:
self._pkgconfig_detect(mods, kwargs)
methods.append('pkgconfig')
if not self.is_found and DependencyMethods.QMAKE in self.methods:
if not self.is_found or DependencyMethods.QMAKE in self.methods:
from_text = self._qmake_detect(mods, kwargs)
methods.append('qmake-' + self.name)
methods.append('qmake')
@ -219,11 +259,16 @@ class QtBaseDependency(ExternalDependency):
for module in mods:
modules[module] = PkgConfigDependency(self.qtpkgname + module, self.env,
kwargs, language=self.language)
for m in modules.values():
for m_name, m in modules.items():
if not m.found():
self.is_found = False
return
self.compile_args += m.get_compile_args()
if self.private_headers:
qt_inc_dir = m.get_pkgconfig_variable('includedir', dict())
mod_private_inc = _qt_get_private_includes(os.path.join(qt_inc_dir, 'Qt' + m_name), m_name, m.version)
for dir in mod_private_inc:
self.compile_args.append('-I' + dir)
self.link_args += m.get_link_args()
self.is_found = True
self.version = m.version
@ -296,6 +341,10 @@ class QtBaseDependency(ExternalDependency):
for module in mods:
mincdir = os.path.join(incdir, 'Qt' + module)
self.compile_args.append('-I' + mincdir)
if self.private_headers:
priv_inc = self.get_private_includes(mincdir, module)
for dir in priv_inc:
self.compile_args.append('-I' + dir)
if for_windows(self.env.is_cross_build(), self.env):
is_debug = self.env.cmd_line_options.buildtype.startswith('debug')
dbg = 'd' if is_debug else ''
@ -327,11 +376,12 @@ class QtBaseDependency(ExternalDependency):
for m in modules:
fname = 'Qt' + m
fwdep = ExtraFrameworkDependency(fname, False, libdir, self.env,
fwdep = QtExtraFrameworkDependency(fname, False, libdir, self.env,
self.language, fw_kwargs)
self.compile_args.append('-F' + libdir)
if fwdep.found():
self.compile_args += fwdep.get_compile_args()
self.compile_args += fwdep.get_compile_args(with_private_headers=self.private_headers,
qt_version=self.version)
self.link_args += fwdep.get_link_args()
else:
break
@ -361,6 +411,9 @@ class QtBaseDependency(ExternalDependency):
# for you, patches are welcome.
return compiler.get_pic_args()
def get_private_includes(self, mod_inc_dir, module):
return tuple()
class Qt4Dependency(QtBaseDependency):
def __init__(self, env, kwargs):
@ -386,6 +439,9 @@ class Qt5Dependency(QtBaseDependency):
def get_pkgconfig_host_bins(self, core):
return core.get_pkgconfig_variable('host_bins', {})
def get_private_includes(self, mod_inc_dir, module):
return _qt_get_private_includes(mod_inc_dir, module, self.version)
# There are three different ways of depending on SDL2:
# sdl2-config, pkg-config and OSX framework

@ -1673,7 +1673,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'build_target': known_build_target_kwargs,
'configure_file': {'input', 'output', 'configuration', 'command', 'copy', 'install_dir', 'capture', 'install', 'format'},
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version', 'private_headers'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
'executable': build.known_exe_kwargs,
'find_program': {'required', 'native'},

@ -1,6 +1,11 @@
#include <QApplication>
#include "mainWindow.h"
#if QT_VERSION > 0x050000
// include some random private headers
#include <private/qobject_p.h>
#endif
int main(int argc, char **argv) {
#ifndef UNITY_BUILD
Q_INIT_RESOURCE(stuff);

@ -33,7 +33,7 @@ foreach qt : ['qt4', 'qt5']
nocoredep = dependency(qt, modules : ['Gui'], required : qt == 'qt5', method : get_option('method'))
# If qt4 modules are found, test that. qt5 is required.
qtdep = dependency(qt, modules : qt_modules, required : qt == 'qt5', method : get_option('method'))
qtdep = dependency(qt, modules : qt_modules, private_headers: true, required : qt == 'qt5', method : get_option('method'))
if qtdep.found()
qtmodule = import(qt)

Loading…
Cancel
Save