ce7df6ac7d
Started-by: Lars Knoll <lars.knoll@qt.io> Change-Id: I29bafc5913cf95d9908dbcdd9597df2258b69837 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
1595 lines
48 KiB
Plaintext
1595 lines
48 KiB
Plaintext
CONFIG -= qt debug_and_release
|
|
load(configure_base)
|
|
|
|
QMAKE_CONFIG_CACHE = $$dirname(_QMAKE_CACHE_)/config.cache
|
|
QMAKE_CONFIG_CACHE_USE = all
|
|
|
|
QT_CONFIGURE_REPORT =
|
|
QT_CONFIGURE_NOTES =
|
|
QT_CONFIGURE_WARNINGS =
|
|
QT_CONFIGURE_ERRORS =
|
|
|
|
defineTest(qtConfAddReport) {
|
|
QT_CONFIGURE_REPORT += "$$join(1, $$escape_expand(\\n))"
|
|
export(QT_CONFIGURE_REPORT)
|
|
}
|
|
|
|
defineTest(qtConfAddNote) {
|
|
QT_CONFIGURE_NOTES += "Note: $$join(1, $$escape_expand(\\n))"
|
|
export(QT_CONFIGURE_NOTES)
|
|
}
|
|
|
|
defineTest(qtConfAddWarning) {
|
|
QT_CONFIGURE_WARNINGS += "WARNING: $$join(1, $$escape_expand(\\n))"
|
|
export(QT_CONFIGURE_WARNINGS)
|
|
}
|
|
|
|
defineTest(qtConfAddError) {
|
|
QT_CONFIGURE_ERRORS += "ERROR: $$join(1, $$escape_expand(\\n))"
|
|
export(QT_CONFIGURE_ERRORS)
|
|
equals(2, log) {
|
|
CONFIG += mention_config_log
|
|
export(CONFIG)
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfCommandlineSetInput) {
|
|
arg = $${1}
|
|
val = $${2}
|
|
!isEmpty(config.commandline.options.$${arg}.name): \
|
|
arg = $$eval(config.commandline.options.$${arg}.name)
|
|
|
|
config.input.$$arg = $$val
|
|
export(config.input.$$arg)
|
|
}
|
|
|
|
defineReplace(qtConfGetNextCommandlineArg) {
|
|
c = $$take_first(QMAKE_EXTRA_ARGS)
|
|
export(QMAKE_EXTRA_ARGS)
|
|
return($$c)
|
|
}
|
|
|
|
defineReplace(qtConfPeekNextCommandlineArg) {
|
|
return($$first(QMAKE_EXTRA_ARGS))
|
|
}
|
|
|
|
defineTest(qtConfCommandline_boolean) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
isEmpty(val): val = yes
|
|
|
|
!equals(val, yes):!equals(val, no) {
|
|
qtConfAddError("Invalid value given for boolean command line option '$$opt'.")
|
|
return()
|
|
}
|
|
|
|
qtConfCommandlineSetInput($$opt, $$val)
|
|
}
|
|
|
|
defineTest(qtConfCommandline_void) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
!isEmpty(val) {
|
|
qtConfAddError("Command line option '$$opt' expects no argument ('$$val' given).")
|
|
return()
|
|
}
|
|
|
|
val = $$eval(config.commandline.options.$${opt}.value)
|
|
isEmpty(val): val = yes
|
|
|
|
qtConfCommandlineSetInput($$opt, $$val)
|
|
}
|
|
|
|
defineTest(qtConfCommandline_enum) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
isEmpty(val): val = yes
|
|
|
|
# validate and map value
|
|
mapped = $$eval(config.commandline.options.$${opt}.values.$${val})
|
|
isEmpty(mapped) {
|
|
# just a list of allowed values
|
|
for (i, config.commandline.options.$${opt}.values._KEYS_) {
|
|
equals(config.commandline.options.$${opt}.values.$${i}, $$val) {
|
|
mapped = $$val
|
|
break()
|
|
}
|
|
}
|
|
}
|
|
isEmpty(mapped) {
|
|
qtConfAddError("Invalid value '$$val' supplied to command line option '$$opt'.")
|
|
return()
|
|
}
|
|
|
|
qtConfCommandlineSetInput($$opt, $$mapped)
|
|
}
|
|
|
|
defineTest(qtConfValidateValue) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
|
|
validValues = $$eval(config.commandline.options.$${opt}.values._KEYS_)
|
|
isEmpty(validValues): \
|
|
return(true)
|
|
|
|
for (i, validValues) {
|
|
equals(config.commandline.options.$${opt}.values.$${i}, $$val): \
|
|
return(true)
|
|
}
|
|
|
|
qtConfAddError("Invalid value '$$val' supplied to command line option '$$opt'.")
|
|
return(false)
|
|
}
|
|
|
|
defineTest(qtConfCommandline_string) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
isEmpty(val): val = $$qtConfGetNextCommandlineArg()
|
|
|
|
# Note: Arguments which are variable assignments are legit here.
|
|
contains(val, "^-.*")|isEmpty(val) {
|
|
qtConfAddError("No value supplied to command line option '$$opt'.")
|
|
return()
|
|
}
|
|
|
|
!qtConfValidateValue($$opt, $$val): \
|
|
return()
|
|
|
|
qtConfCommandlineSetInput($$opt, $$val)
|
|
}
|
|
|
|
defineTest(qtConfCommandline_optionalString) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
isEmpty(val) {
|
|
v = $$qtConfPeekNextCommandlineArg()
|
|
contains(v, "^-.*|[A-Z_]+=.*")|isEmpty(v): \
|
|
val = "yes"
|
|
else: \
|
|
val = $$qtConfGetNextCommandlineArg()
|
|
}
|
|
|
|
!qtConfValidateValue($$opt, $$val): \
|
|
return()
|
|
|
|
qtConfCommandlineSetInput($$opt, $$val)
|
|
}
|
|
|
|
|
|
defineTest(qtConfCommandline_addString) {
|
|
opt = $${1}
|
|
val = $${2}
|
|
isEmpty(val): val = $$qtConfGetNextCommandlineArg()
|
|
|
|
contains(val, "^-.*|[A-Z_]+=.*")|isEmpty(val) {
|
|
qtConfAddError("No value supplied to command line option '$$opt'.")
|
|
return()
|
|
}
|
|
|
|
!qtConfValidateValue($$opt, $$val): \
|
|
return()
|
|
|
|
!isEmpty(config.commandline.options.$${opt}.name): \
|
|
opt = $$eval(config.commandline.options.$${opt}.name)
|
|
|
|
config.input.$$opt += $$val
|
|
export(config.input.$$opt)
|
|
}
|
|
|
|
defineTest(qtConfParseCommandLine) {
|
|
custom = $$config.commandline.custom
|
|
customCall =
|
|
!isEmpty(custom) {
|
|
customCall = qtConfCommandline_$$custom
|
|
!defined($$customCall, test): \
|
|
error("Custom command line callback '$$custom' is undefined.")
|
|
}
|
|
|
|
for (ever) {
|
|
c = $$qtConfGetNextCommandlineArg()
|
|
isEmpty(c): break()
|
|
|
|
# handle options to turn on verbose logging
|
|
contains(c, "^-v")|contains(c, "^--?verbose") {
|
|
QMAKE_CONFIG_VERBOSE = true
|
|
export(QMAKE_CONFIG_VERBOSE)
|
|
next()
|
|
}
|
|
contains(c, "^-no-v")|contains(c, "^--?no-verbose") {
|
|
QMAKE_CONFIG_VERBOSE = false
|
|
export(QMAKE_CONFIG_VERBOSE)
|
|
next()
|
|
}
|
|
|
|
contains(c, "^--?recheck") {
|
|
QMAKE_CONFIG_CACHE_USE = positive
|
|
export(QMAKE_CONFIG_CACHE_USE)
|
|
next()
|
|
}
|
|
contains(c, "^--?recheck-all") {
|
|
QMAKE_CONFIG_CACHE_USE = none
|
|
export(QMAKE_CONFIG_CACHE_USE)
|
|
next()
|
|
}
|
|
|
|
!isEmpty(customCall) {
|
|
$${customCall}($$c): \
|
|
next()
|
|
}
|
|
|
|
contains(c, "([A-Z_]+)=(.*)") {
|
|
opt = $$replace(c, "^([A-Z_]+)=(.*)", "\\1")
|
|
val = $$replace(c, "^([A-Z_]+)=(.*)", "\\2")
|
|
var = $$eval(config.commandline.assignments.$${opt})
|
|
isEmpty(var) {
|
|
qtConfAddError("Assigning unknown variable '$$opt' on command line.")
|
|
return()
|
|
}
|
|
config.input.$$var = $$val
|
|
export(config.input.$$var)
|
|
next()
|
|
}
|
|
|
|
# parse out opt and val
|
|
contains(c, "^--?enable-(.*)") {
|
|
opt = $$replace(c, "^--?enable-(.*)", "\\1")
|
|
val = yes
|
|
} else: contains(c, "^--?(disable|no)-(.*)") {
|
|
opt = $$replace(c, "^--?(disable|no)-(.*)", "\\2")
|
|
val = no
|
|
} else: contains(c, "^--?qt-(.*)") {
|
|
opt = $$replace(c, "^--?qt-(.*)", "\\1")
|
|
val = qt
|
|
} else: contains(c, "^--?system-(.*)") {
|
|
opt = $$replace(c, "^--?system-(.*)", "\\1")
|
|
val = system
|
|
} else: contains(c, "^--?([^-].*)=(.*)") {
|
|
opt = $$replace(c, "^--?([^-].*)=(.*)", "\\1")
|
|
val = $$replace(c, "^--?([^-].*)=(.*)", "\\2")
|
|
} else: contains(c, "^--?([^-].*)") {
|
|
opt = $$replace(c, "^--?([^-].*)", "\\1")
|
|
val =
|
|
} else {
|
|
qtConfAddError("Invalid command line parameter '$$c'.")
|
|
return()
|
|
}
|
|
|
|
type = $$eval(config.commandline.options.$${opt})
|
|
isEmpty(type): \
|
|
type = $$eval(config.commandline.options.$${opt}.type)
|
|
isEmpty(type) {
|
|
# no match in the regular options, try matching the prefixes
|
|
for (p, config.commandline.prefix._KEYS_) {
|
|
e = "^-$${p}(.*)"
|
|
contains(c, $$e) {
|
|
opt = $$eval(config.commandline.prefix.$${p})
|
|
val = $$replace(c, $$e, "\\1")
|
|
type = "addString"
|
|
break()
|
|
}
|
|
}
|
|
}
|
|
# handle builtin [-no]-feature-xxx
|
|
isEmpty(type):contains(opt, "feature-(.*)") {
|
|
# simply skip for now
|
|
next()
|
|
}
|
|
|
|
isEmpty(type) {
|
|
qtConfAddError("Unknown command line option '$$c'.")
|
|
return()
|
|
}
|
|
|
|
call = "qtConfCommandline_$${type}"
|
|
!defined($$call, test): \
|
|
error("Command line option '$$c' has unknown type '$$type'.")
|
|
|
|
# now that we have opt and value, process it
|
|
$${call}($$opt, $$val)
|
|
}
|
|
}
|
|
|
|
defineReplace(qtConfToolchainSupportsFlag) {
|
|
test_out_dir = $$shadowed($$QMAKE_CONFIG_TESTS_DIR)
|
|
test_cmd_base = "cd $$system_quote($$system_path($$test_out_dir)) &&"
|
|
|
|
conftest = "int main() { return 0; }"
|
|
write_file("$$test_out_dir/conftest.cpp", conftest)|error()
|
|
|
|
qtRunLoggedCommand("$$test_cmd_base $$QMAKE_CXX $${1} -o conftest-out conftest.cpp"): \
|
|
return(true)
|
|
return(false)
|
|
}
|
|
|
|
defineTest(qtConfTest_compilerSupportsFlag) {
|
|
flag = $$eval($${1}.flag)
|
|
|
|
return($$qtConfToolchainSupportsFlag($$flag))
|
|
}
|
|
|
|
defineTest(qtConfTest_linkerSupportsFlag) {
|
|
flag = $$eval($${1}.flag)
|
|
|
|
use_gold_linker: \
|
|
LFLAGS = -fuse-ld=gold
|
|
|
|
return($$qtConfToolchainSupportsFlag($$LFLAGS "-Wl,$$flag"))
|
|
}
|
|
|
|
defineReplace(qtConfFindInPathList) {
|
|
for (dir, 2) {
|
|
exists("$$dir/$${1}"): \
|
|
return("$$dir/$${1}")
|
|
}
|
|
return()
|
|
}
|
|
|
|
defineReplace(qtConfFindInPath) {
|
|
ensurePathEnv()
|
|
return($$qtConfFindInPathList($$1, $$2 $$QMAKE_PATH_ENV))
|
|
}
|
|
|
|
defineReplace(qtConfPkgConfigEnv) {
|
|
env =
|
|
!isEmpty(PKG_CONFIG_SYSROOT_DIR): env = "$${SETENV_PFX}PKG_CONFIG_SYSROOT_DIR=$${PKG_CONFIG_SYSROOT_DIR}$${SETENV_SFX} "
|
|
!isEmpty(PKG_CONFIG_LIBDIR): env = "$$env$${SETENV_PFX}PKG_CONFIG_LIBDIR=$${PKG_CONFIG_LIBDIR}$${SETENV_SFX} "
|
|
return($$env)
|
|
}
|
|
|
|
defineReplace(qtConfPkgConfig) {
|
|
host = $$1
|
|
isEmpty(host): host = false
|
|
|
|
$$host {
|
|
pkg_config = $$qtConfFindInPath("pkg-config")
|
|
} else {
|
|
pkg_config = "$$qtConfPkgConfigEnv()$$PKG_CONFIG"
|
|
}
|
|
|
|
return($$pkg_config)
|
|
}
|
|
|
|
defineTest(qtConfPkgConfigPackageExists) {
|
|
isEmpty(1)|isEmpty(2): \
|
|
return(false)
|
|
|
|
!qtRunLoggedCommand("$${1} --exists --silence-errors $${2}"): \
|
|
return(false)
|
|
|
|
return(true)
|
|
}
|
|
|
|
defineReplace(qtConfPrepareArgs) {
|
|
arglist = $$split(1)
|
|
args =
|
|
for (a, arglist): \
|
|
args += $$system_quote($$a)
|
|
return($$args)
|
|
}
|
|
|
|
defineTest(qtConfSetupLibraries) {
|
|
for (l, config.libraries._KEYS_) {
|
|
lpfx = config.libraries.$${l}
|
|
# 'export' may be omitted, in which case it falls back to the library's name
|
|
!defined($${lpfx}.export, var) {
|
|
$${lpfx}.export = $$l
|
|
export($${lpfx}.export)
|
|
}
|
|
isEmpty($${lpfx}.sources._KEYS_): \
|
|
error("Library $$l defines no sources")
|
|
for (s, $${lpfx}.sources._KEYS_) {
|
|
spfx = $${lpfx}.sources.$${s}
|
|
# link back to parent object
|
|
$${spfx}.library = $$l
|
|
export($${spfx}.library)
|
|
# a plain string is transformed into a structure
|
|
isEmpty($${spfx}._KEYS_) {
|
|
$${spfx}.libs = $$eval($${spfx})
|
|
export($${spfx}.libs)
|
|
}
|
|
# if the type is missing (implicitly in the case of plain strings), assume 'inline'
|
|
isEmpty($${spfx}.type) {
|
|
$${spfx}.type = inline
|
|
export($${spfx}.type)
|
|
}
|
|
}
|
|
}
|
|
|
|
# reverse mapping for assignments on command line.
|
|
for (a, config.commandline.assignments._KEYS_) {
|
|
apfx = config.commandline.assignments.$${a}
|
|
ra = config.commandline.rev_assignments.$$eval($$apfx)
|
|
$$ra = $$a
|
|
export($$ra)
|
|
}
|
|
}
|
|
|
|
# the library is specified inline in a 'libs' field.
|
|
# overrides from the command line are accepted.
|
|
defineTest(qtConfLibrary_inline) {
|
|
lib = $$eval($${1}.library)
|
|
!defined($${1}.libs, var): \
|
|
error("'inline' source in library '$$lib' does not specify 'libs'.")
|
|
|
|
# direct libs. overwrites inline libs.
|
|
defined(config.input.$${lib}.libs, var) {
|
|
$${1}.libs = $$eval(config.input.$${lib}.libs)
|
|
export($${1}.libs)
|
|
}
|
|
|
|
# build-specific direct libs. overwrites inline libs.
|
|
vars =
|
|
any = false
|
|
all = true
|
|
for (b, $${1}.builds._KEYS_) {
|
|
iv = $${lib}.libs.$${b}
|
|
vars += $$eval(config.commandline.rev_assignments.$${iv})
|
|
defined(config.input.$${iv}, var) {
|
|
$${1}.builds.$${b}.libs = $$eval(config.input.$${iv})
|
|
export($${1}.builds.$${b}.libs)
|
|
any = true
|
|
} else {
|
|
all = false
|
|
}
|
|
}
|
|
$$any:!$$all {
|
|
qtConfAddError("Either none or all of $$join(vars, ", ", [, ]) must be specified.")
|
|
return(false)
|
|
}
|
|
|
|
# prefix. prepends to (possibly overwritten) inline libs.
|
|
prefix = $$val_escape(config.input.$${lib}.prefix)
|
|
!isEmpty(prefix) {
|
|
$${1}.includedir = $$prefix/include
|
|
export($${1}.includedir)
|
|
$${1}.cflags = -I$$prefix/include
|
|
export($${1}.cflags)
|
|
$${1}.libs = "-L$$prefix/lib $$eval($${1}.libs)"
|
|
export($${1}.libs)
|
|
}
|
|
|
|
return(true)
|
|
}
|
|
|
|
# the library is provided by the qmake spec.
|
|
# this source type cannot fail.
|
|
defineTest(qtConfLibrary_makeSpec) {
|
|
spec = $$eval($${1}.spec)
|
|
isEmpty(spec): \
|
|
error("makeSpec source in library '$$eval($${1}.library)' does not specify 'spec'.")
|
|
|
|
$${1}.includedir = "$$val_escape(QMAKE_INCDIR_$$spec)"
|
|
export($${1}.includedir)
|
|
$${1}.cflags = "$$val_escape(QMAKE_CFLAGS_$$spec)"
|
|
export($${1}.cflags)
|
|
libs =
|
|
for (l, QMAKE_LIBDIR_$$spec): \
|
|
libs += -L$$l
|
|
libs += $$eval(QMAKE_LIBS_$$spec)
|
|
$${1}.libs = "$$val_escape(libs)"
|
|
export($${1}.libs)
|
|
|
|
# the library definition is always in scope, so no point in exporting it.
|
|
$${1}.export = false
|
|
export($${1}.export)
|
|
|
|
return(true)
|
|
}
|
|
|
|
# the library is found via pkg-config.
|
|
defineTest(qtConfLibrary_pkgConfig) {
|
|
pkg_config = $$qtConfPkgConfig($$eval($${1}.host))
|
|
isEmpty(pkg_config): \
|
|
return(false)
|
|
args = $$qtConfPrepareArgs($$eval($${1}.args))
|
|
|
|
!qtConfPkgConfigPackageExists($$pkg_config, $$args): \
|
|
return(false)
|
|
|
|
qtRunLoggedCommand("$$pkg_config --modversion $$args", version)|return(false)
|
|
qtRunLoggedCommand("$$pkg_config --libs $$args", $${1}.libs)|return(false)
|
|
qtRunLoggedCommand("$$pkg_config --cflags $$args", $${1}.cflags)|return(false)
|
|
qtRunLoggedCommand("$$pkg_config --cflags-only-I $$args", includes)|return(false)
|
|
eval(includes = $$includes)
|
|
includes ~= s/^-I//g
|
|
$${1}.includedir = "$$val_escape(includes)"
|
|
$${1}.version = $$first(version)
|
|
export($${1}.libs)
|
|
export($${1}.cflags)
|
|
export($${1}.includedir)
|
|
export($${1}.version)
|
|
return(true)
|
|
}
|
|
|
|
defineTest(qtConfTest_getPkgConfigVariable) {
|
|
pkg_config = $$qtConfPkgConfig($$eval($${1}.host))
|
|
isEmpty(pkg_config): \
|
|
return(false)
|
|
args = $$qtConfPrepareArgs($$eval($${1}.pkg-config-args))
|
|
|
|
!qtConfPkgConfigPackageExists($$pkg_config, $$args): \
|
|
return(false)
|
|
|
|
variable = $$eval($${1}.pkg-config-variable)
|
|
qtRunLoggedCommand("$$pkg_config --variable=$$variable $$args", $${1}.value)|return(false)
|
|
export($${1}.value)
|
|
$${1}.cache += value
|
|
export($${1}.cache)
|
|
return(true)
|
|
}
|
|
|
|
defineReplace(qtConfLibraryArgs) {
|
|
qmake_args =
|
|
libs = $$eval($${1}.libs)
|
|
!isEmpty(libs): \
|
|
qmake_args += $$system_quote(LIBS += $$libs)
|
|
for (b, $${1}.builds._KEYS_): \
|
|
qmake_args += $$system_quote(LIBS_$$upper($$b) += $$eval($${1}.builds.$${b}))
|
|
includedir = $$eval($${1}.includedir)
|
|
!isEmpty(includedir): \
|
|
qmake_args += $$system_quote(INCLUDEPATH *= $$includedir)
|
|
return($$qmake_args)
|
|
}
|
|
|
|
defineReplace(qtConfGetHexVersion) {
|
|
version = $$split(1, '.')
|
|
number =
|
|
for(i, 0..2) {
|
|
n = $$member(version, $$i)
|
|
isEmpty(n): n = 0
|
|
number += $$format_number($$n, obase=16 zeropad width=2)
|
|
}
|
|
number = "0x$$join(number)"
|
|
return($$number)
|
|
}
|
|
|
|
defineTest(qtConfExportLibrary) {
|
|
isEmpty(2): return()
|
|
!$$qtConfEvaluate($$eval($${1}.export)): return()
|
|
|
|
output = privatePro
|
|
|
|
eval(libs = $$eval($${1}.libs))
|
|
eval(cflags = $$eval($${1}.cflags))
|
|
eval(includes = $$eval($${1}.includedir))
|
|
version = $$eval($${1}.version)
|
|
|
|
NAME = $$upper($$2)
|
|
!isEmpty(libs): qtConfOutputVar(assign, $$output, QMAKE_LIBS_$$NAME, $$libs)
|
|
for (b, $${1}.builds._KEYS_): \
|
|
qtConfOutputVar(assign, $$output, QMAKE_LIBS_$${NAME}_$$upper($$b), \
|
|
$$eval($${1}.builds.$${b}))
|
|
!isEmpty(cflags): qtConfOutputVar(assign, $$output, QMAKE_CFLAGS_$$NAME, $$cflags)
|
|
!isEmpty(includes): qtConfOutputVar(assign, $$output, QMAKE_INCDIR_$$NAME, $$includes)
|
|
!isEmpty(version) {
|
|
qtConfOutputVar(assign, $$output, QMAKE_$${NAME}_VERSION, $$version)
|
|
qtConfOutputSetDefine("privateHeader", "QT_LIBRARY_VERSION_$${2}", $$qtConfGetHexVersion($$version))
|
|
version = $$split(version, '.')
|
|
qtConfOutputVar(assign, $$output, QMAKE_$${NAME}_VERSION_MAJOR, $$member(version, 0))
|
|
qtConfOutputVar(assign, $$output, QMAKE_$${NAME}_VERSION_MINOR, $$member(version, 1))
|
|
qtConfOutputVar(assign, $$output, QMAKE_$${NAME}_VERSION_PATCH, $$member(version, 2))
|
|
}
|
|
export(config.output.$${output})
|
|
}
|
|
|
|
defineTest(qtConfHandleLibrary) {
|
|
lpfx = config.libraries.$$1
|
|
defined($${lpfx}.result, var): return()
|
|
|
|
qtConfEnsureTestTypeDeps("library")
|
|
|
|
qtConfLoadResult($${lpfx}, $$1) {
|
|
qtConfExportLibrary($${lpfx}.sources.$$eval($${lpfx}.source), $$eval($${lpfx}.export))
|
|
return()
|
|
}
|
|
|
|
qtLogTestIntro($${lpfx})
|
|
msg = "looking for library $${1}"
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
|
|
result = false
|
|
for (s, $${lpfx}.sources._KEYS_) {
|
|
qtLog("Trying source $$s of library $${1}.")
|
|
spfx = $${lpfx}.sources.$${s}
|
|
|
|
t = $$eval($${spfx}.type)
|
|
call = qtConfLibrary_$$t
|
|
!defined($$call, test): \
|
|
error("Library $${1} source $${s} has unknown type '$$t'")
|
|
|
|
!$$qtConfEvaluate($$eval($${spfx}.condition)) {
|
|
qtLog("Source $$s of library $$1 failed condition.")
|
|
next()
|
|
}
|
|
|
|
!$${call}($$spfx) {
|
|
qtLog("Source $$s of library $$1 produced no result.")
|
|
next()
|
|
}
|
|
|
|
# if the library defines a test, use it to verify the source.
|
|
!isEmpty($${lpfx}.test) {
|
|
$${lpfx}.literal_args = $$qtConfLibraryArgs($$spfx)
|
|
$${lpfx}.host = $$eval($${spfx}.host)
|
|
!qtConfTest_compile($$lpfx) {
|
|
qtLog("Source $$s of library $$1 failed verification.")
|
|
next()
|
|
}
|
|
}
|
|
|
|
$${lpfx}.cache += source
|
|
for (v, $$list(libs includes cflags version export)): \
|
|
$${lpfx}.cache += sources.$${s}.$${v}
|
|
for (b, $${spfx}.builds._KEYS_): \
|
|
$${lpfx}.cache += sources.$${s}.builds.$${b}
|
|
|
|
# immediately output the library as well.
|
|
qtConfExportLibrary($${spfx}, $$eval($${lpfx}.export))
|
|
|
|
$${lpfx}.source = $$s
|
|
export($${lpfx}.source)
|
|
result = true
|
|
break()
|
|
}
|
|
|
|
qtLogTestResult($${lpfx}, $$result)
|
|
|
|
$${lpfx}.result = $$result
|
|
export($${lpfx}.result)
|
|
qtConfSaveResult($${lpfx}, $$1)
|
|
}
|
|
|
|
# This is a fake test type for the test dependency system.
|
|
defineTest(qtConfTest_library) {
|
|
error("The test type 'library' may not be instantiated.")
|
|
}
|
|
|
|
defineTest(qtConfTestPrepare_compile) {
|
|
for (u, $$list($$eval($${1}.use))) {
|
|
!contains(config.libraries._KEYS_, $$u): \
|
|
error("Test $$1 tries to use undeclared library '$$u'")
|
|
qtConfHandleLibrary($$u)
|
|
lpfx = config.libraries.$${u}
|
|
isEmpty($${lpfx}.source): \
|
|
return(false)
|
|
$${1}.literal_args += $$qtConfLibraryArgs($${lpfx}.sources.$$eval($${lpfx}.source))
|
|
}
|
|
export($${1}.literal_args)
|
|
return(true)
|
|
}
|
|
|
|
defineTest(qtConfTest_compile) {
|
|
test = $$eval($${1}.test)
|
|
host = $$eval($${1}.host)
|
|
isEmpty(host): host = false
|
|
|
|
test_dir = $$QMAKE_CONFIG_TESTS_DIR/$$test
|
|
test_out_dir = $$shadowed($$test_dir)
|
|
!isEmpty($${1}.pro): \
|
|
test_dir = $$test_dir/$$eval($${1}.pro)
|
|
test_cmd_base = "cd $$system_quote($$system_path($$test_out_dir)) &&"
|
|
|
|
qmake_args = $$qtConfPkgConfigEnv()$$system_quote($$system_path($$QMAKE_QMAKE))
|
|
!isEmpty(QMAKE_QTCONF): \
|
|
qmake_args += -qtconf $$system_quote($$QMAKE_QTCONF)
|
|
|
|
# Disable qmake features which are typically counterproductive for tests
|
|
qmake_args += "\"CONFIG -= qt debug_and_release app_bundle lib_bundle\""
|
|
|
|
# allow tests to behave differently depending on the type of library
|
|
# being built (shared/static). e.g. see config.tests/unix/icu
|
|
shared: \
|
|
qmake_configs = "shared"
|
|
else: \
|
|
qmake_configs = "static"
|
|
|
|
use_gold_linker: \
|
|
qmake_configs += "use_gold_linker"
|
|
|
|
# add console to the CONFIG variable when running the tests, so that they
|
|
# can work with a regular main() entry point on Windows.
|
|
qmake_configs += "console"
|
|
|
|
qmake_args += "\"CONFIG += $$qmake_configs\""
|
|
|
|
!$$host {
|
|
# On WinRT we need to change the entry point as we cannot create windows
|
|
# applications
|
|
winrt: \
|
|
qmake_args += " \"QMAKE_LFLAGS += /ENTRY:main\""
|
|
|
|
# add compiler flags, these are set for the target and should not be applied to host tests
|
|
!isEmpty(EXTRA_DEFINES): \
|
|
qmake_args += $$system_quote(DEFINES += $$val_escape(EXTRA_DEFINES))
|
|
!isEmpty(EXTRA_LIBDIR) \
|
|
qmake_args += $$system_quote(QMAKE_LIBDIR += $$val_escape(EXTRA_LIBDIR))
|
|
!isEmpty(EXTRA_FRAMEWORKPATH) \
|
|
qmake_args += $$system_quote(QMAKE_FRAMEWORKPATH += $$val_escape(EXTRA_FRAMEWORKPATH))
|
|
!isEmpty(EXTRA_INCLUDEPATH): \
|
|
qmake_args += $$system_quote(INCLUDEPATH += $$val_escape(EXTRA_INCLUDEPATH))
|
|
qmake_args += $$EXTRA_QMAKE_ARGS
|
|
}
|
|
|
|
# Clean up after previous run
|
|
exists($$test_out_dir/Makefile): \
|
|
QMAKE_MAKE = "$$QMAKE_MAKE clean && $$QMAKE_MAKE"
|
|
|
|
mkpath($$test_out_dir)|error()
|
|
|
|
# add possible command line args
|
|
qmake_args += $$qtConfPrepareArgs($$eval($${1}.args)) $$eval($${1}.literal_args)
|
|
|
|
qtRunLoggedCommand("$$test_cmd_base $$qmake_args $$system_quote($$test_dir)") {
|
|
qtRunLoggedCommand("$$test_cmd_base $$QMAKE_MAKE"): \
|
|
return(true)
|
|
}
|
|
|
|
return(false)
|
|
}
|
|
|
|
defineTest(qtConfTest_verifySpec) {
|
|
qtConfTest_compile($$1): return(true)
|
|
qtConfAddError("Cannot compile a minimal program. The toolchain or QMakeSpec is broken.", log)
|
|
qtConfPrintReport()
|
|
error()
|
|
}
|
|
|
|
defineTest(qtConfTest_files) {
|
|
for(i, $${1}.files._KEYS_) {
|
|
f = $$eval($${1}.files.$${i})
|
|
qtLog("Searching for file $${f}.")
|
|
contains(f, ".*\.h") {
|
|
file = $$qtConfFindInPathList($$f, $$EXTRA_INCLUDEPATH $$QMAKE_DEFAULT_INCDIRS)
|
|
} else: contains(f, ".*\.(lib|so|a)") {
|
|
file = $$qtConfFindInPathList($$f, $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS)
|
|
} else {
|
|
# assume we're looking for an executable
|
|
file = $$qtConfFindInPath($$f, $$EXTRA_PATH)
|
|
}
|
|
isEmpty(file) {
|
|
qtLog(" Not found.");
|
|
return(false)
|
|
}
|
|
qtLog(" Found at $${file}.")
|
|
}
|
|
return(true)
|
|
}
|
|
|
|
defineTest(logn) {
|
|
log("$${1}$$escape_expand(\\n)")
|
|
}
|
|
|
|
defineTest(qtLogTestIntro) {
|
|
description = $$eval($${1}.description)
|
|
isEmpty(description): return()
|
|
|
|
msg = "Checking for $${description}... "
|
|
log($$msg)
|
|
$$QMAKE_CONFIG_VERBOSE: log("$$escape_expand(\\n)")
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
}
|
|
|
|
defineTest(qtLogTestResult) {
|
|
isEmpty($${1}.description): return()
|
|
|
|
!isEmpty($${1}.log) {
|
|
field = $$eval($${1}.log)
|
|
log_msg = $$eval($${1}.$$field)
|
|
msg = "test $$1 gave result $$log_msg"
|
|
} else: $${2} {
|
|
log_msg = yes
|
|
msg = "test $$1 succeeded"
|
|
} else {
|
|
log_msg = no
|
|
msg = "test $$1 FAILED"
|
|
}
|
|
$$QMAKE_CONFIG_VERBOSE: log_msg = $$msg
|
|
logn("$$log_msg")
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
}
|
|
|
|
defineTest(qtConfSaveResult) {
|
|
keys = result $$eval($${1}.cache)
|
|
cont = "cache.$${2}._KEYS_ = $$keys"
|
|
for (k, keys): \
|
|
cont += "cache.$${2}.$${k} = $$val_escape($${1}.$${k})"
|
|
write_file($$QMAKE_CONFIG_CACHE, cont, append)|error()
|
|
}
|
|
|
|
defineTest(qtConfLoadResult) {
|
|
equals(QMAKE_CONFIG_CACHE_USE, none): \
|
|
return(false)
|
|
isEmpty(cache.$${2}._KEYS_): \
|
|
return(false)
|
|
equals(QMAKE_CONFIG_CACHE_USE, positive):!$$eval(cache.$${2}.result): \
|
|
return(false)
|
|
for (k, cache.$${2}._KEYS_) {
|
|
$${1}.$${k} = $$eval(cache.$${2}.$${k})
|
|
export($${1}.$${k})
|
|
}
|
|
return(true)
|
|
}
|
|
|
|
defineTest(qtConfIsBoolean) {
|
|
equals(1, "true")|equals(1, "false"): \
|
|
return(true)
|
|
return(false)
|
|
}
|
|
|
|
defineTest(qtConfSetupTestTypeDeps) {
|
|
for (tt, config.testTypeDependencies._KEYS_) {
|
|
!defined(qtConfTest_$${tt}, test): \
|
|
error("Declaring dependency for undefined test type '$$tt'.")
|
|
for (f, config.testTypeDependencies.$${tt}._KEYS_) {
|
|
feature = $$eval(config.testTypeDependencies.$${tt}.$${f})
|
|
isEmpty(config.features.$${feature}._KEYS_): \
|
|
error("Test type '$$tt' depends on undefined feature '$$feature'.")
|
|
}
|
|
}
|
|
# Test type aliasing means that one test type's callback is called by
|
|
# another test type's callback. Put differently, one callback forwards
|
|
# the call to another one. The former representation is more natural
|
|
# (and concise) to write, while the latter is more efficient to process.
|
|
# Hence, this function inverts the mapping.
|
|
for (tt, config.testTypeAliases._KEYS_) {
|
|
!defined(qtConfTest_$${tt}, test): \
|
|
error("Aliasing undefined test type '$$tt'.")
|
|
for (tta, config.testTypeAliases.$${tt}._KEYS_) {
|
|
type = $$eval(config.testTypeAliases.$${tt}.$${tta})
|
|
!defined(qtConfTest_$${type}, test): \
|
|
error("Aliasing '$$tt' to undefined test type '$$type'.")
|
|
config.testTypeForwards.$${type} += $$tt
|
|
export(config.testTypeForwards.$${type})
|
|
}
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfEnsureTestTypeDeps) {
|
|
depsn = config.testTypeDependencies.$${1}._KEYS_
|
|
!isEmpty($$depsn) {
|
|
for (dep, $$depsn) {
|
|
feature = $$eval(config.testTypeDependencies.$${1}.$${dep})
|
|
!qtConfCheckFeature($$feature): \
|
|
error("Test type '$$1' depends on non-emitted feature $${feature}.")
|
|
}
|
|
$$depsn =
|
|
export($$depsn)
|
|
}
|
|
fwdsn = config.testTypeForwards.$${1}
|
|
!isEmpty($$fwdsn) {
|
|
for (fwd, $$fwdsn): \
|
|
qtConfEnsureTestTypeDeps($$fwd)
|
|
$$fwdsn =
|
|
export($$fwdsn)
|
|
}
|
|
}
|
|
|
|
defineTest(qtRunSingleTest) {
|
|
tpfx = config.tests.$${1}
|
|
defined($${tpfx}.result, var): \
|
|
return()
|
|
result = true
|
|
|
|
type = $$eval($${tpfx}.type)
|
|
call = "qtConfTest_$$type"
|
|
!defined($$call, test): \
|
|
error("Configure test $${1} refers to nonexistent type $$type")
|
|
|
|
qtConfEnsureTestTypeDeps($$type)
|
|
|
|
preCall = "qtConfTestPrepare_$$type"
|
|
defined($$preCall, test): \
|
|
!$${preCall}($${tpfx}): result = false
|
|
|
|
$$result {
|
|
# note: we do this only after resolving the dependencies and the
|
|
# preparation (which may resolve libraries), so that caching does
|
|
# not alter the execution order (and thus the output).
|
|
qtConfLoadResult($${tpfx}, $$1): \
|
|
return()
|
|
|
|
qtLogTestIntro($${tpfx})
|
|
msg = "executing config test $${1}"
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
|
|
!$${call}($${tpfx}): result = false
|
|
|
|
qtLogTestResult($${tpfx}, $$result)
|
|
}
|
|
|
|
$${tpfx}.result = $$result
|
|
export($${tpfx}.result)
|
|
qtConfSaveResult($${tpfx}, $$1)
|
|
}
|
|
|
|
defineReplace(qtConfEvaluate) {
|
|
isEmpty(1): return(true)
|
|
|
|
1 ~= s/$$escape_expand(\\t)/ /g
|
|
1 ~= s/$$escape_expand(\\r)//g
|
|
1 ~= s/$$escape_expand(\\n) */ /g
|
|
expr = $${1}
|
|
expr ~= s/&&/ && /g
|
|
expr ~= s/\|\|/ || /g
|
|
expr ~= s/!/ ! /g
|
|
expr ~= s/\\(/ ( /g
|
|
expr ~= s/\\)/ ) /g
|
|
expr ~= s/ *== */==/g
|
|
expr ~= s/ *! = */!=/g
|
|
expr_list = $$eval($$list($$expr))
|
|
return($$qtConfEvaluateSubExpression($${1}, $$expr_list, 0))
|
|
}
|
|
|
|
defineReplace(qtConfEvaluateSingleExpression) {
|
|
e = $${2}
|
|
|
|
equals(e, true) {
|
|
result = true
|
|
} else: equals(e, false) {
|
|
result = false
|
|
} else: contains(e, "^[0-9]+$") {
|
|
# numbers
|
|
result = $$e
|
|
} else: contains(e, "^'.*'$") {
|
|
# quoted literals
|
|
result = $$replace(e, "^'(.*)'$", "\\1")
|
|
} else: contains(e, "^tests\..*") {
|
|
!qt_conf_tests_allowed: \
|
|
error("Expression '$${1}' refers to a test, which is not allowed at this stage of configuring.")
|
|
test = $$section(e, ".", 1, 1)
|
|
var = $$section(e, ".", 2, -1)
|
|
isEmpty(var): \
|
|
var = result
|
|
!contains(config.tests._KEYS_, $$test): \
|
|
error("Unknown test object $${test} in expression '$${1}'.")
|
|
qtRunSingleTest($$test)
|
|
result = $$eval(config.tests.$${test}.$${var})
|
|
} else: contains(e, "^libs\..*") {
|
|
!qt_conf_tests_allowed: \
|
|
error("Expression '$${1}' refers to a library, which is not allowed at this stage of configuring.")
|
|
lib = $$section(e, ".", 1, 1)
|
|
var = $$section(e, ".", 2, -1)
|
|
isEmpty(var): \
|
|
var = result
|
|
!contains(config.libraries._KEYS_, $$lib): \
|
|
error("Unknown library object $${lib} in expression '$${1}'.")
|
|
qtConfHandleLibrary($$lib)
|
|
!defined(config.libraries.$${lib}.$${var}, var): \
|
|
var = sources.$$eval(config.libraries.$${lib}.$${source}).$$var
|
|
result = $$eval(config.libraries.$${lib}.$${var})
|
|
} else: contains(e, "^features\..*") {
|
|
feature = $$section(e, ".", 1, 1)
|
|
var = $$section(e, ".", 2, -1)
|
|
isEmpty(var): \
|
|
var = available
|
|
!contains(config.features._KEYS_, $$feature): \
|
|
error("Unknown feature object $${feature} in expression '$${1}'.")
|
|
!qtConfCheckFeature($$feature): \
|
|
error("Expression '$$1' is accessing non-emitted feature $${feature}.")
|
|
result = $$eval(config.features.$${feature}.$${var})
|
|
} else: contains(e, "^config\..*") {
|
|
var = $$replace(e, "^config\.", "")
|
|
result = false
|
|
contains(CONFIG, $$var): result = true
|
|
} else: contains(e, "^arch\..*") {
|
|
var = $$replace(e, "^arch\.", "")
|
|
result = false
|
|
isEmpty(QT_ARCH): \
|
|
qtConfCheckFeature(architecture)
|
|
contains(QT_ARCH, $$var): result = true
|
|
} else: contains(e, "^input\..*") {
|
|
result = $$eval(config.$$e)
|
|
} else: contains(e, "^var\..*") {
|
|
var = $$replace(e, "^var\.", "")
|
|
result = $$eval($$var)
|
|
} else: contains(e, "^call\..*") {
|
|
call = $$replace(e, "^call\.", "qtConfFunc_")
|
|
!defined($$call, replace): \
|
|
error("Call $$call referenced in expression '$${1}' does not exist")
|
|
eval(result = \$\$"$$call"())
|
|
} else {
|
|
error("Unrecognized token $$e in expression '$${1}'")
|
|
}
|
|
return($$result)
|
|
}
|
|
|
|
defineReplace(qtConfEvaluateSubExpression) {
|
|
expr_list = $${2}
|
|
result = true
|
|
negate = false
|
|
runSubExpression = false
|
|
nesting_level = 0
|
|
for (n, $${3}..$$num_add($$size(expr_list), -1)) {
|
|
e = $$member(expr_list, $$n)
|
|
$$runSubExpression {
|
|
runSubExpression = false
|
|
result = $$qtConfEvaluateSubExpression($${1}, $$expr_list, $$n)
|
|
} else: isEqual(e, "(") {
|
|
isEqual(nesting_level, 0): runSubExpression = true
|
|
nesting_level = $$num_add($$nesting_level, 1)
|
|
next()
|
|
} else: isEqual(e, ")") {
|
|
nesting_level = $$num_add($$nesting_level, -1)
|
|
lessThan(nesting_level, 0): break()
|
|
next()
|
|
} else: greaterThan(nesting_level, 0) {
|
|
next()
|
|
} else: isEqual(e, "!") {
|
|
negate = true
|
|
next()
|
|
} else: isEqual(e, "&&") {
|
|
!qtConfIsBoolean($$result): \
|
|
error("Left hand side of && is non-boolean value '$$result' in expression '$${1}'")
|
|
!$$result: return(false)
|
|
} else: isEqual(e, "||") {
|
|
!qtConfIsBoolean($$result): \
|
|
error("Left hand side of || is non-boolean value '$$result' in expression '$${1}'")
|
|
$$result: return(true)
|
|
} else {
|
|
contains(e, ".*==.*") {
|
|
lhs = $$qtConfEvaluateSingleExpression($${1}, $$replace(e, "==.*", ""))
|
|
rhs = $$qtConfEvaluateSingleExpression($${1}, $$replace(e, ".*==", ""))
|
|
result = false
|
|
equals(lhs, $$rhs): result = true
|
|
} else: contains(e, ".*!=.*") {
|
|
lhs = $$qtConfEvaluateSingleExpression($${1}, $$replace(e, "!=.*", ""))
|
|
rhs = $$qtConfEvaluateSingleExpression($${1}, $$replace(e, ".*!=", ""))
|
|
result = false
|
|
!equals(lhs, $$rhs): result = true
|
|
} else {
|
|
result = $$qtConfEvaluateSingleExpression($${1}, $$e)
|
|
}
|
|
}
|
|
$$negate {
|
|
!qtConfIsBoolean($$result): \
|
|
error("Attempting to negate a non-boolean value '$$result' in expression '$${1}'")
|
|
$$result: \
|
|
result = false
|
|
else: \
|
|
result = true
|
|
negate = false
|
|
}
|
|
}
|
|
return($$result)
|
|
}
|
|
|
|
defineReplace(qtIsFeatureEnabled) {
|
|
enable = $$eval(config.features.$${1}.enable)
|
|
!isEmpty(enable) {
|
|
$$qtConfEvaluate($$enable): \
|
|
return(true)
|
|
} else {
|
|
equals(config.input.$${1}, "yes"): \
|
|
return(true)
|
|
}
|
|
|
|
return(false)
|
|
}
|
|
|
|
defineReplace(qtIsFeatureDisabled) {
|
|
disable = $$eval(config.features.$${1}.disable)
|
|
!isEmpty(disable) {
|
|
$$qtConfEvaluate($$disable): \
|
|
return(true)
|
|
} else {
|
|
equals(config.input.$${1}, "no"): \
|
|
return(true)
|
|
}
|
|
|
|
return(false)
|
|
}
|
|
|
|
defineReplace(qtConfCheckSingleCondition) {
|
|
result = $$qtConfEvaluate($$2)
|
|
|
|
!qtConfIsBoolean($$result): \
|
|
error("Evaluation of condition '$$2' yielded non-boolean value '$$result' in feature '$${1}'.")
|
|
|
|
!$$result {
|
|
$${3} {
|
|
qtConfAddError("Feature '$${1}' was enabled, but the pre-condition '$$2' failed.", log)
|
|
$$result = true
|
|
}
|
|
}
|
|
return($$result)
|
|
}
|
|
|
|
defineTest(qtConfCheckFeature) {
|
|
fpfx = config.features.$${1}
|
|
|
|
available = $$eval($${fpfx}.available)
|
|
!isEmpty(available): return(true)
|
|
|
|
# skip features that will not get emitted anyway
|
|
emitIf = $$qtConfEvaluate($$eval($${fpfx}.emitIf))
|
|
enabled = $$qtIsFeatureEnabled($$1)
|
|
disabled = $$qtIsFeatureDisabled($$1)
|
|
|
|
!$$emitIf {
|
|
$$enabled|$$disabled: \
|
|
qtConfAddWarning("Feature $${1} is insignificant in this configuration, ignoring related command line option(s).")
|
|
return(false)
|
|
}
|
|
|
|
$$disabled {
|
|
result = false
|
|
} else: !$$enabled:!$$qtConfEvaluate($$eval($${fpfx}.autoDetect)) {
|
|
# feature not auto-detected and not explicitly enabled
|
|
result = false
|
|
} else {
|
|
condition = $$eval($${fpfx}.condition)
|
|
!isEmpty(condition) {
|
|
result = $$qtConfCheckSingleCondition($$1, $$condition, $$enabled)
|
|
} else {
|
|
result = true
|
|
# check whether we have an array of conditions
|
|
for (i, $${fpfx}.condition._KEYS_) {
|
|
condition = $$eval($${fpfx}.condition.$$i)
|
|
result = $$qtConfCheckSingleCondition($$1, $$condition, $$enabled)
|
|
!$$result: break()
|
|
}
|
|
}
|
|
}
|
|
$${fpfx}.available = $$result
|
|
export($${fpfx}.available)
|
|
|
|
for (i, config.features.$${feature}.output._KEYS_): \
|
|
qtConfProcessOneOutput($$feature, $$i)
|
|
|
|
return(true)
|
|
}
|
|
|
|
|
|
defineTest(qtConfProcessFeatures) {
|
|
for (feature, config.features._KEYS_): \
|
|
qtConfCheckFeature($$feature)
|
|
}
|
|
|
|
#
|
|
# reporting
|
|
#
|
|
|
|
QT_CONF_REPORT_PADDING = "........................................"
|
|
|
|
defineTest(qtConfReportPadded) {
|
|
pad = $$num_add($$str_size($$QT_CONF_REPORT_PADDING), -$$str_size($${1}))
|
|
lessThan(pad, 0): pad = 0
|
|
str = "$$1 $$str_member($$QT_CONF_REPORT_PADDING, 0, $$pad)"
|
|
|
|
qtConfAddReport("$$str $${2}")
|
|
}
|
|
|
|
defineReplace(qtConfCollectFeatures) {
|
|
l =
|
|
for (feature, $$list($${1})) {
|
|
$$eval(config.features.$${feature}.available): \
|
|
l += $$eval(config.features.$${feature}.description)
|
|
}
|
|
|
|
isEmpty(l): return("<none>")
|
|
return($$join(l, ' '))
|
|
}
|
|
|
|
defineTest(qtConfReport_featureList) {
|
|
qtConfReportPadded($${1}, $$qtConfCollectFeatures($${2}))
|
|
}
|
|
|
|
defineReplace(qtConfFindFirstAvailableFeature) {
|
|
for (feature, $$list($${1})) {
|
|
isEmpty(config.features.$${feature}._KEYS_): \
|
|
error("Asking for a report on undefined feature $${2}.")
|
|
$$eval(config.features.$${feature}.available): \
|
|
return($$eval(config.features.$${feature}.description))
|
|
}
|
|
|
|
return("<none>")
|
|
}
|
|
|
|
defineTest(qtConfReport_firstAvailableFeature) {
|
|
qtConfReportPadded($${1}, $$qtConfFindFirstAvailableFeature($${2}))
|
|
}
|
|
|
|
defineTest(qtConfReport_feature) {
|
|
!contains(config.features._KEYS_, $$2): \
|
|
error("Asking for a report on undefined feature $${2}.")
|
|
|
|
# hide report for not emitted features
|
|
isEmpty(config.features.$${2}.available): \
|
|
return()
|
|
|
|
$$eval(config.features.$${2}.available) {
|
|
result = "yes"
|
|
!isEmpty(3): result = "$${3}"
|
|
} else {
|
|
result = "no"
|
|
!isEmpty(4): result = "$${4}"
|
|
}
|
|
|
|
text = $$eval(config.features.$${2}.description)
|
|
|
|
qtConfReportPadded($${1}$$text, $$result)
|
|
}
|
|
|
|
defineTest(qtConfReport_note) {
|
|
qtConfAddNote($${1})
|
|
}
|
|
|
|
defineTest(qtConfReport_warning) {
|
|
qtConfAddWarning($${1})
|
|
}
|
|
|
|
defineTest(qtConfReport_error) {
|
|
qtConfAddError($${1}, log)
|
|
}
|
|
|
|
defineTest(qtConfCreateReportRecurse) {
|
|
equals(2, false) {
|
|
indent = ""
|
|
recurse = false
|
|
} else {
|
|
indent = $${2}
|
|
recurse = true
|
|
}
|
|
|
|
keys = $$eval($${1}._KEYS_)
|
|
for (n, keys) {
|
|
entry = $${1}.$$n
|
|
subKeys = $$eval($${entry}._KEYS_)
|
|
contains(subKeys, condition) {
|
|
condition = $$eval($${entry}.condition)
|
|
r = $$qtConfEvaluate($$condition)
|
|
!qtConfIsBoolean($$r): \
|
|
error("Evaluation of condition '$$condition' in report entry $${entry} yielded non-boolean value '$$r'.")
|
|
!$$r: next()
|
|
}
|
|
contains(subKeys, "section") {
|
|
!$$recurse: \
|
|
error("Report type 'section' is not allowed in '$$1'.")
|
|
section = $$eval($${entry}.section)
|
|
qtConfAddReport("$$indent$$section:")
|
|
qtConfCreateReportRecurse("$${entry}.entries", "$$indent ")
|
|
} else: !isEmpty($${entry}) {
|
|
feature = $$eval($${entry})
|
|
qtConfReport_feature($$indent, $$feature)
|
|
} else {
|
|
text = $$eval($${entry}.message)
|
|
isEmpty($${entry}.type): \
|
|
error("Report entry $${entry} doesn't define a type.")
|
|
r = "qtConfReport_$$eval($${entry}.type)"
|
|
!defined($$r, test): \
|
|
error("Undefined report type $$eval($${entry}.type) used in report entry $${entry}.")
|
|
args = $$eval($${entry}.args)
|
|
$${r}($$indent$${text}, $$args)
|
|
}
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfProcessEarlyChecks) {
|
|
qtConfCreateReportRecurse(config.earlyReport, false)
|
|
qtConfCheckErrors()
|
|
}
|
|
|
|
|
|
defineTest(qtConfCreateReport) {
|
|
qtConfAddReport(" ")
|
|
qtConfCreateReportRecurse(config.report, false)
|
|
}
|
|
|
|
defineTest(qtConfCreateSummary) {
|
|
qtConfCreateReportRecurse(config.summary, "")
|
|
}
|
|
|
|
defineTest(qtConfPrintReport) {
|
|
for (n, QT_CONFIGURE_REPORT): \
|
|
logn($$n)
|
|
logn()
|
|
|
|
for (n, QT_CONFIGURE_NOTES) {
|
|
logn($$n)
|
|
logn()
|
|
}
|
|
|
|
for (w, QT_CONFIGURE_WARNINGS) {
|
|
logn($$w)
|
|
logn()
|
|
}
|
|
|
|
!isEmpty(QT_CONFIGURE_ERRORS) {
|
|
for (e, QT_CONFIGURE_ERRORS) {
|
|
logn($$e)
|
|
logn()
|
|
}
|
|
mention_config_log:!$$QMAKE_CONFIG_VERBOSE {
|
|
logn("Check config.log for details.")
|
|
logn()
|
|
}
|
|
|
|
!equals(config.input.continue, yes): \
|
|
error()
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfCheckErrors) {
|
|
!isEmpty(QT_CONFIGURE_ERRORS):!equals(config.input.continue, yes): \
|
|
qtConfPrintReport()
|
|
}
|
|
|
|
#
|
|
# output generation
|
|
#
|
|
|
|
defineReplace(qtConfOutputSelectProFile) {
|
|
!isEmpty($${1}.public) {
|
|
$$eval($${1}.public): \
|
|
return(publicPro)
|
|
}
|
|
return(privatePro)
|
|
}
|
|
|
|
|
|
# qtConfOutputVar(modifier, output, name, value)
|
|
defineTest(qtConfOutputVar) {
|
|
modifier = $$1
|
|
output = $$2
|
|
name = $$3
|
|
value = $$val_escape(4)
|
|
|
|
!isEmpty(config.output.$${output}.assign.$${name}): \
|
|
error("Trying to overwrite assigned variable '$$name' in '$$output' using modifier '$$modifier'.")
|
|
|
|
equals(modifier, assign) {
|
|
!isEmpty(config.output.$${output}.append.$${name})|!isEmpty(config.output.$${output}.remove.$${name}): \
|
|
error("Trying to assign variable '$$name' in '$$output', which has already appended or removed parts.")
|
|
config.output.$${output}.$${modifier}.$${name} = $$value
|
|
} else: equals(modifier, append) {
|
|
contains(config.output.$${output}.remove.$${name}, $$value): \
|
|
error("Trying to append removed '$$value' to variable '$$name' in '$$output'.")
|
|
config.output.$${output}.$${modifier}.$${name} += $$value
|
|
} else: equals(modifier, remove) {
|
|
contains(config.output.$${output}.append.$${name}, $$value): \
|
|
error("Trying to remove appended '$$value' to variable '$$name' in '$$output'.")
|
|
config.output.$${output}.$${modifier}.$${name} += $$value
|
|
} else {
|
|
error("Invalid modifier '$$modifier' passed to qtConfOutputVar.")
|
|
}
|
|
config.output.$${output}.$${modifier}._KEYS_ *= $${name}
|
|
export(config.output.$${output}.$${modifier}.$${name})
|
|
export(config.output.$${output}.$${modifier}._KEYS_)
|
|
}
|
|
|
|
defineTest(qtConfOutputVarHelper) {
|
|
negative = $$eval($${2}.negative)
|
|
isEmpty(negative): negative = false
|
|
!$${3}:!$$negative: return()
|
|
$${3}:$$negative: return()
|
|
|
|
output = $$qtConfOutputSelectProFile($${2})
|
|
name = $$eval($${2}.name)
|
|
isEmpty(name): \
|
|
error("Output type 'var$$title($$1)' used in feature '$$eval($${2}.feature)' without a 'name' entry.")
|
|
|
|
value = $$qtConfEvaluate($$eval($${2}.value))
|
|
!isEmpty($${2}.eval):$$qtConfEvaluate($$eval($${2}.eval)): \
|
|
eval(value = $$value)
|
|
qtConfOutputVar($$1, $$output, $$name, $$value)
|
|
}
|
|
|
|
defineTest(qtConfOutput_varAssign) {
|
|
qtConfOutputVarHelper(assign, $$1, $$2)
|
|
}
|
|
|
|
defineTest(qtConfOutput_varAppend) {
|
|
qtConfOutputVarHelper(append, $$1, $$2)
|
|
}
|
|
|
|
defineTest(qtConfOutput_varRemove) {
|
|
qtConfOutputVarHelper(remove, $$1, $$2)
|
|
}
|
|
|
|
defineTest(qtConfOutputConfigVar) {
|
|
pro = $$3
|
|
var = $$4
|
|
negative = $$eval($${1}.negative)
|
|
isEmpty(negative): negative = false
|
|
|
|
val = $$eval($${1}.name)
|
|
isEmpty(val) {
|
|
val = $$eval($${1}.feature)
|
|
$$negative: val = no-$$val
|
|
}
|
|
|
|
$${2} {
|
|
!$$negative: qtConfOutputVar(append, $$pro, $$var, $$val)
|
|
} else {
|
|
$$negative: qtConfOutputVar(append, $$pro, $$var, $$val)
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfOutput_publicQtConfig) {
|
|
qtConfOutputConfigVar($$1, $$2, "publicPro", "QT_CONFIG")
|
|
}
|
|
|
|
defineTest(qtConfOutput_publicConfig) {
|
|
qtConfOutputConfigVar($$1, $$2, "publicPro", "CONFIG")
|
|
}
|
|
|
|
defineTest(qtConfOutput_privateConfig) {
|
|
qtConfOutputConfigVar($$1, $$2, "privatePro", "CONFIG")
|
|
}
|
|
|
|
defineTest(qtConfOutputSetDefine) {
|
|
config.output.$${1}.$${2} = $${3}
|
|
config.output.$${1}._KEYS_ *= $${2}
|
|
export(config.output.$${1}.$${2})
|
|
export(config.output.$${1}._KEYS_)
|
|
}
|
|
|
|
defineTest(qtConfOutput_define) {
|
|
output = publicHeader
|
|
define = $$eval($${1}.name)
|
|
value = $$qtConfEvaluate($$eval($${1}.value))
|
|
isEmpty(define): \
|
|
error("Output type 'define' used in feature '$$eval($${1}.feature)' without a 'name' entry.")
|
|
|
|
negative = $$eval($${1}.negative)
|
|
isEmpty(negative): negative = false
|
|
|
|
$${2} {
|
|
!$$negative: qtConfOutputSetDefine($$output, $$define, $$value)
|
|
} else {
|
|
$$negative: qtConfOutputSetDefine($$output, $$define, $$value)
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfOutput_feature) {
|
|
name = "$$eval($${1}.name)"
|
|
isEmpty(name): \
|
|
name = $$eval($${1}.feature)
|
|
|
|
$${2} {
|
|
qtConfOutputVar(append, "publicPro", "QT_CONFIG", $$name)
|
|
} else {
|
|
f = $$upper($$replace(name, -, _))
|
|
qtConfOutputSetDefine("publicHeader", "QT_NO_$$f")
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfOutput_publicFeature) {
|
|
name = "$$eval($${1}.name)"
|
|
isEmpty(name): \
|
|
name = $$eval($${1}.feature)
|
|
feature = $$replace(name, [-+.], _)
|
|
|
|
$${2} {
|
|
qtConfOutputVar(append, "publicPro", "QT.global.enabled_features", $$name)
|
|
qtConfOutputSetDefine("publicHeader", "QT_FEATURE_$$feature", 1)
|
|
} else {
|
|
qtConfOutputVar(append, "publicPro", "QT.global.disabled_features", $$name)
|
|
qtConfOutputSetDefine("publicHeader", "QT_FEATURE_$$feature", -1)
|
|
}
|
|
}
|
|
|
|
# currently this is somewhat inconsistent, as the feature is output to the public pro file,
|
|
# whereas the define is being added to the private pro file.
|
|
# This should get cleaned up to add to the private pro and header instead.
|
|
defineTest(qtConfOutput_privateFeature) {
|
|
name = "$$eval($${1}.name)"
|
|
isEmpty(name): \
|
|
name = $$eval($${1}.feature)
|
|
feature = $$replace(name, [-+.], _)
|
|
|
|
$${2} {
|
|
qtConfOutputVar(append, "privatePro", "QT.global.enabled_features", $$name)
|
|
qtConfOutputSetDefine("privateHeader", "QT_FEATURE_$$feature", 1)
|
|
} else {
|
|
qtConfOutputVar(append, "privatePro", "QT.global.disabled_features", $$name)
|
|
qtConfOutputSetDefine("privateHeader", "QT_FEATURE_$$feature", -1)
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfProcessOneOutput) {
|
|
feature = $${1}
|
|
fpfx = config.features.$${feature}
|
|
opfx = $${fpfx}.output.$${2}
|
|
|
|
condition = $$eval($${opfx}.condition)
|
|
!isEmpty(condition):!$$qtConfEvaluate($$condition): \
|
|
return()
|
|
|
|
call = $$eval($${opfx}.type)
|
|
isEmpty(call) {
|
|
# output is just a string, not an object
|
|
call = $$eval($$opfx)
|
|
}
|
|
!defined("qtConfOutput_$$call", test): \
|
|
error("Undefined type '$$call' in output '$$2' of feature '$$feature'.")
|
|
|
|
condition = $$eval($${opfx}.condition)
|
|
!isEmpty(condition) {
|
|
!$$qtConfEvaluate($$condition): \
|
|
return(false)
|
|
}
|
|
|
|
$${opfx}.feature = $$feature
|
|
qtConfOutput_$${call}($$opfx, $$eval($${fpfx}.available))
|
|
}
|
|
|
|
defineTest(qtConfProcessOutput) {
|
|
# write it to the output files
|
|
for (type, config.files._KEYS_) {
|
|
file = $$OUT_PWD/$$eval(config.files.$${type})
|
|
contains(type, ".*Pro") {
|
|
for (k, config.output.$${type}.assign._KEYS_): \
|
|
config.output.$$type += "$$k = $$eval(config.output.$${type}.assign.$$k)"
|
|
for (k, config.output.$${type}.remove._KEYS_): \
|
|
config.output.$$type += "$$k -= $$eval(config.output.$${type}.remove.$$k)"
|
|
for (k, config.output.$${type}.append._KEYS_): \
|
|
config.output.$$type += "$$k += $$eval(config.output.$${type}.append.$$k)"
|
|
} else {
|
|
for (define, config.output.$${type}._KEYS_) {
|
|
value = $$eval(config.output.$${type}.$${define})
|
|
config.output.$$type += "$${LITERAL_HASH}define $$define $$value"
|
|
}
|
|
}
|
|
defined(qtConfOutputPostProcess_$${type}, test): \
|
|
qtConfOutputPostProcess_$${type}()
|
|
|
|
write_file($$file, config.output.$${type})|error()
|
|
}
|
|
}
|
|
|
|
#
|
|
# tie it all together
|
|
#
|
|
|
|
defineTest(qtConfigure) {
|
|
# load configuration data
|
|
configure_data = $$cat($${1}, blob)
|
|
!parseJson(configure_data, config): \
|
|
error("Invalid or non-existent file $${1}.")
|
|
|
|
qtConfSetupLibraries()
|
|
qtConfSetupTestTypeDeps()
|
|
|
|
qtConfParseCommandLine()
|
|
|
|
!equals(QMAKE_CONFIG_CACHE_USE, none) {
|
|
include($$QMAKE_CONFIG_CACHE, , true)
|
|
# this crudely determines when to discard the cache. this also catches the case
|
|
# of no cache being there in the first place.
|
|
!equals(cache.platform, $$[QMAKE_SPEC])|!equals(cache.xplatform, $$[QMAKE_XSPEC]): \
|
|
QMAKE_CONFIG_CACHE_USE = none
|
|
}
|
|
equals(QMAKE_CONFIG_CACHE_USE, none) {
|
|
cont = \
|
|
"cache.platform = $$[QMAKE_SPEC]" \
|
|
"cache.xplatform = $$[QMAKE_XSPEC]"
|
|
write_file($$QMAKE_CONFIG_CACHE, cont)
|
|
}
|
|
|
|
# do early checks, mainly to validate the command line
|
|
qtConfProcessEarlyChecks()
|
|
|
|
CONFIG += qt_conf_tests_allowed
|
|
logn()
|
|
logn("Running configuration tests...")
|
|
|
|
# process all features
|
|
qtConfProcessFeatures()
|
|
|
|
# generate files and reports
|
|
qtConfProcessOutput()
|
|
qtConfCreateReport()
|
|
qtConfCreateSummary()
|
|
|
|
logn("Done running configuration tests.")
|
|
logn()
|
|
}
|
|
|
|
qtConfigure($$_PRO_FILE_PWD_/configure.json)
|
|
|
|
logn("Configure summary:")
|
|
logn()
|
|
|
|
qtConfPrintReport()
|