Enable precompiled headers on iOS, tvOS, watchOS
The actual blocker for precompiled headers is not the iOS/tvOS/watchOS platforms, but the way qmake handled multiple-architecture builds on Apple platforms. This patch allows multi-arch builds to be performed while using precompiled headers. Since df91ef3d6c55692a0236f67b6c6b134a3bf84098 (April 2009), Clang has had support for PCH files in the driver, which allows to use the -include flag to automatically translate to -include-pch. We can then take advantage of the fact that the -include option is allowed to not be separate from its argument, which lets us take advantage of -Xarch to specify a per-architecture precompiled header file. This is done through some magic in the qmake Makefile generator which "multiplexes" the PCH creation rule across multiple architectures and replaces a series of tokens with the proper precompiled header paths and architecture flags at usage point. Change-Id: I76c8dc9cda7e218869c2919f023d9b04f311c6fd Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
parent
443240b512
commit
73331eebf8
@ -1484,7 +1484,7 @@
|
||||
},
|
||||
"precompile_header": {
|
||||
"description": "Using precompiled headers",
|
||||
"condition": "config.msvc || (!config.uikit && tests.precompile_header)",
|
||||
"condition": "config.msvc || tests.precompile_header",
|
||||
"output": [
|
||||
"privateConfig",
|
||||
{ "type": "varRemove", "negative": true, "name": "CONFIG", "value": "'precompile_header'" }
|
||||
|
@ -56,13 +56,32 @@ for(tool, $$list(QMAKE_CC QMAKE_CXX QMAKE_FIX_RPATH QMAKE_AR QMAKE_RANLIB QMAKE_
|
||||
|
||||
!equals(MAKEFILE_GENERATOR, XCODE) {
|
||||
uikit:!host_build {
|
||||
simulator: \
|
||||
ios: os_var = IOS
|
||||
tvos: os_var = TVOS
|
||||
watchos: os_var = WATCHOS
|
||||
|
||||
deployment_target = $$eval(QMAKE_$${os_var}_DEPLOYMENT_TARGET)
|
||||
simulator {
|
||||
archs = $$eval(QMAKE_$${os_var}_SIMULATOR_ARCHS)
|
||||
version_identifier = $$simulator.deployment_identifier
|
||||
else: \
|
||||
} else {
|
||||
archs = $$eval(QMAKE_$${os_var}_DEVICE_ARCHS)
|
||||
version_identifier = $$device.deployment_identifier
|
||||
ios: deployment_target = $$QMAKE_IOS_DEPLOYMENT_TARGET
|
||||
tvos: deployment_target = $$QMAKE_TVOS_DEPLOYMENT_TARGET
|
||||
watchos: deployment_target = $$QMAKE_WATCHOS_DEPLOYMENT_TARGET
|
||||
}
|
||||
|
||||
single_arch: archs = $$first(archs)
|
||||
|
||||
QMAKE_CFLAGS_USE_PRECOMPILE =
|
||||
for(arch, archs) {
|
||||
QMAKE_CFLAGS_USE_PRECOMPILE += \
|
||||
-Xarch_$${arch} \
|
||||
-include${QMAKE_PCH_OUTPUT_$${arch}}
|
||||
}
|
||||
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
|
||||
QMAKE_OBJCFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
|
||||
QMAKE_OBJCXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
|
||||
|
||||
QMAKE_PCH_OUTPUT_EXT = _${QMAKE_PCH_ARCH}$${QMAKE_PCH_OUTPUT_EXT}
|
||||
} else: osx {
|
||||
version_identifier = macosx
|
||||
deployment_target = $$QMAKE_MACOSX_DEPLOYMENT_TARGET
|
||||
|
@ -114,4 +114,6 @@ macx-xcode {
|
||||
QMAKE_CFLAGS += $$arch_flags
|
||||
QMAKE_CXXFLAGS += $$arch_flags
|
||||
QMAKE_LFLAGS += $$arch_flags
|
||||
|
||||
QMAKE_PCH_ARCHS = $$VALID_ARCHS
|
||||
}
|
||||
|
@ -194,6 +194,18 @@ UnixMakefileGenerator::init()
|
||||
if (!language.isEmpty()) {
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"),
|
||||
escapeFilePath(pchBaseName + language + headerSuffix));
|
||||
const ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
for (const ProString &arch : pchArchs) {
|
||||
QString suffix = headerSuffix;
|
||||
suffix.replace(QLatin1String("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
if (project->isActiveConfig("clang_pch_style")
|
||||
&& (suffix.endsWith(QLatin1String(".pch"))
|
||||
|| suffix.endsWith(QLatin1String(".gch")))) {
|
||||
suffix.chop(4); // must omit header suffix for -include to recognize the PCH
|
||||
}
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT_") + arch + QLatin1Char('}'),
|
||||
escapeFilePath(pchBaseName + language + suffix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,9 +363,17 @@ QStringList
|
||||
if (!file.endsWith(extension.toQString()))
|
||||
continue;
|
||||
|
||||
QString precompiledHeader = header_prefix + language + header_suffix;
|
||||
if (!ret.contains(precompiledHeader))
|
||||
ret += precompiledHeader;
|
||||
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
if (pchArchs.isEmpty())
|
||||
pchArchs << ProString(); // normal single-arch PCH
|
||||
for (const ProString &arch : qAsConst(pchArchs)) {
|
||||
QString suffix = header_suffix;
|
||||
if (!arch.isEmpty())
|
||||
suffix.replace(QLatin1String("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
QString precompiledHeader = header_prefix + language + suffix;
|
||||
if (!ret.contains(precompiledHeader))
|
||||
ret += precompiledHeader;
|
||||
}
|
||||
|
||||
goto foundPrecompiledDependency;
|
||||
}
|
||||
|
@ -996,7 +996,15 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
||||
if (language.isEmpty())
|
||||
continue;
|
||||
|
||||
precomp_files += precomph_out_dir + header_prefix + language + header_suffix;
|
||||
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
if (pchArchs.isEmpty())
|
||||
pchArchs << ProString(); // normal single-arch PCH
|
||||
for (const ProString &arch : qAsConst(pchArchs)) {
|
||||
auto suffix = header_suffix.toQString();
|
||||
if (!arch.isEmpty())
|
||||
suffix.replace(QStringLiteral("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
precomp_files += precomph_out_dir + header_prefix + language + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
t << "-$(DEL_FILE) " << escapeFilePaths(precomp_files).join(' ') << "\n\t";
|
||||
@ -1052,6 +1060,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
||||
QString pchInput = project->first("PRECOMPILED_HEADER").toQString();
|
||||
t << "###### Precompiled headers\n";
|
||||
for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) {
|
||||
QString pchOutputDir;
|
||||
QString pchFlags = var(ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE"));
|
||||
if(pchFlags.isEmpty())
|
||||
continue;
|
||||
@ -1062,6 +1071,9 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
||||
else
|
||||
cflags += " $(CXXFLAGS)";
|
||||
|
||||
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
if (pchArchs.isEmpty())
|
||||
pchArchs << ProString(); // normal single-arch PCH
|
||||
ProString pchBaseName = project->first("QMAKE_ORIG_TARGET");
|
||||
ProString pchOutput;
|
||||
if(!project->isEmpty("PRECOMPILED_DIR"))
|
||||
@ -1088,30 +1100,47 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
||||
ProString header_suffix = project->isActiveConfig("clang_pch_style")
|
||||
? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
|
||||
pchOutput += Option::dir_sep;
|
||||
QString pchOutputDir = pchOutput.toQString();
|
||||
pchOutputDir = pchOutput.toQString();
|
||||
|
||||
QString language = project->first(ProKey("QMAKE_LANGUAGE_" + compiler)).toQString();
|
||||
if (language.isEmpty())
|
||||
continue;
|
||||
|
||||
pchOutput += header_prefix + language + header_suffix;
|
||||
|
||||
t << escapeDependencyPath(pchOutput) << ": " << escapeDependencyPath(pchInput) << ' '
|
||||
<< escapeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t")
|
||||
<< "\n\t" << mkdir_p_asstring(pchOutputDir);
|
||||
}
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_INPUT}"), escapeFilePath(pchInput))
|
||||
.replace(QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), escapeFilePath(pchBaseName.toQString()))
|
||||
.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"), escapeFilePath(pchOutput.toQString()));
|
||||
.replace(QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), escapeFilePath(pchBaseName.toQString()));
|
||||
for (const ProString &arch : qAsConst(pchArchs)) {
|
||||
auto pchArchOutput = pchOutput.toQString();
|
||||
if (!arch.isEmpty())
|
||||
pchArchOutput.replace(QStringLiteral("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
|
||||
QString compilerExecutable;
|
||||
if (compiler == "C" || compiler == "OBJC")
|
||||
compilerExecutable = "$(CC)";
|
||||
else
|
||||
compilerExecutable = "$(CXX)";
|
||||
if (!project->isActiveConfig("icc_pch_style")) {
|
||||
const auto pchFilePath_d = escapeDependencyPath(pchArchOutput);
|
||||
if (!arch.isEmpty()) {
|
||||
t << pchFilePath_d << ": " << "EXPORT_ARCH_ARGS = -arch " << arch << "\n\n";
|
||||
t << pchFilePath_d << ": "
|
||||
<< "EXPORT_QMAKE_XARCH_CFLAGS = $(EXPORT_QMAKE_XARCH_CFLAGS_" << arch << ")" << "\n\n";
|
||||
t << pchFilePath_d << ": "
|
||||
<< "EXPORT_QMAKE_XARCH_LFLAGS = $(EXPORT_QMAKE_XARCH_LFLAGS_" << arch << ")" << "\n\n";
|
||||
}
|
||||
t << pchFilePath_d << ": " << escapeDependencyPath(pchInput) << ' '
|
||||
<< escapeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t")
|
||||
<< "\n\t" << mkdir_p_asstring(pchOutputDir);
|
||||
}
|
||||
|
||||
// compile command
|
||||
t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchFlags << endl << endl;
|
||||
auto pchArchFlags = pchFlags;
|
||||
pchArchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"), escapeFilePath(pchArchOutput));
|
||||
|
||||
QString compilerExecutable;
|
||||
if (compiler == "C" || compiler == "OBJC")
|
||||
compilerExecutable = "$(CC)";
|
||||
else
|
||||
compilerExecutable = "$(CXX)";
|
||||
|
||||
// compile command
|
||||
t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchArchFlags << endl << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user