62838f07d4
standardize on the fields in the json structure being single strings in which separate elements are quoted and space-joined (because quoting is unlikely to be necessary in the json file itself, and this format avoids the visual noise of array handling). the quoting itself is expected to be qmake-compatible, which is assumed to be the case for the output of pkg-config (it's actually shell-quoted, but that's the same except in some not-so-relevant corner cases). Change-Id: Icc1d7abc02c449fa759d9714bc5e56e2b8809585 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
1201 lines
35 KiB
Plaintext
1201 lines
35 KiB
Plaintext
CONFIG -= qt debug_and_release
|
|
load(configure_base)
|
|
|
|
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()
|
|
|
|
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, "^-.*")|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, "^-.*")|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) {
|
|
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()
|
|
}
|
|
|
|
# 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)
|
|
}
|
|
}
|
|
|
|
defineTest(qtConfTest_shell) {
|
|
test = $$eval($${1}.test)
|
|
dir = $$replace(test, [^/]*$, "")
|
|
test = $$replace(test, ([^/]*/)*, "")
|
|
args = $$eval($${1}.args)
|
|
# replace any things like $$QMAKE_CXX by their values
|
|
eval(args = $$args)
|
|
|
|
test_dir = $$QMAKE_CONFIG_TESTS_DIR/$$dir
|
|
test_out_dir = $$shadowed($$test_dir)
|
|
test_cmd_base = "cd $$system_quote($$system_path($$test_out_dir)) &&"
|
|
|
|
mkpath($$test_out_dir)|error()
|
|
|
|
qtRunLoggedCommand("$$test_cmd_base $$test_dir/$${test} $${args}"): \
|
|
return(false)
|
|
return(true)
|
|
}
|
|
|
|
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(qtConfFindInPath) {
|
|
ensurePathEnv()
|
|
for (dir, QMAKE_PATH_ENV) {
|
|
exists("$$dir/$${1}"): \
|
|
return("$$dir/$${1}")
|
|
}
|
|
return()
|
|
}
|
|
|
|
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")
|
|
isEmpty(pkg_config): \
|
|
return(false)
|
|
} 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(qtConfTest_pkgConfig) {
|
|
pkg_config = $$qtConfPkgConfig($$eval($${1}.host))
|
|
args = $$qtConfPrepareArgs($$eval($${1}.pkg-config-args))
|
|
|
|
!qtConfPkgConfigPackageExists($$pkg_config, $$args): \
|
|
return(false)
|
|
|
|
$${1}.libs = $$system("$$pkg_config --libs $$args", lines)
|
|
$${1}.cflags = $$system("$$pkg_config --cflags $$args", lines)
|
|
includes = $$system("$$pkg_config --cflags-only-I $$args", lines)
|
|
eval(includes = $$includes)
|
|
includes ~= s/^-I//g
|
|
$${1}.includedir = "$$val_escape(includes)"
|
|
version = $$system("$$pkg_config --modversion $$args")
|
|
$${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))
|
|
args = $$qtConfPrepareArgs($$eval($${1}.pkg-config-args))
|
|
|
|
!qtConfPkgConfigPackageExists($$pkg_config, $$args): \
|
|
return(false)
|
|
|
|
variable = $$eval($${1}.pkg-config-variable)
|
|
$${1}.value = $$system("$$pkg_config --variable=$$variable $$args")
|
|
export($${1}.value)
|
|
return(true)
|
|
}
|
|
|
|
defineTest(qtConfTest_compile) {
|
|
test = $$eval($${1}.test)
|
|
host = $$eval($${1}.host)
|
|
isEmpty(host): host = false
|
|
|
|
# get package config information
|
|
qtConfTest_pkgConfig($${1})
|
|
|
|
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)) &&"
|
|
|
|
# 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"
|
|
|
|
# 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
|
|
}
|
|
|
|
libs = $$eval($${1}.libs)
|
|
!isEmpty(libs): \
|
|
qmake_args += "\"LIBS += $$libs\""
|
|
|
|
includedir = $$eval($${1}.includedir)
|
|
!isEmpty(includedir): \
|
|
qmake_args += "\"INCLUDEPATH *= $$includedir\""
|
|
|
|
# Clean up after previous run
|
|
exists($$test_out_dir/Makefile): qtRunLoggedCommand("$$test_cmd_base $$QMAKE_MAKE distclean")
|
|
|
|
mkpath($$test_out_dir)|error()
|
|
|
|
!isEmpty(QMAKE_QTCONF): qtconfarg = -qtconf $$QMAKE_QTCONF
|
|
|
|
# add possible command line args
|
|
qmake_args += $$qtConfPrepareArgs($$eval($${1}.args))
|
|
|
|
qtRunLoggedCommand("$$test_cmd_base $$qtConfPkgConfigEnv()$$system_quote($$system_path($$QMAKE_QMAKE)) $$qtconfarg $$qmake_args $$shell_quote($$test_dir)") {
|
|
qtRunLoggedCommand("$$test_cmd_base $$QMAKE_MAKE"): \
|
|
return(true)
|
|
}
|
|
|
|
return(false)
|
|
}
|
|
|
|
defineTest(logn) {
|
|
log("$${1}$$escape_expand(\\n)")
|
|
}
|
|
|
|
defineTest(qtLogTestResult) {
|
|
!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(qtConfIsBoolean) {
|
|
equals(1, "true")|equals(1, "false"): \
|
|
return(true)
|
|
return(false)
|
|
}
|
|
|
|
defineTest(qtRunSingleTest) {
|
|
tpfx = config.tests.$${1}
|
|
defined($${tpfx}.result, var): \
|
|
return()
|
|
|
|
type = $$eval($${tpfx}.type)
|
|
call = "qtConfTest_$$type"
|
|
!defined($$call, test): \
|
|
error("Configure test $${1} refers to nonexistent type $$type")
|
|
|
|
description = $$eval($${tpfx}.description)
|
|
!isEmpty(description) {
|
|
msg = "checking for $${description}... "
|
|
log($$msg)
|
|
$$QMAKE_CONFIG_VERBOSE: log("$$escape_expand(\\n)")
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
}
|
|
|
|
msg = "executing config test $${1}"
|
|
write_file($$QMAKE_CONFIG_LOG, msg, append)
|
|
|
|
result = false
|
|
$${call}($${tpfx}): result = true
|
|
|
|
!isEmpty(description): qtLogTestResult($${tpfx}, $$result)
|
|
$${tpfx}.result = $$result
|
|
export($${tpfx}.result)
|
|
}
|
|
|
|
defineReplace(qtConfEvaluate) {
|
|
isEmpty(1): return(true)
|
|
|
|
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, "^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
|
|
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) {
|
|
priorities = 0
|
|
for (feature, config.features._KEYS_): \
|
|
priorities += $$eval(config.features.$${feature}.priority)
|
|
priorities = $$unique(priorities)
|
|
|
|
for (p, priorities): \
|
|
opriorities += $$format_number($$num_add($$p, 10000), width=5 zeropad)
|
|
opriorities = $$sorted(opriorities)
|
|
|
|
priorities =
|
|
for (op, opriorities): \
|
|
priorities += $$num_add($$op, -10000)
|
|
|
|
for (priority, priorities) {
|
|
for (feature, config.features._KEYS_) {
|
|
p = $$eval(config.features.$${feature}.priority)
|
|
isEmpty(p): p = 0
|
|
equals(p, $$priority): \
|
|
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))
|
|
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")
|
|
}
|
|
}
|
|
|
|
# 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)
|
|
|
|
$${2} {
|
|
qtConfOutputVar(append, "publicPro", "QT_CONFIG", $$name)
|
|
} else {
|
|
f = $$upper($$replace(name, -, _))
|
|
qtConfOutputVar(append, "privatePro", "DEFINES", "QT_NO_$$f")
|
|
}
|
|
}
|
|
|
|
|
|
defineTest(qtConfOutput_library) {
|
|
!$${2}: return()
|
|
|
|
output = privatePro
|
|
name = "$$eval($${1}.name)"
|
|
isEmpty(name): \
|
|
name = $$eval($${1}.feature)
|
|
NAME = $$upper($$replace(name, [-.], _))
|
|
|
|
lookup = "config.tests.$$eval($${1}.test)"
|
|
isEmpty(lookup): \
|
|
error("Output type 'library' used in feature '$$eval($${1}.feature)' without a 'test' entry.")
|
|
|
|
eval(libs = $$eval($${lookup}.libs))
|
|
eval(cflags = $$eval($${lookup}.cflags))
|
|
eval(includes = $$eval($${lookup}.includedir))
|
|
version = $$split($${lookup}.version, '.')
|
|
|
|
!isEmpty(libs): qtConfOutputVar(assign, $$output, QMAKE_LIBS_$$NAME, $$libs)
|
|
!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_MAJOR, $$first(version))
|
|
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(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'.")
|
|
|
|
isEmpty($${opfx}.feature): \
|
|
$${opfx}.feature = $$feature
|
|
|
|
condition = $$eval($${opfx}.condition)
|
|
!isEmpty(condition) {
|
|
!$$qtConfEvaluate($$condition): \
|
|
return(false)
|
|
}
|
|
|
|
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}ifndef $$define"
|
|
config.output.$$type += "$${LITERAL_HASH}define $$define $$value"
|
|
config.output.$$type += "$${LITERAL_HASH}endif"
|
|
}
|
|
}
|
|
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}.")
|
|
|
|
qtConfParseCommandLine()
|
|
|
|
# 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()
|