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": {
|
"precompile_header": {
|
||||||
"description": "Using precompiled headers",
|
"description": "Using precompiled headers",
|
||||||
"condition": "config.msvc || (!config.uikit && tests.precompile_header)",
|
"condition": "config.msvc || tests.precompile_header",
|
||||||
"output": [
|
"output": [
|
||||||
"privateConfig",
|
"privateConfig",
|
||||||
{ "type": "varRemove", "negative": true, "name": "CONFIG", "value": "'precompile_header'" }
|
{ "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) {
|
!equals(MAKEFILE_GENERATOR, XCODE) {
|
||||||
uikit:!host_build {
|
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
|
version_identifier = $$simulator.deployment_identifier
|
||||||
else: \
|
} else {
|
||||||
|
archs = $$eval(QMAKE_$${os_var}_DEVICE_ARCHS)
|
||||||
version_identifier = $$device.deployment_identifier
|
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 {
|
} else: osx {
|
||||||
version_identifier = macosx
|
version_identifier = macosx
|
||||||
deployment_target = $$QMAKE_MACOSX_DEPLOYMENT_TARGET
|
deployment_target = $$QMAKE_MACOSX_DEPLOYMENT_TARGET
|
||||||
|
@ -114,4 +114,6 @@ macx-xcode {
|
|||||||
QMAKE_CFLAGS += $$arch_flags
|
QMAKE_CFLAGS += $$arch_flags
|
||||||
QMAKE_CXXFLAGS += $$arch_flags
|
QMAKE_CXXFLAGS += $$arch_flags
|
||||||
QMAKE_LFLAGS += $$arch_flags
|
QMAKE_LFLAGS += $$arch_flags
|
||||||
|
|
||||||
|
QMAKE_PCH_ARCHS = $$VALID_ARCHS
|
||||||
}
|
}
|
||||||
|
@ -194,6 +194,18 @@ UnixMakefileGenerator::init()
|
|||||||
if (!language.isEmpty()) {
|
if (!language.isEmpty()) {
|
||||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"),
|
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"),
|
||||||
escapeFilePath(pchBaseName + language + headerSuffix));
|
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()))
|
if (!file.endsWith(extension.toQString()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QString precompiledHeader = header_prefix + language + header_suffix;
|
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||||
if (!ret.contains(precompiledHeader))
|
if (pchArchs.isEmpty())
|
||||||
ret += precompiledHeader;
|
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;
|
goto foundPrecompiledDependency;
|
||||||
}
|
}
|
||||||
|
@ -996,7 +996,15 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
|||||||
if (language.isEmpty())
|
if (language.isEmpty())
|
||||||
continue;
|
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";
|
t << "-$(DEL_FILE) " << escapeFilePaths(precomp_files).join(' ') << "\n\t";
|
||||||
@ -1052,6 +1060,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
|||||||
QString pchInput = project->first("PRECOMPILED_HEADER").toQString();
|
QString pchInput = project->first("PRECOMPILED_HEADER").toQString();
|
||||||
t << "###### Precompiled headers\n";
|
t << "###### Precompiled headers\n";
|
||||||
for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) {
|
for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) {
|
||||||
|
QString pchOutputDir;
|
||||||
QString pchFlags = var(ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE"));
|
QString pchFlags = var(ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE"));
|
||||||
if(pchFlags.isEmpty())
|
if(pchFlags.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
@ -1062,6 +1071,9 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
|||||||
else
|
else
|
||||||
cflags += " $(CXXFLAGS)";
|
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 pchBaseName = project->first("QMAKE_ORIG_TARGET");
|
||||||
ProString pchOutput;
|
ProString pchOutput;
|
||||||
if(!project->isEmpty("PRECOMPILED_DIR"))
|
if(!project->isEmpty("PRECOMPILED_DIR"))
|
||||||
@ -1088,30 +1100,47 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
|
|||||||
ProString header_suffix = project->isActiveConfig("clang_pch_style")
|
ProString header_suffix = project->isActiveConfig("clang_pch_style")
|
||||||
? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
|
? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
|
||||||
pchOutput += Option::dir_sep;
|
pchOutput += Option::dir_sep;
|
||||||
QString pchOutputDir = pchOutput.toQString();
|
pchOutputDir = pchOutput.toQString();
|
||||||
|
|
||||||
QString language = project->first(ProKey("QMAKE_LANGUAGE_" + compiler)).toQString();
|
QString language = project->first(ProKey("QMAKE_LANGUAGE_" + compiler)).toQString();
|
||||||
if (language.isEmpty())
|
if (language.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pchOutput += header_prefix + language + header_suffix;
|
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))
|
pchFlags.replace(QLatin1String("${QMAKE_PCH_INPUT}"), escapeFilePath(pchInput))
|
||||||
.replace(QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), escapeFilePath(pchBaseName.toQString()))
|
.replace(QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), escapeFilePath(pchBaseName.toQString()));
|
||||||
.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"), escapeFilePath(pchOutput.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 (!project->isActiveConfig("icc_pch_style")) {
|
||||||
if (compiler == "C" || compiler == "OBJC")
|
const auto pchFilePath_d = escapeDependencyPath(pchArchOutput);
|
||||||
compilerExecutable = "$(CC)";
|
if (!arch.isEmpty()) {
|
||||||
else
|
t << pchFilePath_d << ": " << "EXPORT_ARCH_ARGS = -arch " << arch << "\n\n";
|
||||||
compilerExecutable = "$(CXX)";
|
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
|
auto pchArchFlags = pchFlags;
|
||||||
t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchFlags << endl << endl;
|
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