1project('qt4 and 5 build test', 'cpp',
2  # Qt5 now requires C++ 11 support
3  default_options : ['cpp_std=c++11'])
4
5qt5_modules = ['Widgets']
6qt6_modules = ['Widgets']
7foreach qt : ['qt4', 'qt5', 'qt6']
8  qt_modules = ['Core', 'Gui']
9  if qt == 'qt5'
10    qt_modules += qt5_modules
11  elif qt == 'qt6'
12    qt_modules += qt6_modules
13  endif
14
15  # Test that invalid modules are indeed not found
16  fakeqtdep = dependency(qt, modules : ['DefinitelyNotFound'], required : false, method : get_option('method'))
17  if fakeqtdep.found()
18    error('Invalid qt dep incorrectly found!')
19  endif
20
21  # Test that partially-invalid modules are indeed not found
22  fakeqtdep = dependency(qt, modules : ['Core', 'DefinitelyNotFound'], required : false, method : get_option('method'))
23  if fakeqtdep.found()
24    error('Invalid qt dep incorrectly found!')
25  endif
26
27  # This test should be skipped if the required version of Qt isn't found
28  #
29  # (In the CI environment, the specified version of Qt is definitely present.
30  # An unexpected skip here is treated as a failure, so we are testing that the
31  # detection mechanism is able to find Qt.)
32  needed_qt = get_option('required').to_lower()
33  required = (qt == needed_qt)
34  if required
35    dep = dependency(qt, modules : ['Core'], required : false, method : get_option('method'))
36    if not dep.found()
37      error('MESON_SKIP_TEST @0@ not found.'.format(needed_qt))
38    endif
39  endif
40
41  # Ensure that the "no-Core-module-specified" code branch is hit
42  nocoredep = dependency(qt, modules : ['Gui'], required : required, method : get_option('method'))
43
44  # If 'qt' modules are found, test that.
45  qtdep = dependency(qt, modules : qt_modules, main : true, private_headers: true, required : required, method : get_option('method'))
46  if qtdep.found()
47    qtmodule = import(qt)
48    assert(qtmodule.has_tools())
49
50    # The following has two resource files because having two in one target
51    # requires you to do it properly or you get linker symbol clashes.
52
53    prep = qtmodule.preprocess(
54      moc_headers : ['mainWindow.h'],           # These need to be fed through the moc tool before use.
55      method : get_option('method')
56    )
57    # XML files that need to be compiled with the uic tol.
58    prep += qtmodule.compile_ui(sources : 'mainWindow.ui', method: get_option('method'))
59
60    qtmodule.preprocess(
61      ui_files : 'mainWindow.ui',
62      method: get_option('method'))
63
64    # Resource file(s) for rcc compiler
65    extra_cpp_args = []
66    if meson.is_unity()
67      extra_cpp_args += '-DUNITY_BUILD'
68      prep_rcc = qtmodule.preprocess(qt + '_unity_ressource', qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
69    else
70      prep_rcc = qtmodule.preprocess(qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
71    endif
72
73    # Test that setting a unique name with a positional argument works
74    qtmodule.compile_resources(
75      name : qt + 'teststuff',
76      sources : files(['stuff.qrc', 'stuff2.qrc']),
77      method : get_option('method')
78    )
79
80    # Test that passing extra arguments to rcc works
81    # qt4-rcc and qt5-rcc take different arguments, for example qt4: ['-compress', '3']; qt5: '--compress=3'
82    qtmodule.preprocess(qt + 'testrccarg', qresources : files(['stuff.qrc', 'stuff2.qrc']), rcc_extra_arguments : '--compress=3', method : get_option('method'))
83
84    translations_cpp = qtmodule.compile_translations(qresource: qt+'_lang.qrc')
85    # unity builds suck and definitely cannot handle two qrc embeds in one compilation unit
86    unityproof_translations = static_library('unityproof_translations', translations_cpp)
87
88    extra_cpp_args += '-DQT="@0@"'.format(qt)
89    qexe = executable(qt + 'app',
90      sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
91      prep, prep_rcc],
92      dependencies : qtdep,
93      link_with: unityproof_translations,
94      cpp_args: extra_cpp_args,
95      gui_app : true)
96
97    # We need a console test application because some test environments
98    # do not have an X server.
99
100    translations = qtmodule.compile_translations(ts_files : qt+'core_fr.ts', build_by_default : true)
101
102    qtcore = dependency(qt, modules : 'Core', method : get_option('method'))
103
104    qtcoreapp = executable(qt + 'core', 'q5core.cpp',
105      cpp_args: '-DQT="@0@"'.format(qt),
106      dependencies : qtcore)
107
108    test(qt + 'test', qtcoreapp)
109
110    # The build system needs to include the cpp files from
111    # headers but the user must manually include moc
112    # files from sources.
113    qtmodule.preprocess(
114      moc_extra_arguments : ['-DMOC_EXTRA_FLAG'], # This is just a random macro to test `extra_arguments`
115      moc_sources : 'manualinclude.cpp',
116      moc_headers : 'manualinclude.h',
117      method : get_option('method'))
118
119    manpreprocessed = qtmodule.compile_moc(
120      extra_args : ['-DMOC_EXTRA_FLAG'], # This is just a random macro to test `extra_arguments`
121      sources : 'manualinclude.cpp',
122      headers : 'manualinclude.h',
123      method : get_option('method'))
124
125    qtmaninclude = executable(qt + 'maninclude',
126      sources : ['manualinclude.cpp', manpreprocessed],
127      dependencies : qtcore)
128
129    test(qt + 'maninclude', qtmaninclude)
130
131    # building Qt plugins implies to give include path to moc
132    plugin_includes = include_directories('pluginInterface', 'plugin')
133    pluginpreprocess = qtmodule.preprocess(
134      moc_headers : 'plugin/plugin.h',
135      include_directories : plugin_includes
136    )
137    plugin = library(qt + 'plugin', 'plugin/plugin.cpp', pluginpreprocess,
138          include_directories : plugin_includes,
139          dependencies : qtcore)
140
141    # implementing Qt interfaces requires passing Qt include paths to moc
142    qtinterfacepreprocess = qtmodule.preprocess(
143      moc_sources : 'qtinterface.cpp',
144      dependencies : qtdep
145    )
146    qtinterface = library(qt + 'qtinterface',
147                          sources : ['qtinterface.cpp', qtinterfacepreprocess],
148                          dependencies : qtdep)
149
150    if qt == 'qt5'
151      subdir('subfolder')
152    endif
153
154    # Check we can apply a version constraint
155    dependency(qt, modules: qt_modules, version: '>=@0@'.format(qtdep.version()), method : get_option('method'))
156
157  endif
158endforeach
159