qt5base-lts/mkspecs/features/qt_configure.prf

1210 lines
35 KiB
Plaintext
Raw Normal View History

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")
} 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))
isEmpty(pkg_config): \
return(false)
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))
isEmpty(pkg_config): \
return(false)
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"
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
}
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): \
QMAKE_MAKE = "$$QMAKE_MAKE clean && $$QMAKE_MAKE"
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, [-.], _))
test = $$eval($${1}.test)
isEmpty(test): \
error("Output type 'library' used in feature '$$eval($${1}.feature)' without a 'test' entry.")
lookup = "config.tests.$$test"
isEmpty($${lookup}._KEYS_): \
error("Output type 'library' used in feature '$$eval($${1}.feature)' refers to undefined test '$$test'.")
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()