defineTest(qtToolchainError) { msg = \ $$1 \ "===================" \ $$2 \ "===================" \ $$3 error($$join(msg, $$escape_expand(\\n))) } defineTest(qtCompilerError) { !cross_compile: \ what = else: host_build: \ what = " host" else: \ what = " target" qtToolchainError("Cannot run$$what compiler '$$1'. Output:", $$2, \ "Maybe you forgot to setup the environment?") } cross_compile:host_build: \ target_prefix = QMAKE_HOST_CXX else: \ target_prefix = QMAKE_CXX # # Determine and cache the compiler version # defineReplace(qtVariablesFromMSVC) { ret = $$system("$$1 -nologo -E $$2 $$system_quote($$PWD/data/macros.cpp) 2>NUL", lines, ec) !equals(ec, 0): qtCompilerError($$1, $$ret) return($$ret) } defineReplace(qtVariablesFromGCC) { ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) \ 2>$$QMAKE_SYSTEM_NULL_DEVICE", lines, ec) !equals(ec, 0): qtCompilerError($$1, $$ret) return($$ret) } isEmpty($${target_prefix}.COMPILER_MACROS) { msvc { clang_cl { # We need to obtain the cl.exe version first vars = $$qtVariablesFromMSVC(cl) for (v, vars) { isEmpty(v)|contains(v, $${LITERAL_HASH}.*): next() eval($$v) } isEmpty(QMAKE_MSC_FULL_VER): error("Could not determine the Visual Studio version") QMAKE_CFLAGS_MSVC_COMPAT = $$replace(QMAKE_MSC_FULL_VER, "(..)(..)(.*)", \ "-fms-compatibility-version=\\1.\\2.\\3") cache($${target_prefix}.QMAKE_CFLAGS_MSVC_COMPAT, set stash, QMAKE_CFLAGS_MSVC_COMPAT) $${target_prefix}.COMPILER_MACROS += QMAKE_CFLAGS_MSVC_COMPAT vars = $$qtVariablesFromMSVC($$QMAKE_CXX, $$QMAKE_CFLAGS_MSVC_COMPAT) } else { vars = $$qtVariablesFromMSVC($$QMAKE_CXX) } } else: gcc|ghs { vars = $$qtVariablesFromGCC($$QMAKE_CXX) } for (v, vars) { !contains(v, "[A-Z_]+ = .*"): next() # Set both for the outer scope ... eval($$v) v ~= s/ .*// isEmpty($$v): error("Compiler produced empty value for $${v}.") # ... and save QMAKE_(HOST_)?CXX. in the cache. cache($${target_prefix}.$$v, set stash, $$v) $${target_prefix}.COMPILER_MACROS += $$v } cache($${target_prefix}.COMPILER_MACROS, set stash) } else { # load from the cache for (i, $${target_prefix}.COMPILER_MACROS): \ $$i = $$eval($${target_prefix}.$$i) } # Populate QMAKE_COMPILER_DEFINES and some compatibility variables. # The $$format_number() calls strip leading zeros to avoid misinterpretation as octal. QMAKE_COMPILER_DEFINES += __cplusplus=$$QT_COMPILER_STDCXX !isEmpty(QMAKE_MSC_VER): \ QMAKE_COMPILER_DEFINES += _MSC_VER=$$QMAKE_MSC_VER _MSC_FULL_VER=$$QMAKE_MSC_FULL_VER !isEmpty(QMAKE_ICC_VER): \ QMAKE_COMPILER_DEFINES += __INTEL_COMPILER=$$QMAKE_ICC_VER __INTEL_COMPILER_UPDATE=$$QMAKE_ICC_UPDATE_VER !isEmpty(QMAKE_APPLE_CC): \ QMAKE_COMPILER_DEFINES += __APPLE_CC__=$$QMAKE_APPLE_CC !isEmpty(QMAKE_APPLE_CLANG_MAJOR_VERSION): \ QMAKE_COMPILER_DEFINES += __clang__ \ __clang_major__=$$QMAKE_APPLE_CLANG_MAJOR_VERSION \ __clang_minor__=$$QMAKE_APPLE_CLANG_MINOR_VERSION \ __clang_patchlevel__=$$QMAKE_APPLE_CLANG_PATCH_VERSION !isEmpty(QMAKE_CLANG_MAJOR_VERSION): \ QMAKE_COMPILER_DEFINES += __clang__ \ __clang_major__=$$QMAKE_CLANG_MAJOR_VERSION \ __clang_minor__=$$QMAKE_CLANG_MINOR_VERSION \ __clang_patchlevel__=$$QMAKE_CLANG_PATCH_VERSION !isEmpty(QMAKE_GCC_MAJOR_VERSION): \ QMAKE_COMPILER_DEFINES += \ __GNUC__=$$QMAKE_GCC_MAJOR_VERSION \ __GNUC_MINOR__=$$QMAKE_GCC_MINOR_VERSION \ __GNUC_PATCHLEVEL__=$$QMAKE_GCC_PATCH_VERSION !isEmpty(QMAKE_GHS_VERSION): \ QMAKE_COMPILER_DEFINES += __ghs__ __GHS_VERSION_NUMBER=$$QMAKE_GHS_VERSION QMAKE_CFLAGS += $$QMAKE_CFLAGS_MSVC_COMPAT QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_MSVC_COMPAT clang_cl|intel_icl { include(../common/msvc-based-version.conf) } else: msvc { include(../common/msvc-version.conf) } # # Determine and cache the default search paths # defineReplace(qtMakeExpand) { out = "$$1" for(ever) { m = $$replace(out, ".*\\$\\(EXPORT_([^)]+)\\).*", \\1) equals(m, $$out): \ return($$out) out = $$replace(out, "\\$\\(EXPORT_$$m\\)", $$eval($$m)) } } defineReplace(qtSplitPathList) { paths = $$split(1, $$QMAKE_DIRLIST_SEP) ret = for (p, paths): \ ret += $$clean_path($$p) return($$ret) } defineReplace(qtNmakePathList) { paths = for (p, 1): \ paths += $$shell_path($$p) paths ~= s,$${LITERAL_HASH},^$${LITERAL_HASH},g paths ~= s,\\$,\$\$,g return($$join(paths, $$QMAKE_DIRLIST_SEP)) } msvc { arch = $$lower($$VCPROJ_ARCH) equals(arch, x64): \ # may be "win32" or undefined arch = amd64 else: !equals(arch, arm):!equals(arch, arm64): \ # may be "win32" or undefined arch = x86 # Consider only ARM64 desktop builds to be cross-builds - # the host is assumed to be Intel and capable of running the target # executables (so building for x64 on x86 will break). equals(arch, arm64): \ CONFIG += msvc_cross } isEmpty($${target_prefix}.INCDIRS) { # # Get default include and library paths from compiler # wasm { # wasm compiler does not work here, just use defaults } else: gcc { cmd_suffix = "<$$QMAKE_SYSTEM_NULL_DEVICE >$$QMAKE_SYSTEM_NULL_DEVICE" equals(QMAKE_HOST.os, Windows): \ cmd_prefix = "set LC_ALL=C&" else: \ cmd_prefix = "LC_ALL=C" cxx_flags = $$QMAKE_CXXFLAGS # Manually inject the sysroot for Apple Platforms because its resolution # normally does not happen until default_post.prf. This is especially # important for moc to gain the correct default include directory list. # While technically incorrect but without any likely practical effect, # UIKit simulator platforms will see the device SDK's sysroot in # QMAKE_DEFAULT_*DIRS, because they're handled in a single build pass. darwin { uikit { # Clang doesn't automatically pick up the architecture, just because # we're passing the iOS sysroot below, and we will end up building the # test for the host architecture, resulting in linker errors when # linking against the iOS libraries. We work around this by passing # the architecture explicitly. cxx_flags += -arch $$first(QMAKE_APPLE_DEVICE_ARCHS) } uikit:macx-xcode: \ cxx_flags += -isysroot $$sdk_path_device.value else: \ cxx_flags += -isysroot $$QMAKE_MAC_SDK_PATH } rim_qcc: \ # Need the cc1plus and ld command lines to pick up the paths cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$QMAKE_SYSTEM_NULL_DEVICE -v else: darwin:clang: \ # Need to link to pick up library paths cxx_flags += -g0 $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v else: \ # Just preprocess, might not pick up library paths cxx_flags += -E -v output = $$system("$$cmd_prefix $$QMAKE_CXX $$qtMakeExpand($$cxx_flags) -xc++ - 2>&1 $$cmd_suffix", lines, ec) !equals(ec, 0): qtCompilerError($$QMAKE_CXX, $$output) rim_qcc { for (line, output) { contains(line, "^[^ ]*cc1plus .*") { take_next = false for (parameter, $$list($$line)) { $$take_next { QMAKE_DEFAULT_INCDIRS += $$clean_path($$parameter) take_next = false } else: equals(parameter, "-isystem") { take_next = true } } } else: contains(line, "^[^ ]*-ld .*") { for (parameter, $$list($$line)) { contains(parameter, "^-L.*") { parameter ~= s/^-L// QMAKE_DEFAULT_LIBDIRS += $$clean_path($$parameter) } } } } } else { add_includes = false add_libraries = false for (line, output) { line ~= s/^[ \\t]*// # remove leading spaces contains(line, "LIBRARY_PATH=.*") { line ~= s/^LIBRARY_PATH=// # remove leading LIBRARY_PATH= equals(QMAKE_HOST.os, Windows): \ paths = $$split(line, ;) else: \ paths = $$split(line, $$QMAKE_DIRLIST_SEP) for (path, paths): \ QMAKE_DEFAULT_LIBDIRS += $$clean_path($$path) } else: contains(line, "Library search paths:") { add_libraries = true } else: contains(line, "$${LITERAL_HASH}include <.*") { # #include <...> search starts here: add_includes = true } else: contains(line, "End of search.*") { add_includes = false } else: $$add_libraries { # We assume all library search paths are absolute !contains(line, "^/.*") { add_libraries = false next() } QMAKE_DEFAULT_LIBDIRS += $$clean_path($$line) } else: $$add_includes { !contains(line, ".* \\(framework directory\\)"): \ QMAKE_DEFAULT_INCDIRS += $$clean_path($$line) } } } if(!darwin:clang)|intel_icc { # Clang on a non-Apple system (that is, a system without ld64 -- say, with GNU ld # or gold under Linux) will not print any library search path. Need to use another # invocation with different options (which in turn doesn't print include search # paths, so it can't just be used in place of the above code). # What's more, -print-search-dirs can't be used on clang on Apple because it # won't print all the library paths (only the clang-internal ones). output = $$system("$$cmd_prefix $$QMAKE_LINK $$QMAKE_LFLAGS -print-search-dirs", lines, ec) !equals(ec, 0): qtCompilerError($$QMAKE_LINK, $$output) for (line, output) { contains(line, "^libraries: .*") { line ~= s,^libraries: ,, equals(QMAKE_HOST.os, Windows) { # clang (7.x) on Windows uses the wrong path list separator ... line ~= s,:(?![/\\\\]),;, paths = $$split(line, ;) } else { paths = $$split(line, $$QMAKE_DIRLIST_SEP) } for (path, paths): \ QMAKE_DEFAULT_LIBDIRS += $$clean_path($$replace(path, ^=, $$[SYSROOT])) } } } isEmpty(QMAKE_DEFAULT_INCDIRS): \ !integrity: \ error("failed to parse default include paths from compiler output") isEmpty(QMAKE_DEFAULT_LIBDIRS): \ !integrity:!darwin: \ error("failed to parse default library paths from compiler output") QMAKE_DEFAULT_LIBDIRS = $$unique(QMAKE_DEFAULT_LIBDIRS) } else: ghs { cmd = $$QMAKE_CXX $$QMAKE_CXXFLAGS -$${LITERAL_HASH} -o /tmp/fake_output /tmp/fake_input.cpp output = $$system("$$cmd", blob, ec) !equals(ec, 0): qtCompilerError($$QMAKE_CXX, $$output) output ~= s/\\\\\\n {8}//g output = $$split(output, $$escape_expand(\\n)) for (line, output) { contains(line, "^[^ ]+/ecom[^ ]+ .* /tmp/fake_input\\.cpp") { for (parameter, $$list($$line)) { contains(parameter, "^(-I|--include_no_mmd=|--sys_include=).*") { parameter ~= s/^(-I|--include_no_mmd=|--sys_include=)// QMAKE_DEFAULT_INCDIRS += $$clean_path($$parameter) } } } else: contains(line, "^[^ ]+/elxr .*") { for (parameter, $$list($$line)) { contains(parameter, "^-L.*") { parameter ~= s/^-L// QMAKE_DEFAULT_LIBDIRS += $$clean_path($$parameter) } } } } } else: msvc_cross { # Use a batch file, because %VAR% in the system() call expands to # the pre-script-call value, and !VAR! cannot be enabled outside # a batch file without invoking another shell instance. cmd = $$system_quote($$system_path($$PWD/data/dumpvcvars.bat)) hostArch = $$QMAKE_HOST.arch equals(hostArch, x86_64): \ hostArch = amd64 !equals(arch, $$hostArch): \ arch = $${hostArch}_$$arch isEmpty(MSVC_VER): \ error("Mkspec does not specify MSVC_VER. Cannot continue.") versionAtLeast(MSVC_VER, 15.0) { dir = $$(VSINSTALLDIR) isEmpty(dir) { version_parts = $$split(MSVC_VER, .) MSVC_NEXT_MAJOR = $$num_add($$first(version_parts), 1) vswhere = "$$getenv(ProgramFiles\(x86\))/Microsoft Visual Studio/Installer/vswhere.exe" !exists($$vswhere): \ error("Could not find $$vswhere") vswhere = $$system_quote($$system_path($$vswhere)) # -version parameter: A version range for instances to find. 15.0 will get all versions >= 15.0 # Example: [15.0,16.0) will find versions 15.*. dir = $$system("$$vswhere -latest -version [$$MSVC_VER,$${MSVC_NEXT_MAJOR}.0] -property installationPath") } isEmpty(dir): \ error("Failed to find the Visual Studio installation directory.") cmd += $$system_quote($$dir\\VC\\Auxiliary\\Build\\vcvarsall.bat) $$arch } else { dir = $$(VCINSTALLDIR) isEmpty(dir): \ dir = $$read_registry(HKLM, \ "Software\\Microsoft\\VisualStudio\\$$MSVC_VER\\Setup\\VC\\ProductDir", 32) isEmpty(dir): \ error("Failed to find the Visual C installation directory.") cmd += $$system_quote($$dir\\vcvarsall.bat) $$arch } isEmpty(WINSDK_VER): \ error("Mkspec does not specify WINSDK_VER. Cannot continue.") # We prefer the environment variable, because that may work around # a broken registry entry after uninstalling a newer SDK. # However, we do that only if the major+minor SDK version matches # the one requested by the mkspec, as we might be building for a # newer target than the host. winsdk_ver = $$(WindowsSDKVersion) !isEmpty(winsdk_ver) { winsdk_ver ~= s,\\\\$,, # Work around SDK breakage. !equals(WINSDK_VER, $$replace(winsdk_ver, ^(\\d+\\.\\d+).*$, \\1)): \ winsdk_ver = } !isEmpty(winsdk_ver) { cmd += $$winsdk_ver } else { winsdk_ver = $$read_registry(HKLM, \ "Software\\Microsoft\\Microsoft SDKs\\Windows\\v$$WINSDK_VER\\ProductVersion", 32) isEmpty(winsdk_ver): \ error("Windows SDK $$WINSDK_VER requested by mkspec is not installed. Cannot continue.") cmd += $${winsdk_ver}.0 } output = $$system("$$cmd 2>&1", lines, ec) !equals(ec, 0): \ qtToolchainError("SDK setup script failed. Output:", $$output, \ "Command was: $$cmd") lines = $$output for(ever) { isEmpty(lines): \ break() line = $$take_first(lines) equals(line, "=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+="): \ break() } !count(lines, 3): \ qtToolchainError("SDK setup script returned unexpected output:", $$output, \ "Command was: $$cmd") # These contain only paths for the target. QMAKE_DEFAULT_INCDIRS = $$qtSplitPathList($$member(lines, 0)) QMAKE_DEFAULT_LIBDIRS = $$qtSplitPathList($$member(lines, 1)) # PATH is inherently for the host, and paths that are not shadowed # by vcvarsall.bat are assumed to contain only tools that work for # both host and target builds. QMAKE_DEFAULT_PATH = $$qtSplitPathList($$member(lines, 2)) # We de-duplicate, because the script just prepends to the paths for # the host, some of which are identical to the ones for the target. QMAKE_DEFAULT_PATH = $$unique(QMAKE_DEFAULT_PATH) } else: msvc { LIB = $$getenv("LIB") QMAKE_DEFAULT_LIBDIRS = $$split(LIB, $$QMAKE_DIRLIST_SEP) INCLUDE = $$getenv("INCLUDE") QMAKE_DEFAULT_INCDIRS = $$split(INCLUDE, $$QMAKE_DIRLIST_SEP) } unix:!darwin:if(!cross_compile|host_build) { isEmpty(QMAKE_DEFAULT_INCDIRS): QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include isEmpty(QMAKE_DEFAULT_LIBDIRS): QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib } # cache() complains about undefined variables and doesn't persist empty ones. !isEmpty(QMAKE_DEFAULT_INCDIRS): \ cache($${target_prefix}.INCDIRS, set stash, QMAKE_DEFAULT_INCDIRS) !isEmpty(QMAKE_DEFAULT_LIBDIRS): \ cache($${target_prefix}.LIBDIRS, set stash, QMAKE_DEFAULT_LIBDIRS) !isEmpty(QMAKE_DEFAULT_PATH): \ cache($${target_prefix}.PATH, set stash, QMAKE_DEFAULT_PATH) } else { QMAKE_DEFAULT_INCDIRS = $$eval($${target_prefix}.INCDIRS) QMAKE_DEFAULT_LIBDIRS = $$eval($${target_prefix}.LIBDIRS) QMAKE_DEFAULT_PATH = $$eval($${target_prefix}.PATH) } msvc_cross { qmake_inc_exp.name = INCLUDE qmake_inc_exp.value = $$qtNmakePathList($$QMAKE_DEFAULT_INCDIRS) qmake_lib_exp.name = LIB qmake_lib_exp.value = $$qtNmakePathList($$QMAKE_DEFAULT_LIBDIRS) qmake_path_exp.name = PATH qmake_path_exp.value = $$qtNmakePathList($$QMAKE_DEFAULT_PATH) QMAKE_EXPORTED_VARIABLES += qmake_inc_exp qmake_lib_exp qmake_path_exp } unset(target_prefix)