1# this must be done outside any function
2QT_SOURCE_TREE = $$PWD
3QT_BUILD_TREE = $$shadowed($$PWD)
4
5# custom command line handling
6
7defineTest(qtConfCommandline_qmakeArgs) {
8    contains(1, QMAKE_[A-Z0-9_]+ *[-+]?=.*) {
9        config.input.qmakeArgs += $$1
10        export(config.input.qmakeArgs)
11        return(true)
12    }
13    return(false)
14}
15
16defineTest(qtConfCommandline_cxxstd) {
17    arg = $${1}
18    val = $${2}
19    isEmpty(val): val = $$qtConfGetNextCommandlineArg()
20    !contains(val, "^-.*"):!isEmpty(val) {
21        contains(val, "(c\+\+)?11") {
22            qtConfCommandlineSetInput("c++14", "no")
23            qtConfCommandlineSetInput("c++1z", "no")
24            qtConfCommandlineSetInput("c++2a", "no")
25        } else: contains(val, "(c\+\+)?(14|1y)") {
26            qtConfCommandlineSetInput("c++14", "yes")
27            qtConfCommandlineSetInput("c++1z", "no")
28            qtConfCommandlineSetInput("c++2a", "no")
29        } else: contains(val, "(c\+\+)?(17|1z)") {
30            qtConfCommandlineSetInput("c++14", "yes")
31            qtConfCommandlineSetInput("c++1z", "yes")
32            qtConfCommandlineSetInput("c++2a", "no")
33        } else: contains(val, "(c\+\+)?(2a)") {
34            qtConfCommandlineSetInput("c++14", "yes")
35            qtConfCommandlineSetInput("c++1z", "yes")
36            qtConfCommandlineSetInput("c++2a", "yes")
37        } else {
38            qtConfAddError("Invalid argument $$val to command line parameter $$arg")
39        }
40    } else {
41        qtConfAddError("Missing argument to command line parameter $$arg")
42    }
43}
44
45defineTest(qtConfCommandline_sanitize) {
46    arg = $${1}
47    val = $${2}
48    isEmpty(val): val = $$qtConfGetNextCommandlineArg()
49    !contains(val, "^-.*"):!isEmpty(val) {
50        equals(val, "address") {
51            qtConfCommandlineSetInput("sanitize_address", "yes")
52        } else: equals(val, "thread") {
53            qtConfCommandlineSetInput("sanitize_thread", "yes")
54        } else: equals(val, "memory") {
55            qtConfCommandlineSetInput("sanitize_memory", "yes")
56        } else: equals(val, "fuzzer-no-link") {
57            qtConfCommandlineSetInput("sanitize_fuzzer_no_link", "yes")
58        } else: equals(val, "undefined") {
59            qtConfCommandlineSetInput("sanitize_undefined", "yes")
60        } else {
61            qtConfAddError("Invalid argument $$val to command line parameter $$arg")
62        }
63    } else {
64        qtConfAddError("Missing argument to command line parameter $$arg")
65    }
66}
67
68defineTest(qtConfCommandline_coverage) {
69    arg = $${1}
70    val = $${2}
71    isEmpty(val): val = $$qtConfGetNextCommandlineArg()
72    !contains(val, "^-.*"):!isEmpty(val) {
73        equals(val, "trace-pc-guard") {
74            qtConfCommandlineSetInput("coverage_trace_pc_guard", "yes")
75        } else: equals(val, "source-based") {
76            qtConfCommandlineSetInput("coverage_source_based", "yes")
77        } else: {
78            qtConfAddError("Invalid argument $$val to command line parameter $$arg")
79        }
80    } else {
81        qtConfAddError("Missing argument to command line parameter $$arg")
82    }
83}
84
85# callbacks
86
87defineReplace(qtConfFunc_crossCompile) {
88    !isEmpty(config.input.xplatform): return(true)
89    !isEmpty(config.input.device-option): return(true)
90    !isEmpty(config.input.sysroot): return(true)
91    spec = $$[QMAKE_SPEC]
92    !equals(spec, $$[QMAKE_XSPEC]): return(true)
93    return(false)
94}
95
96defineReplace(qtConfFunc_licenseCheck) {
97    exists($$QT_SOURCE_TREE/LICENSE.LGPL3)|exists($$QT_SOURCE_TREE/LICENSE.GPL2)|exists($$QT_SOURCE_TREE/LICENSE.GPL3): \
98        hasOpenSource = true
99    else: \
100        hasOpenSource = false
101    exists($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT): \
102        hasCommercial = true
103    else: \
104        hasCommercial = false
105
106    commercial = $$config.input.commercial
107    isEmpty(commercial) {
108        $$hasOpenSource {
109            $$hasCommercial {
110                logn()
111                logn("Selecting Qt Edition.")
112                logn()
113                logn("Type 'c' if you want to use the Commercial Edition.")
114                logn("Type 'o' if you want to use the Open Source Edition.")
115                logn()
116                for(ever) {
117                    val = $$lower($$prompt("Which edition of Qt do you want to use? ", false))
118                    equals(val, c) {
119                        commercial = yes
120                        QMAKE_SAVED_ARGS += -commercial
121                    } else: equals(val, o) {
122                        commercial = no
123                        QMAKE_SAVED_ARGS += -opensource
124                    } else {
125                        next()
126                    }
127                    export(QMAKE_SAVED_ARGS)
128                    break()
129                }
130            } else {
131                commercial = no
132            }
133        } else {
134            !$$hasCommercial: \
135                qtConfFatalError("No license files. Cannot proceed. Try re-installing Qt.")
136            commercial = yes
137        }
138    }
139
140    equals(commercial, no) {
141        !$$hasOpenSource: \
142            qtConfFatalError("This is the Qt Commercial Edition." \
143                             "Cannot proceed with -opensource.")
144
145        logn()
146        logn("This is the Qt Open Source Edition.")
147
148        EditionString = "Open Source"
149        config.input.qt_edition = OpenSource
150        export(config.input.qt_edition)
151    } else {
152        !$$hasCommercial: \
153            qtConfFatalError("This is the Qt Open Source Edition." \
154                             "Cannot proceed with -commercial.")
155
156        !exists($$QT_SOURCE_TREE/.release-timestamp) {
157            #  Build from git
158
159            logn()
160            logn("This is the Qt Commercial Edition.")
161
162            EditionString = "Commercial"
163            config.input.qt_edition = Commercial
164            export(config.input.qt_edition)
165        } else {
166            # Build from a released source package
167
168            equals(QMAKE_HOST.os, Linux) {
169                !equals(QMAKE_HOST.arch, x86_64): \
170                    Licheck = licheck32
171                else: \
172                    Licheck = licheck64
173            } else: equals(QMAKE_HOST.os, Darwin) {
174                Licheck = licheck_mac
175            } else: equals(QMAKE_HOST.os, Windows) {
176                Licheck = licheck.exe
177            } else {
178                qtConfFatalError("Host operating system not supported by this edition of Qt.")
179            }
180
181            !qtRunLoggedCommand("$$system_quote($$QT_SOURCE_TREE/bin/$$Licheck) \
182                                    $$system_quote($$eval(config.input.confirm-license)) \
183                                    $$system_quote($$QT_SOURCE_TREE) $$system_quote($$QT_BUILD_TREE) \
184                                    $$[QMAKE_SPEC] $$[QMAKE_XSPEC]", \
185                                LicheckOutput, false): \
186                return(false)
187            logn()
188            for (o, LicheckOutput) {
189                contains(o, "\\w+=.*"): \
190                    eval($$o)
191                else: \
192                    logn($$o)
193            }
194            config.input.qt_edition = $$Edition
195            config.input.qt_licheck = $$Licheck
196            config.input.qt_release_date = $$ReleaseDate
197            export(config.input.qt_edition)
198            export(config.input.qt_licheck)
199            export(config.input.qt_release_date)
200            return(true)
201        }
202    }
203
204    !isEmpty(config.input.confirm-license) {
205        logn()
206        logn("You have already accepted the terms of the $$EditionString license.")
207        return(true)
208    }
209
210    affix = the
211    equals(commercial, no) {
212        theLicense = "GNU Lesser General Public License (LGPL) version 3"
213        showWhat = "Type 'L' to view the GNU Lesser General Public License version 3 (LGPLv3)."
214        gpl2Ok = false
215        gpl3Ok = false
216        winrt {
217            notTheLicense = "Note: GPL version 2 is not available on WinRT."
218        } else: wasm {
219            gpl3Ok = true
220            theLicense = "GNU General Public License (GPL) version 3"
221            showWhat = "Type 'G' to view the GNU General Public License version 3 (GPLv3)."
222        } else: $$qtConfEvaluate("features.android-style-assets") {
223            notTheLicense = "Note: GPL version 2 is not available due to using Android style assets."
224        } else {
225            theLicense += "or the GNU General Public License (GPL) version 2"
226            showWhat += "Type 'G' to view the GNU General Public License version 2 (GPLv2)."
227            gpl2Ok = true
228            affix = either
229        }
230    } else {
231        theLicense = $$cat($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT, lines)
232        theLicense = $$first(theLicense)
233        showWhat = "Type '?' to view the $${theLicense}."
234    }
235    msg = \
236        " " \
237        "You are licensed to use this software under the terms of" \
238        "the "$$theLicense"." \
239        $$notTheLicense \
240        " " \
241        $$showWhat \
242        "Type 'y' to accept this license offer." \
243        "Type 'n' to decline this license offer." \
244        " "
245
246    for(ever) {
247        logn($$join(msg, $$escape_expand(\\n)))
248        for(ever) {
249            val = $$lower($$prompt("Do you accept the terms of $$affix license? ", false))
250            equals(val, y)|equals(val, yes) {
251                logn()
252                QMAKE_SAVED_ARGS += -confirm-license
253                export(QMAKE_SAVED_ARGS)
254                return(true)
255            } else: equals(val, n)|equals(val, no) {
256                return(false)
257            } else: equals(commercial, yes):equals(val, ?) {
258                licenseFile = $$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT
259            } else: equals(commercial, no):equals(val, l) {
260                licenseFile = $$QT_SOURCE_TREE/LICENSE.LGPL3
261            } else: equals(commercial, no):equals(val, g):$$gpl2Ok {
262                licenseFile = $$QT_SOURCE_TREE/LICENSE.GPL2
263            } else: equals(commercial, no):equals(val, g):$$gpl3Ok {
264                licenseFile = $$QT_SOURCE_TREE/LICENSE.GPL3
265            } else {
266                next()
267            }
268            break()
269        }
270        system("more $$system_quote($$system_path($$licenseFile))")
271        logn()
272        logn()
273    }
274}
275
276# custom tests
277
278# this is meant for linux device specs only
279defineTest(qtConfTest_machineTuple) {
280    qtRunLoggedCommand("$$QMAKE_CXX -dumpmachine", $${1}.tuple)|return(false)
281    $${1}.cache += tuple
282    export($${1}.cache)
283    return(true)
284}
285
286defineTest(qtConfTest_verifySpec) {
287    qtConfTest_compile($$1): return(true)
288    qtConfFatalError("Cannot compile a minimal program. The toolchain or QMakeSpec is broken.", log)
289}
290
291defineTest(qtConfTest_architecture) {
292    !qtConfTest_compile($${1}): \
293        error("Could not determine $$eval($${1}.label). See config.log for details.")
294
295    test = $$eval($${1}.test)
296    output = $$eval($${1}.output)
297    test_out_dir = $$OUT_PWD/$$basename(QMAKE_CONFIG_TESTS_DIR)/$$test
298    test_out_file = $$test_out_dir/$$cat($$test_out_dir/$${output}.target.txt)
299    exists($$test_out_file): \
300        content = $$cat($$test_out_file, blob)
301    else: \
302        error("$$eval($${1}.label) detection binary not found.")
303    content = $$cat($$test_out_file, blob)
304
305    arch_magic = ".*==Qt=magic=Qt== Architecture:([^\\0]*).*"
306    subarch_magic = ".*==Qt=magic=Qt== Sub-architecture:([^\\0]*).*"
307    buildabi_magic = ".*==Qt=magic=Qt== Build-ABI:([^\\0]*).*"
308
309    !contains(content, $$arch_magic)|!contains(content, $$subarch_magic)|!contains(content, $$buildabi_magic): \
310        error("$$eval($${1}.label) detection binary does not contain expected data.")
311
312    $${1}.arch = $$replace(content, $$arch_magic, "\\1")
313    $${1}.subarch = $$replace(content, $$subarch_magic, "\\1")
314    $${1}.subarch = $$split($${1}.subarch, " ")
315    $${1}.buildabi = $$replace(content, $$buildabi_magic, "\\1")
316    export($${1}.arch)
317    export($${1}.subarch)
318    export($${1}.buildabi)
319    qtLog("Detected architecture: $$eval($${1}.arch) ($$eval($${1}.subarch))")
320
321    $${1}.cache += arch subarch buildabi
322    export($${1}.cache)
323    return(true)
324}
325
326defineTest(qtConfTest_gnumake) {
327    make = $$qtConfFindInPath("gmake")
328    isEmpty(make): make = $$qtConfFindInPath("make")
329    !isEmpty(make) {
330        qtRunLoggedCommand("$$make -v", version)|return(false)
331        contains(version, "^GNU Make.*"): return(true)
332    }
333    return(false)
334}
335
336defineTest(qtConfTest_detectPkgConfig) {
337    pkgConfig = $$getenv("PKG_CONFIG")
338    !isEmpty(pkgConfig): {
339        qtLog("Found pkg-config from environment variable: $$pkgConfig")
340    } else {
341        pkgConfig = $$QMAKE_PKG_CONFIG
342
343        !isEmpty(pkgConfig) {
344            qtLog("Found pkg-config from mkspec: $$pkgConfig")
345        } else {
346            pkgConfig = $$qtConfFindInPath("pkg-config")
347
348            isEmpty(pkgConfig): \
349                return(false)
350
351            qtLog("Found pkg-config from path: $$pkgConfig")
352        }
353    }
354
355    $$qtConfEvaluate("features.cross_compile") {
356        # cross compiling, check that pkg-config is set up sanely
357        sysroot = $$config.input.sysroot
358
359        pkgConfigLibdir = $$getenv("PKG_CONFIG_LIBDIR")
360        isEmpty(pkgConfigLibdir) {
361            isEmpty(sysroot) {
362                qtConfAddWarning("Cross compiling without sysroot. Disabling pkg-config")
363                return(false)
364            }
365            !exists("$$sysroot/usr/lib/pkgconfig") {
366                qtConfAddWarning( \
367                    "Disabling pkg-config since PKG_CONFIG_LIBDIR is not set and" \
368                    "the host's .pc files would be used (even if you set PKG_CONFIG_PATH)." \
369                    "Set this variable to the directory that contains target .pc files" \
370                    "for pkg-config to function correctly when cross-compiling or" \
371                    "use -pkg-config to override this test.")
372                return(false)
373            }
374
375            pkgConfigLibdir = $$sysroot/usr/lib/pkgconfig:$$sysroot/usr/share/pkgconfig
376            machineTuple = $$eval($${currentConfig}.tests.machineTuple.tuple)
377            !isEmpty(machineTuple): \
378                pkgConfigLibdir = "$$pkgConfigLibdir:$$sysroot/usr/lib/$$machineTuple/pkgconfig"
379
380            qtConfAddNote("PKG_CONFIG_LIBDIR automatically set to $$pkgConfigLibdir")
381        }
382        pkgConfigSysrootDir = $$getenv("PKG_CONFIG_SYSROOT_DIR")
383        isEmpty(pkgConfigSysrootDir) {
384            isEmpty(sysroot) {
385                qtConfAddWarning( \
386                    "Disabling pkg-config since PKG_CONFIG_SYSROOT_DIR is not set." \
387                    "Set this variable to your sysroot for pkg-config to function correctly when" \
388                    "cross-compiling or use -pkg-config to override this test.")
389                return(false)
390            }
391
392            pkgConfigSysrootDir = $$sysroot
393            qtConfAddNote("PKG_CONFIG_SYSROOT_DIR automatically set to $$pkgConfigSysrootDir")
394        }
395        $${1}.pkgConfigLibdir = $$pkgConfigLibdir
396        export($${1}.pkgConfigLibdir)
397        $${1}.pkgConfigSysrootDir = $$pkgConfigSysrootDir
398        export($${1}.pkgConfigSysrootDir)
399        $${1}.cache += pkgConfigLibdir pkgConfigSysrootDir
400    }
401    $${1}.pkgConfig = $$pkgConfig
402    export($${1}.pkgConfig)
403    $${1}.cache += pkgConfig
404    export($${1}.cache)
405
406    return(true)
407}
408
409defineTest(qtConfTest_buildParts) {
410    parts = $$config.input.make
411    isEmpty(parts) {
412        parts = libs examples
413
414        $$qtConfEvaluate("features.developer-build"): \
415            parts += tests
416        !$$qtConfEvaluate("features.cross_compile"): \
417            parts += tools
418    }
419
420    parts -= $$config.input.nomake
421
422    # always add libs, as it's required to build Qt
423    parts *= libs
424
425    $${1}.value = $$parts
426    export($${1}.value)
427    $${1}.cache = -
428    export($${1}.cache)
429    return(true)
430}
431
432defineTest(qtConfTest_x86Simd) {
433    simd = $$section(1, ".", -1)    # last component
434    $${1}.args = CONFIG+=add_cflags DEFINES+=NO_ATTRIBUTE SIMD=$$simd
435    $${1}.test = x86_simd
436    qtConfTest_compile($${1})
437}
438
439defineTest(qtConfTest_x86SimdAlways) {
440    configs =
441    fpfx = $${currentConfig}.features
442    tpfx = $${currentConfig}.tests
443
444    # Make a list of all passing features whose tests have type=x86Simd
445    for (f, $${tpfx}._KEYS_) {
446        !equals($${tpfx}.$${f}.type, "x86Simd"): \
447            next()
448        qtConfCheckFeature($$f)
449        equals($${fpfx}.$${f}.available, true): configs += $$f
450    }
451    $${1}.literal_args = SIMD=$$join(configs, " ")
452    qtConfTest_compile($${1})
453}
454
455# custom outputs
456
457# this reloads the qmakespec as completely as reasonably possible.
458defineTest(reloadSpec) {
459    bypassNesting() {
460        for (f, QMAKE_INTERNAL_INCLUDED_FILES) {
461            contains(f, .*/mkspecs/.*):\
462                    !contains(f, .*/(qt_build_config|qt_parts|qt_configure|configure_base)\\.prf): \
463                discard_from($$f)
464        }
465        # nobody's going to try to re-load the features above,
466        # so don't bother with being selective.
467        QMAKE_INTERNAL_INCLUDED_FEATURES = \
468            # loading it gets simulated below.
469            $$[QT_HOST_DATA/src]/mkspecs/features/device_config.prf \
470            # must be delayed until qdevice.pri is ready.
471            $$[QT_HOST_DATA/src]/mkspecs/features/mac/toolchain.prf \
472            $$[QT_HOST_DATA/src]/mkspecs/features/toolchain.prf
473
474        saved_variables = CONFIG QMAKE_CXXFLAGS
475        for (name, saved_variables): \
476            _SAVED_$$name = $$eval($$name)
477        load(spec_pre)
478        # qdevice.pri gets written too late (and we can't write it early
479        # enough, as it's populated in stages, with later ones depending
480        # on earlier ones). so inject its variables manually.
481        for (l, $${currentConfig}.output.devicePro): \
482            eval($$l)
483        include($$QMAKESPEC/qmake.conf)
484        load(spec_post)
485        for (name, saved_variables): \
486            $$name += $$eval(_SAVED_$$name)
487        load(default_pre)
488
489        # ensure pristine environment for configuration. again.
490        discard_from($$[QT_HOST_DATA/get]/mkspecs/qconfig.pri)
491        discard_from($$[QT_HOST_DATA/get]/mkspecs/qmodule.pri)
492    }
493}
494
495defineTest(qtConfOutput_prepareSpec) {
496    device = $$eval(config.input.device)
497    !isEmpty(device) {
498        devices = $$files($$[QT_HOST_DATA/src]/mkspecs/devices/*$$device*)
499        isEmpty(devices): \
500            qtConfFatalError("No device matching '$$device'.")
501        !count(devices, 1) {
502            err = "Multiple matches for device '$$device'. Candidates are:"
503            for (d, devices): \
504                err += "    $$basename(d)"
505            qtConfFatalError($$err)
506        }
507        XSPEC = $$relative_path($$devices, $$[QT_HOST_DATA/src]/mkspecs)
508    }
509    xspec = $$eval(config.input.xplatform)
510    !isEmpty(xspec) {
511        !exists($$[QT_HOST_DATA/src]/mkspecs/$$xspec/qmake.conf): \
512            qtConfFatalError("Invalid target platform '$$xspec'.")
513        XSPEC = $$xspec
514    }
515    isEmpty(XSPEC): \
516        XSPEC = $$[QMAKE_SPEC]
517    export(XSPEC)
518    QMAKESPEC = $$[QT_HOST_DATA/src]/mkspecs/$$XSPEC
519    export(QMAKESPEC)
520
521    notes = $$cat($$OUT_PWD/.config.notes, lines)
522    !isEmpty(notes): \
523        qtConfAddNote("Also available for $$notes")
524
525    # deviceOptions() below contains conditionals coming form the spec,
526    # so this cannot be delayed for a batch reload.
527    reloadSpec()
528}
529
530defineTest(qtConfOutput_prepareOptions) {
531    $${currentConfig}.output.devicePro += \
532        $$replace(config.input.device-option, "^([^=]+) *= *(.*)$", "\\1 = \\2")
533    darwin:!isEmpty(config.input.sdk) {
534        $${currentConfig}.output.devicePro += \
535            "QMAKE_MAC_SDK = $$val_escape(config.input.sdk)"
536    }
537    android {
538        sdk_root = $$eval(config.input.android-sdk)
539        isEmpty(sdk_root): \
540            sdk_root = $$getenv(ANDROID_SDK_ROOT)
541        isEmpty(sdk_root) {
542            for(ever) {
543                equals(QMAKE_HOST.os, Linux): \
544                    sdk_root = $$(HOME)/Android/Sdk
545                else: equals(QMAKE_HOST.os, Darwin): \
546                    sdk_root = $$(HOME)/Library/Android/sdk
547                else: \
548                    break()
549                !exists($$sdk_root): \
550                    sdk_root =
551                break()
552            }
553        }
554        isEmpty(sdk_root): \
555            qtConfFatalError("Cannot find Android SDK." \
556                             "Please use -android-sdk option to specify one.")
557
558        ndk_root = $$eval(config.input.android-ndk)
559        isEmpty(ndk_root): \
560            ndk_root = $$getenv(ANDROID_NDK_ROOT)
561        isEmpty(ndk_root) {
562            for(ever) {
563                exists($$sdk_root/ndk-bundle) {
564                    ndk_root = $$sdk_root/ndk-bundle
565                    break()
566                }
567                equals(QMAKE_HOST.os, Linux): \
568                    ndk_root = $$(HOME)/Android/Sdk/ndk-bundle
569                else: equals(QMAKE_HOST.os, Darwin): \
570                    ndk_root = $$(HOME)/Library/Android/sdk/ndk-bundle
571                else: \
572                    break()
573                !exists($$ndk_root): \
574                    ndk_root =
575                break()
576            }
577        }
578        isEmpty(ndk_root): \
579            qtConfFatalError("Cannot find Android NDK." \
580                             "Please use -android-ndk option to specify one.")
581
582        ndk_tc_pfx = $$ndk_root/toolchains/llvm/prebuilt
583        ndk_host = $$eval(config.input.android-ndk-host)
584        isEmpty(ndk_host): \
585            ndk_host = $$getenv(ANDROID_NDK_HOST)
586        isEmpty(ndk_host) {
587            equals(QMAKE_HOST.os, Linux) {
588                ndk_host_64 = linux-x86_64
589                ndk_host_32 = linux-x86
590            } else: equals(QMAKE_HOST.os, Darwin) {
591                ndk_host_64 = darwin-x86_64
592                ndk_host_32 = darwin-x86
593            } else: equals(QMAKE_HOST.os, Windows) {
594                ndk_host_64 = windows-x86_64
595                ndk_host_32 = windows
596            } else {
597                qtConfFatalError("Host operating system not supported by Android.")
598            }
599            !exists($$ndk_tc_pfx/$$ndk_host_64/*): ndk_host_64 =
600            !exists($$ndk_tc_pfx/$$ndk_host_32/*): ndk_host_32 =
601            equals(QMAKE_HOST.arch, x86_64):!isEmpty(ndk_host_64) {
602                ndk_host = $$ndk_host_64
603            } else: equals(QMAKE_HOST.arch, x86):!isEmpty(ndk_host_32) {
604                ndk_host = $$ndk_host_32
605            } else {
606                !isEmpty(ndk_host_64): \
607                    ndk_host = $$ndk_host_64
608                else: !isEmpty(ndk_host_32): \
609                    ndk_host = $$ndk_host_32
610                else: \
611                    qtConfFatalError("Cannot detect the Android host." \
612                                     "Please use -android-ndk-host option to specify one.")
613                qtConfAddNote("Available Android host does not match host architecture.")
614            }
615        } else {
616            !exists($$ndk_tc_pfx/$$ndk_host/*) {
617                err = "Specified Android NDK host '$$ndk_host' is invalid. Expected files in the following directory to exist:"
618                err += '$${ndk_tc_pfx}/$${ndk_host}/'
619                qtConfFatalError($$err)
620            }
621        }
622
623        android_abis = $$eval(config.input.android-abis)
624        isEmpty(android_abis): \
625            android_abis = $$eval(config.input.android-arch)
626        isEmpty(android_abis): \
627            android_abis = armeabi-v7a,arm64-v8a,x86,x86_64
628        platform = $$eval(config.input.android-ndk-platform)
629        isEmpty(platform): \
630            platform = android-21
631
632        android_javac_target = $$eval(config.input.android-javac-target)
633        android_javac_source = $$eval(config.input.android-javac-source)
634
635        $${currentConfig}.output.devicePro += \
636            "DEFAULT_ANDROID_SDK_ROOT = $$val_escape(sdk_root)" \
637            "DEFAULT_ANDROID_NDK_ROOT = $$val_escape(ndk_root)" \
638            "DEFAULT_ANDROID_PLATFORM = $$platform" \
639            "DEFAULT_ANDROID_NDK_HOST = $$ndk_host" \
640            "DEFAULT_ANDROID_ABIS = $$split(android_abis, ',')" \
641            "ANDROID_JAVAC_TARGET_VERSION = $$android_javac_target" \
642            "ANDROID_JAVAC_SOURCE_VERSION = $$android_javac_source"
643    }
644
645    export($${currentConfig}.output.devicePro)
646
647    # if any settings were made, the spec will be reloaded later
648    # to make them take effect.
649}
650
651defineTest(qtConfOutput_machineTuple) {
652    $${currentConfig}.output.devicePro += \
653        "GCC_MACHINE_DUMP = $$eval($${currentConfig}.tests.machineTuple.tuple)"
654    export($${currentConfig}.output.devicePro)
655
656    # for completeness, one could reload the spec here,
657    # but no downstream users actually need that.
658}
659
660defineTest(qtConfOutput_commitOptions) {
661    # qdevice.pri needs to be written early, because the compile tests require it.
662    write_file($$QT_BUILD_TREE/mkspecs/qdevice.pri, $${currentConfig}.output.devicePro)|error()
663}
664
665# type (empty or 'host'), option name, default value
666defineTest(processQtPath) {
667    out_var = config.rel_input.$${2}
668    path = $$eval(config.input.$${2})
669    isEmpty(path) {
670        $$out_var = $$3
671    } else {
672        path = $$absolute_path($$path, $$OUT_PWD)
673        rel = $$relative_path($$path, $$eval(config.input.$${1}prefix))
674        isEmpty(rel) {
675            $$out_var = .
676        } else: contains(rel, \.\..*) {
677            !equals(2, sysconfdir) {
678                PREFIX_COMPLAINTS += "-$$2 is not a subdirectory of -$${1}prefix."
679                export(PREFIX_COMPLAINTS)
680                !$$eval(have_$${1}prefix) {
681                    PREFIX_REMINDER = true
682                    export(PREFIX_REMINDER)
683                }
684            }
685            $$out_var = $$path
686        } else {
687            $$out_var = $$rel
688        }
689    }
690    export($$out_var)
691}
692
693defineTest(addConfStr) {
694    QT_CONFIGURE_STR_OFFSETS += "    $$QT_CONFIGURE_STR_OFF,"
695    QT_CONFIGURE_STRS += "    \"$$1\\0\""
696    QT_CONFIGURE_STR_OFF = $$num_add($$QT_CONFIGURE_STR_OFF, $$str_size($$1), 1)
697    export(QT_CONFIGURE_STR_OFFSETS)
698    export(QT_CONFIGURE_STRS)
699    export(QT_CONFIGURE_STR_OFF)
700}
701
702defineReplace(printInstallPath) {
703    val = $$eval(config.rel_input.$$2)
704    equals(val, $$3): return()
705    return("$$1=$$val")
706}
707
708defineReplace(printInstallPaths) {
709    ret = \
710        $$printInstallPath(Documentation, docdir, doc) \
711        $$printInstallPath(Headers, headerdir, include) \
712        $$printInstallPath(Libraries, libdir, lib) \
713        $$printInstallPath(LibraryExecutables, libexecdir, $$DEFAULT_LIBEXEC) \
714        $$printInstallPath(Binaries, bindir, bin) \
715        $$printInstallPath(Plugins, plugindir, plugins) \
716        $$printInstallPath(Imports, importdir, imports) \
717        $$printInstallPath(Qml2Imports, qmldir, qml) \
718        $$printInstallPath(ArchData, archdatadir, .) \
719        $$printInstallPath(Data, datadir, .) \
720        $$printInstallPath(Translations, translationdir, translations) \
721        $$printInstallPath(Examples, examplesdir, examples) \
722        $$printInstallPath(Tests, testsdir, tests)
723    return($$ret)
724}
725
726defineReplace(printHostPaths) {
727    ret = \
728        "HostPrefix=$$config.input.hostprefix" \
729        $$printInstallPath(HostBinaries, hostbindir, bin) \
730        $$printInstallPath(HostLibraries, hostlibdir, lib) \
731        $$printInstallPath(HostData, hostdatadir, .) \
732        "Sysroot=$$config.input.sysroot" \
733        "SysrootifyPrefix=$$qmake_sysrootify" \
734        "TargetSpec=$$XSPEC" \
735        "HostSpec=$$[QMAKE_SPEC]"
736    return($$ret)
737}
738
739defineTest(qtConfOutput_preparePaths) {
740    isEmpty(config.input.prefix) {
741        $$qtConfEvaluate("features.developer-build") {
742            config.input.prefix = $$QT_BUILD_TREE  # In Development, we use sandboxed builds by default
743        } else {
744            win32: \
745                config.input.prefix = C:/Qt/Qt-$$[QT_VERSION]
746            else: \
747                config.input.prefix = /usr/local/Qt-$$[QT_VERSION]
748        }
749        have_prefix = false
750    } else {
751        equals(XSPEC, $$[QMAKE_SPEC]) {
752            # Only make the user-specified prefix absolute if we're not cross-compiling.
753            config.input.prefix = $$absolute_path($$config.input.prefix, $$OUT_PWD)
754        } else {
755            # But we still must normalize path separators.
756            config.input.prefix = $$replace(config.input.prefix, \\\\, /)
757        }
758        have_prefix = true
759    }
760
761    isEmpty(config.input.extprefix) {
762        config.input.extprefix = $$config.input.prefix
763        !isEmpty(config.input.sysroot): \
764            qmake_sysrootify = true
765        else: \
766            qmake_sysrootify = false
767    } else {
768        config.input.extprefix = $$absolute_path($$config.input.extprefix, $$OUT_PWD)
769        qmake_sysrootify = false
770    }
771
772    isEmpty(config.input.hostprefix) {
773        $$qmake_sysrootify: \
774            config.input.hostprefix = $$config.input.sysroot$$config.input.extprefix
775        else: \
776            config.input.hostprefix = $$config.input.extprefix
777        have_hostprefix = false
778    } else {
779        isEqual(config.input.hostprefix, yes): \
780            config.input.hostprefix = $$QT_BUILD_TREE
781        else: \
782            config.input.hostprefix = $$absolute_path($$config.input.hostprefix, $$OUT_PWD)
783        have_hostprefix = true
784    }
785
786    equals(config.input.prefix, $$config.input.extprefix): \
787        qmake_crossbuild = false
788    else: \
789        qmake_crossbuild = true
790
791    PREFIX_COMPLAINTS =
792    PREFIX_REMINDER = false
793    win32: \
794        DEFAULT_LIBEXEC = bin
795    else: \
796        DEFAULT_LIBEXEC = libexec
797    darwin: \
798        DEFAULT_SYSCONFDIR = /Library/Preferences/Qt
799    else: \
800        DEFAULT_SYSCONFDIR = etc/xdg
801
802    processQtPath("", headerdir, include)
803    processQtPath("", libdir, lib)
804    processQtPath("", bindir, bin)
805    processQtPath("", datadir, .)
806    !equals(config.rel_input.datadir, .): \
807        data_pfx = $$config.rel_input.datadir/
808    processQtPath("", docdir, $${data_pfx}doc)
809    processQtPath("", translationdir, $${data_pfx}translations)
810    processQtPath("", examplesdir, $${data_pfx}examples)
811    processQtPath("", testsdir, tests)
812    processQtPath("", archdatadir, .)
813    !equals(config.rel_input.archdatadir, .): \
814        archdata_pfx = $$config.rel_input.archdatadir/
815    processQtPath("", libexecdir, $${archdata_pfx}$$DEFAULT_LIBEXEC)
816    processQtPath("", plugindir, $${archdata_pfx}plugins)
817    processQtPath("", importdir, $${archdata_pfx}imports)
818    processQtPath("", qmldir, $${archdata_pfx}qml)
819    processQtPath("", sysconfdir, $$DEFAULT_SYSCONFDIR)
820    $$have_hostprefix {
821        processQtPath(host, hostbindir, bin)
822        processQtPath(host, hostlibdir, lib)
823        processQtPath(host, hostdatadir, .)
824    } else {
825        processQtPath(host, hostbindir, $$config.rel_input.bindir)
826        processQtPath(host, hostlibdir, $$config.rel_input.libdir)
827        processQtPath(host, hostdatadir, $$config.rel_input.archdatadir)
828    }
829
830    win32:$$qtConfEvaluate("features.shared") {
831        # Windows DLLs are in the bin dir.
832        libloc_absolute_path = $$absolute_path($$config.rel_input.bindir, $$config.input.prefix)
833    } else {
834        libloc_absolute_path = $$absolute_path($$config.rel_input.libdir, $$config.input.prefix)
835    }
836    config.input.liblocation_to_prefix = $$relative_path($$config.input.prefix, $$libloc_absolute_path)
837    config.qtbase.features.shared.available =
838    export(config.qtbase.features.shared.available)
839
840    hostbindir_absolute_path = $$absolute_path($$config.rel_input.hostbindir, $$config.input.hostprefix)
841    config.input.hostbindir_to_hostprefix = $$relative_path($$config.input.hostprefix, $$hostbindir_absolute_path)
842    config.input.hostbindir_to_extprefix = $$relative_path($$config.input.extprefix, $$hostbindir_absolute_path)
843
844    !isEmpty(PREFIX_COMPLAINTS) {
845        PREFIX_COMPLAINTS = "$$join(PREFIX_COMPLAINTS, "$$escape_expand(\\n)Note: ")"
846        $$PREFIX_REMINDER: \
847            PREFIX_COMPLAINTS += "Maybe you forgot to specify -prefix/-hostprefix?"
848        qtConfAddNote($$PREFIX_COMPLAINTS)
849    }
850
851    # populate qconfig.cpp (for qtcore)
852
853    QT_CONFIGURE_STR_OFF = 0
854    QT_CONFIGURE_STR_OFFSETS =
855    QT_CONFIGURE_STRS =
856
857    addConfStr($$config.rel_input.docdir)
858    addConfStr($$config.rel_input.headerdir)
859    addConfStr($$config.rel_input.libdir)
860    addConfStr($$config.rel_input.libexecdir)
861    addConfStr($$config.rel_input.bindir)
862    addConfStr($$config.rel_input.plugindir)
863    addConfStr($$config.rel_input.importdir)
864    addConfStr($$config.rel_input.qmldir)
865    addConfStr($$config.rel_input.archdatadir)
866    addConfStr($$config.rel_input.datadir)
867    addConfStr($$config.rel_input.translationdir)
868    addConfStr($$config.rel_input.examplesdir)
869    addConfStr($$config.rel_input.testsdir)
870
871    QT_CONFIGURE_STR_OFFSETS_ALL = $$QT_CONFIGURE_STR_OFFSETS
872    QT_CONFIGURE_STRS_ALL = $$QT_CONFIGURE_STRS
873    QT_CONFIGURE_STR_OFFSETS =
874    QT_CONFIGURE_STRS =
875
876    addConfStr($$config.input.sysroot)
877    addConfStr($$qmake_sysrootify)
878    addConfStr($$config.rel_input.hostbindir)
879    addConfStr($$config.rel_input.hostlibdir)
880    addConfStr($$config.rel_input.hostdatadir)
881    addConfStr($$XSPEC)
882    addConfStr($$[QMAKE_SPEC])
883
884    $${currentConfig}.output.qconfigSource = \
885        "/* Installation Info */" \
886        "static const char qt_configure_prefix_path_str  [12+256] = \"qt_prfxpath=$$config.input.prefix\";" \
887        "$${LITERAL_HASH}ifdef QT_BUILD_QMAKE" \
888        "static const char qt_configure_ext_prefix_path_str   [12+256] = \"qt_epfxpath=$$config.input.extprefix\";" \
889        "static const char qt_configure_host_prefix_path_str  [12+256] = \"qt_hpfxpath=$$config.input.hostprefix\";" \
890        "$${LITERAL_HASH}endif" \
891        "" \
892        "static const short qt_configure_str_offsets[] = {" \
893        $$QT_CONFIGURE_STR_OFFSETS_ALL \
894        "$${LITERAL_HASH}ifdef QT_BUILD_QMAKE" \
895        $$QT_CONFIGURE_STR_OFFSETS \
896        "$${LITERAL_HASH}endif" \
897        "};" \
898        "static const char qt_configure_strs[] =" \
899        $$QT_CONFIGURE_STRS_ALL \
900        "$${LITERAL_HASH}ifdef QT_BUILD_QMAKE" \
901        $$QT_CONFIGURE_STRS \
902        "$${LITERAL_HASH}endif" \
903        ";" \
904        "" \
905        "$${LITERAL_HASH}define QT_CONFIGURE_SETTINGS_PATH \"$$config.rel_input.sysconfdir\"" \
906        "$${LITERAL_HASH}define QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH \"$$config.input.liblocation_to_prefix\"" \
907        "$${LITERAL_HASH}define QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH \"$$config.input.hostbindir_to_extprefix\"" \
908        "$${LITERAL_HASH}define QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH \"$$config.input.hostbindir_to_hostprefix\"" \
909        "" \
910        "$${LITERAL_HASH}ifdef QT_BUILD_QMAKE" \
911        "$${LITERAL_HASH} define QT_CONFIGURE_SYSROOTIFY_PREFIX $$qmake_sysrootify" \
912        "$${LITERAL_HASH} define QT_CONFIGURE_CROSSBUILD $$qmake_crossbuild" \
913        "$${LITERAL_HASH}endif" \
914        "" \
915        "$${LITERAL_HASH}define QT_CONFIGURE_PREFIX_PATH qt_configure_prefix_path_str + 12" \
916        "$${LITERAL_HASH}ifdef QT_BUILD_QMAKE" \
917        "$${LITERAL_HASH} define QT_CONFIGURE_EXT_PREFIX_PATH qt_configure_ext_prefix_path_str + 12" \
918        "$${LITERAL_HASH} define QT_CONFIGURE_HOST_PREFIX_PATH qt_configure_host_prefix_path_str + 12" \
919        "$${LITERAL_HASH}endif"
920    export($${currentConfig}.output.qconfigSource)
921
922    # create bin/qt.conf. this doesn't use the regular file output
923    # mechanism, as the file is relied upon by configure tests.
924
925    cont = \
926        "[EffectivePaths]" \
927        "Prefix=.." \
928        "[DevicePaths]" \
929        "Prefix=$$config.input.prefix" \
930        $$printInstallPaths() \
931        "[Paths]" \
932        "Prefix=$$config.input.extprefix" \
933        $$printInstallPaths() \
934        $$printHostPaths()
935    !equals(QT_SOURCE_TREE, $$QT_BUILD_TREE): \
936        cont += \
937            "[EffectiveSourcePaths]" \
938            "Prefix=$$[QT_INSTALL_PREFIX/src]"
939    write_file($$QT_BUILD_TREE/bin/qt.conf, cont)|error()
940    reload_properties()
941
942    # if a sysroot was configured, the spec will be reloaded later,
943    # as some specs contain $$[SYSROOT] references.
944}
945
946defineTest(qtConfOutput_reloadSpec) {
947    !isEmpty($${currentConfig}.output.devicePro)| \
948            !isEmpty(config.input.sysroot): \
949        reloadSpec()
950
951    # toolchain.prf uses this.
952    dummy = $$qtConfEvaluate("features.cross_compile")
953
954    bypassNesting() {
955        QMAKE_INTERNAL_INCLUDED_FEATURES -= \
956            $$[QT_HOST_DATA/src]/mkspecs/features/mac/toolchain.prf \
957            $$[QT_HOST_DATA/src]/mkspecs/features/toolchain.prf
958        load(toolchain)
959    }
960}
961
962defineTest(qtConfOutput_shared) {
963    !$${2}: return()
964
965    # export this here, so later tests can use it
966    CONFIG += shared
967    export(CONFIG)
968}
969
970defineTest(qtConfOutput_sanitizer) {
971    !$${2}: return()
972
973    # Export this here, so that WebEngine can access it at configure time.
974    CONFIG += sanitizer
975    $$qtConfEvaluate("features.sanitize_address"): CONFIG += sanitize_address
976    $$qtConfEvaluate("features.sanitize_thread"): CONFIG += sanitize_thread
977    $$qtConfEvaluate("features.sanitize_memory"): CONFIG += sanitize_memory
978    $$qtConfEvaluate("features.sanitize_undefined"): CONFIG += sanitize_undefined
979
980    export(CONFIG)
981}
982
983defineTest(qtConfOutput_architecture) {
984    arch = $$qtConfEvaluate("tests.architecture.arch")
985    subarch = $$qtConfEvaluate('tests.architecture.subarch')
986    buildabi = $$qtConfEvaluate("tests.architecture.buildabi")
987
988    $$qtConfEvaluate("features.cross_compile") {
989        host_arch = $$qtConfEvaluate("tests.host_architecture.arch")
990        host_buildabi = $$qtConfEvaluate("tests.host_architecture.buildabi")
991
992        privatePro = \
993            "host_build {" \
994            "    QT_CPU_FEATURES.$$host_arch = $$qtConfEvaluate('tests.host_architecture.subarch')" \
995            "} else {" \
996            "    QT_CPU_FEATURES.$$arch = $$subarch" \
997            "}"
998        publicPro = \
999            "host_build {" \
1000            "    QT_ARCH = $$host_arch" \
1001            "    QT_BUILDABI = $$host_buildabi" \
1002            "    QT_TARGET_ARCH = $$arch" \
1003            "    QT_TARGET_BUILDABI = $$buildabi" \
1004            "} else {" \
1005            "    QT_ARCH = $$arch" \
1006            "    QT_BUILDABI = $$buildabi" \
1007            "}"
1008
1009    } else {
1010        privatePro = \
1011            "QT_CPU_FEATURES.$$arch = $$subarch"
1012        publicPro = \
1013            "QT_ARCH = $$arch" \
1014            "QT_BUILDABI = $$buildabi"
1015    }
1016
1017    $${currentConfig}.output.publicPro += $$publicPro
1018    export($${currentConfig}.output.publicPro)
1019    $${currentConfig}.output.privatePro += $$privatePro
1020    export($${currentConfig}.output.privatePro)
1021
1022    # setup QT_ARCH and QT_CPU_FEATURES variables used by qtConfEvaluate
1023    QT_ARCH = $$arch
1024    export(QT_ARCH)
1025    QT_CPU_FEATURES.$$arch = $$subarch
1026    export(QT_CPU_FEATURES.$$arch)
1027}
1028
1029defineTest(qtConfOutput_qreal) {
1030    qreal = $$config.input.qreal
1031    isEmpty(qreal): qreal = "double"
1032    qreal_string = $$replace(qreal, [^a-zA-Z0-9], "_")
1033    qtConfOutputVar(assign, "privatePro", "QT_COORD_TYPE", $$qreal)
1034    !equals(qreal, "double") {
1035        qtConfOutputSetDefine("publicHeader", "QT_COORD_TYPE", $$qreal)
1036        qtConfOutputSetDefine("publicHeader", "QT_COORD_TYPE_STRING", "\"$$qreal_string\"")
1037    }
1038}
1039
1040defineTest(qtConfOutput_pkgConfig) {
1041    !$${2}: return()
1042
1043    PKG_CONFIG_EXECUTABLE = $$eval($${currentConfig}.tests.pkg-config.pkgConfig)
1044    qtConfOutputVar(assign, "privatePro", "PKG_CONFIG_EXECUTABLE", $$PKG_CONFIG_EXECUTABLE)
1045    export(PKG_CONFIG_EXECUTABLE)
1046    # this method also exports PKG_CONFIG_(LIB|SYSROOT)DIR, so that tests using pkgConfig will work correctly
1047    PKG_CONFIG_SYSROOT_DIR = $$eval($${currentConfig}.tests.pkg-config.pkgConfigSysrootDir)
1048    !isEmpty(PKG_CONFIG_SYSROOT_DIR) {
1049        qtConfOutputVar(assign, "publicPro", "PKG_CONFIG_SYSROOT_DIR", $$PKG_CONFIG_SYSROOT_DIR)
1050        export(PKG_CONFIG_SYSROOT_DIR)
1051    }
1052    PKG_CONFIG_LIBDIR = $$eval($${currentConfig}.tests.pkg-config.pkgConfigLibdir)
1053    !isEmpty(PKG_CONFIG_LIBDIR) {
1054        qtConfOutputVar(assign, "publicPro", "PKG_CONFIG_LIBDIR", $$PKG_CONFIG_LIBDIR)
1055        export(PKG_CONFIG_LIBDIR)
1056    }
1057}
1058
1059defineTest(qtConfOutput_crossCompile) {
1060    !$${2}: return()
1061
1062    # We need to preempt the output here, as subsequent tests rely on it
1063    CONFIG += cross_compile
1064    export(CONFIG)
1065}
1066
1067defineTest(qtConfOutput_useBFDLinker) {
1068    !$${2}: return()
1069
1070    # We need to preempt the output here, so that qtConfTest_linkerSupportsFlag can work properly in qtbase
1071    CONFIG += use_bfd_linker
1072    export(CONFIG)
1073}
1074
1075defineTest(qtConfOutput_useGoldLinker) {
1076    !$${2}: return()
1077
1078    # We need to preempt the output here, so that qtConfTest_linkerSupportsFlag can work properly in qtbase
1079    CONFIG += use_gold_linker
1080    export(CONFIG)
1081}
1082
1083defineTest(qtConfOutput_useLLDLinker) {
1084    !$${2}: return()
1085
1086    # We need to preempt the output here, so that qtConfTest_linkerSupportsFlag can work properly in qtbase
1087    CONFIG += use_lld_linker
1088    export(CONFIG)
1089}
1090
1091defineTest(qtConfOutput_debugAndRelease) {
1092    $$qtConfEvaluate("features.debug") {
1093        qtConfOutputVar(append, "publicPro", "CONFIG", "debug")
1094        $${2}: qtConfOutputVar(append, "publicPro", "QT_CONFIG", "release")
1095        qtConfOutputVar(append, "publicPro", "QT_CONFIG", "debug")
1096    } else {
1097        qtConfOutputVar(append, "publicPro", "CONFIG", "release")
1098        $${2}: qtConfOutputVar(append, "publicPro", "QT_CONFIG", "debug")
1099        qtConfOutputVar(append, "publicPro", "QT_CONFIG", "release")
1100    }
1101}
1102
1103defineTest(qtConfOutput_compilerFlags) {
1104    # this output also exports the variables locally, so that subsequent compiler tests can use them
1105
1106    output =
1107    !isEmpty(config.input.wflags) {
1108        wflags = $$join(config.input.wflags, " -W", "-W")
1109        QMAKE_CFLAGS_WARN_ON += $$wflags
1110        QMAKE_CXXFLAGS_WARN_ON += $$wflags
1111        export(QMAKE_CFLAGS_WARN_ON)
1112        export(QMAKE_CXXFLAGS_WARN_ON)
1113        output += \
1114            "QMAKE_CFLAGS_WARN_ON += $$wflags" \
1115            "QMAKE_CXXFLAGS_WARN_ON += $$wflags"
1116    }
1117    !isEmpty(config.input.defines) {
1118        EXTRA_DEFINES += $$config.input.defines
1119        export(EXTRA_DEFINES)
1120        output += "EXTRA_DEFINES += $$val_escape(config.input.defines)"
1121    }
1122    !isEmpty(config.input.includes) {
1123        EXTRA_INCLUDEPATH += $$config.input.includes
1124        export(EXTRA_INCLUDEPATH)
1125        output += "EXTRA_INCLUDEPATH += $$val_escape(config.input.includes)"
1126    }
1127
1128    !isEmpty(config.input.lpaths) {
1129        EXTRA_LIBDIR += $$config.input.lpaths
1130        export(EXTRA_LIBDIR)
1131        output += "EXTRA_LIBDIR += $$val_escape(config.input.lpaths)"
1132    }
1133    darwin:!isEmpty(config.input.fpaths) {
1134        EXTRA_FRAMEWORKPATH += $$config.input.fpaths
1135        export(EXTRA_FRAMEWORKPATH)
1136        output += "EXTRA_FRAMEWORKPATH += $$val_escape(config.input.fpaths)"
1137    }
1138
1139    $${currentConfig}.output.privatePro += $$output
1140    export($${currentConfig}.output.privatePro)
1141}
1142
1143defineTest(qtConfOutput_gccSysroot) {
1144    !$${2}: return()
1145
1146    # This variable also needs to be exported immediately, so the compilation tests
1147    # can pick it up.
1148    EXTRA_QMAKE_ARGS += \
1149        "\"QMAKE_CFLAGS += --sysroot=$$config.input.sysroot\"" \
1150        "\"QMAKE_CXXFLAGS += --sysroot=$$config.input.sysroot\"" \
1151        "\"QMAKE_LFLAGS += --sysroot=$$config.input.sysroot\""
1152    export(EXTRA_QMAKE_ARGS)
1153
1154    # This one is for qtConfToolchainSupportsFlag().
1155    QMAKE_CXXFLAGS += --sysroot=$$config.input.sysroot
1156    export(QMAKE_CXXFLAGS)
1157
1158    output = \
1159        "!host_build {" \
1160        "    QMAKE_CFLAGS    += --sysroot=\$\$[QT_SYSROOT]" \
1161        "    QMAKE_CXXFLAGS  += --sysroot=\$\$[QT_SYSROOT]" \
1162        "    QMAKE_LFLAGS    += --sysroot=\$\$[QT_SYSROOT]" \
1163        "}"
1164    $${currentConfig}.output.publicPro += $$output
1165    export($${currentConfig}.output.publicPro)
1166}
1167
1168defineTest(qtConfOutput_qmakeArgs) {
1169    !$${2}: return()
1170
1171    $${currentConfig}.output.privatePro += "!host_build|!cross_compile {"
1172    for (a, config.input.qmakeArgs) {
1173        $${currentConfig}.output.privatePro += "    $$a"
1174        EXTRA_QMAKE_ARGS += $$system_quote($$a)
1175    }
1176    $${currentConfig}.output.privatePro += "}"
1177    export(EXTRA_QMAKE_ARGS)
1178    export($${currentConfig}.output.privatePro)
1179}
1180
1181defineReplace(qtConfOutputPostProcess_publicPro) {
1182    qt_version = $$[QT_VERSION]
1183    output = \
1184        $$1 \
1185        "QT_VERSION = $$qt_version" \
1186        "QT_MAJOR_VERSION = $$section(qt_version, '.', 0, 0)" \
1187        "QT_MINOR_VERSION = $$section(qt_version, '.', 1, 1)" \
1188        "QT_PATCH_VERSION = $$section(qt_version, '.', 2, 2)"
1189
1190    #libinfix and namespace
1191    !isEmpty(config.input.qt_libinfix): output += "QT_LIBINFIX = $$config.input.qt_libinfix"
1192    !isEmpty(config.input.qt_namespace): output += "QT_NAMESPACE = $$config.input.qt_namespace"
1193
1194    !isEmpty(QMAKE_GCC_MAJOR_VERSION) {
1195        output += \
1196            "QT_GCC_MAJOR_VERSION = $$QMAKE_GCC_MAJOR_VERSION" \
1197            "QT_GCC_MINOR_VERSION = $$QMAKE_GCC_MINOR_VERSION" \
1198            "QT_GCC_PATCH_VERSION = $$QMAKE_GCC_PATCH_VERSION"
1199    }
1200    !isEmpty(QMAKE_MAC_SDK_VERSION): \
1201        output += "QT_MAC_SDK_VERSION = $$QMAKE_MAC_SDK_VERSION"
1202    !isEmpty(QMAKE_CLANG_MAJOR_VERSION) {
1203        output += \
1204            "QT_CLANG_MAJOR_VERSION = $$QMAKE_CLANG_MAJOR_VERSION" \
1205            "QT_CLANG_MINOR_VERSION = $$QMAKE_CLANG_MINOR_VERSION" \
1206            "QT_CLANG_PATCH_VERSION = $$QMAKE_CLANG_PATCH_VERSION"
1207    }
1208    !isEmpty(QMAKE_APPLE_CLANG_MAJOR_VERSION) {
1209        output += \
1210            "QT_APPLE_CLANG_MAJOR_VERSION = $$QMAKE_APPLE_CLANG_MAJOR_VERSION" \
1211            "QT_APPLE_CLANG_MINOR_VERSION = $$QMAKE_APPLE_CLANG_MINOR_VERSION" \
1212            "QT_APPLE_CLANG_PATCH_VERSION = $$QMAKE_APPLE_CLANG_PATCH_VERSION"
1213    }
1214    !isEmpty(QMAKE_MSC_VER) {
1215        output += \
1216            "QT_MSVC_MAJOR_VERSION = $$replace(QMAKE_MSC_FULL_VER, "(..)(..)(.*)", "\\1")" \
1217            "QT_MSVC_MINOR_VERSION = $$format_number($$replace(QMAKE_MSC_FULL_VER, "(..)(..)(.*)", "\\2"))" \
1218            "QT_MSVC_PATCH_VERSION = $$replace(QMAKE_MSC_FULL_VER, "(..)(..)(.*)", "\\3")"
1219    }
1220    !isEmpty(QMAKE_ICC_VER) {
1221        output += \
1222            "QT_ICC_MAJOR_VERSION = $$replace(QMAKE_ICC_VER, "(..)(..)", "\\1")" \
1223            "QT_ICC_MINOR_VERSION = $$format_number($$replace(QMAKE_ICC_VER, "(..)(..)", "\\2"))" \
1224            "QT_ICC_PATCH_VERSION = $$QMAKE_ICC_UPDATE_VER"
1225    }
1226    !isEmpty(QMAKE_GHS_VERSION) {
1227        output += \
1228            "QT_GHS_MAJOR_VERSION = $$replace(QMAKE_GHS_VERSION, "(.*)(.)(.)", "\\1")" \
1229            "QT_GHS_MINOR_VERSION = $$replace(QMAKE_GHS_VERSION, "(.*)(.)(.)", "\\2")" \
1230            "QT_GHS_PATCH_VERSION = $$replace(QMAKE_GHS_VERSION, "(.*)(.)(.)", "\\3")"
1231    }
1232
1233    output += "QT_EDITION = $$config.input.qt_edition"
1234    !contains(config.input.qt_edition, "(OpenSource|Preview)") {
1235        output += \
1236            "QT_LICHECK = $$config.input.qt_licheck" \
1237            "QT_RELEASE_DATE = $$config.input.qt_release_date"
1238    }
1239
1240    wasm: {
1241        qt_emcc_version = $$qtSystemEmccVersion()
1242        output += \
1243           "QT_EMCC_VERSION = $$qt_emcc_version"
1244    }
1245
1246    return($$output)
1247}
1248
1249defineReplace(qtConfOutputPostProcess_privatePro) {
1250    output = $$1
1251
1252    !isEmpty(config.input.external-hostbindir): \
1253        output += "HOST_QT_TOOLS = $$val_escape(config.input.external-hostbindir)"
1254
1255    return($$output)
1256}
1257
1258defineReplace(qtConfOutputPostProcess_publicHeader) {
1259    qt_version = $$[QT_VERSION]
1260    output = \
1261        $$1 \
1262        "$${LITERAL_HASH}define QT_VERSION_STR \"$$qt_version\"" \
1263        "$${LITERAL_HASH}define QT_VERSION_MAJOR $$section(qt_version, '.', 0, 0)" \
1264        "$${LITERAL_HASH}define QT_VERSION_MINOR $$section(qt_version, '.', 1, 1)" \
1265        "$${LITERAL_HASH}define QT_VERSION_PATCH $$section(qt_version, '.', 2, 2)"
1266
1267    !$$qtConfEvaluate("features.shared") {
1268        output += \
1269            "/* Qt was configured for a static build */" \
1270            "$${LITERAL_HASH}if !defined(QT_SHARED) && !defined(QT_STATIC)" \
1271            "$${LITERAL_HASH} define QT_STATIC" \
1272            "$${LITERAL_HASH}endif"
1273    }
1274
1275    !isEmpty(config.input.qt_libinfix): \
1276        output += "$${LITERAL_HASH}define QT_LIBINFIX \"$$eval(config.input.qt_libinfix)\""
1277
1278    wasm: {
1279        qt_emcc_version = $$qtSystemEmccVersion()
1280output += \
1281           "$${LITERAL_HASH}define QT_EMCC_VERSION \"$$qt_emcc_version\""
1282    }
1283
1284    return($$output)
1285}
1286
1287
1288# custom reporting
1289
1290defineTest(qtConfReport_buildParts) {
1291    qtConfReportPadded($${1}, $$qtConfEvaluate("tests.build_parts.value"))
1292}
1293
1294defineReplace(qtConfReportArch) {
1295    arch = $$qtConfEvaluate('tests.$${1}.arch')
1296    subarch = $$qtConfEvaluate('tests.$${1}.subarch')
1297    isEmpty(subarch): subarch = <none>
1298    return("$$arch, CPU features: $$subarch")
1299}
1300
1301defineReplace(qtConfReportCompiler) {
1302    clang_cl: {
1303        return("clang-cl $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}")
1304    } else: clang {
1305        !isEmpty(QMAKE_APPLE_CLANG_MAJOR_VERSION) {
1306            return("clang (Apple) $${QMAKE_APPLE_CLANG_MAJOR_VERSION}.$${QMAKE_APPLE_CLANG_MINOR_VERSION}.$${QMAKE_APPLE_CLANG_PATCH_VERSION}")
1307        } else {
1308            return("clang $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}")
1309        }
1310    } else: intel_icc {
1311        return("intel_icc $$QMAKE_ICC_VER")
1312    } else: intel_icl {
1313        return("intel_icl $$QMAKE_ICC_VER")
1314    } else: rim_qcc {
1315        return("rim_qcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}")
1316    } else: gcc {
1317        return("gcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}")
1318    } else: msvc {
1319        return("msvc $$QMAKE_MSC_FULL_VER")
1320    } else: ghs {
1321        return("ghs $$QMAKE_GHS_VERSION")
1322    } else {
1323        return("unknown ($$QMAKE_COMPILER)")
1324    }
1325}
1326
1327
1328defineTest(qtConfReport_buildTypeAndConfig) {
1329    !$$qtConfEvaluate("features.cross_compile") {
1330        qtConfAddReport("Build type: $$[QMAKE_SPEC] ($$qtConfReportArch(architecture))")
1331        qtConfAddReport("Compiler: $$qtConfReportCompiler()")
1332    } else {
1333        qtConfAddReport("Building on: $$[QMAKE_SPEC] ($$qtConfReportArch(host_architecture))")
1334        qtConfAddReport("Building for: $$[QMAKE_XSPEC] ($$qtConfReportArch(architecture))")
1335        qtConfAddReport("Target compiler: $$qtConfReportCompiler()")
1336    }
1337
1338    qtConfAddReport()
1339    qtConfAddReport("Configuration: $$eval($${currentConfig}.output.privatePro.append.CONFIG) $$eval($${currentConfig}.output.publicPro.append.QT_CONFIG)")
1340    qtConfAddReport()
1341}
1342
1343defineTest(qtConfReport_buildMode) {
1344    $$qtConfEvaluate("features.force_debug_info"): \
1345        release = "release (with debug info)"
1346    else: \
1347        release = "release"
1348
1349    $$qtConfEvaluate("features.debug") {
1350        build_mode = "debug"
1351        raw_build_mode = "debug"
1352    } else {
1353        build_mode = $$release
1354        raw_build_mode = "release"
1355    }
1356
1357    $$qtConfEvaluate("features.debug_and_release"): \
1358        build_mode = "debug and $$release; default link: $$raw_build_mode"
1359
1360    $$qtConfEvaluate("features.release_tools"): \
1361        build_mode = "$$build_mode; optimized tools"
1362
1363    qtConfReportPadded($$1, $$build_mode)
1364}
1365
1366defineTest(qtConfReport_emccVersion) {
1367    EMCC_VERSION = $$qtSystemEmccVersion()
1368    REQ_VERSION = $$qtEmccRecommendedVersion()
1369    !equals(EMCC_VERSION, $$REQ_VERSION) {
1370        qtConfAddReport("You should use the recommended Emscripten version $$REQ_VERSION with this Qt. You have $$EMCC_VERSION $$QT_EMCC_VERSION")
1371    }
1372}
1373
1374# ensure pristine environment for configuration
1375discard_from($$[QT_HOST_DATA/get]/mkspecs/qconfig.pri)
1376discard_from($$[QT_HOST_DATA/get]/mkspecs/qmodule.pri)
1377# ... and cause them to be reloaded afterwards
1378QMAKE_POST_CONFIGURE += \
1379    "include(\$\$[QT_HOST_DATA/get]/mkspecs/qconfig.pri)" \
1380    "include(\$\$[QT_HOST_DATA/get]/mkspecs/qmodule.pri)"
1381
1382defineTest(createConfigStatus) {
1383    $$QMAKE_REDO_CONFIG: return()
1384    cfg = $$relative_path($$_PRO_FILE_PWD_/configure, $$OUT_PWD)
1385    ext =
1386    equals(QMAKE_HOST.os, Windows) {
1387        ext = .bat
1388        cont = \
1389            "$$system_quote($$system_path($$cfg)$$ext) -redo %*"
1390    } else {
1391        !contains(cfg, .*/.*): cfg = ./$$cfg
1392        cont = \
1393            "$${LITERAL_HASH}!/bin/sh" \
1394            "exec $$system_quote($$cfg) -redo \"$@\""
1395    }
1396    write_file($$OUT_PWD/config.status$$ext, cont, exe)|error()
1397}
1398
1399QMAKE_POST_CONFIGURE += \
1400    "createConfigStatus()"
1401