From 73331eebf885ba8918447d26ba37bef2208bdb5e Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Tue, 23 Aug 2016 15:16:42 -0700 Subject: 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 --- qmake/generators/unix/unixmake.cpp | 26 ++++++++++++++-- qmake/generators/unix/unixmake2.cpp | 59 +++++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 18 deletions(-) (limited to 'qmake') diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index b0f7593fbe..349dcd2f40 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -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; } diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index d437a0782b..6fa355390f 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -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()); + + 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); + } - QString compilerExecutable; - if (compiler == "C" || compiler == "OBJC") - compilerExecutable = "$(CC)"; - else - compilerExecutable = "$(CXX)"; + auto pchArchFlags = pchFlags; + pchArchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"), escapeFilePath(pchArchOutput)); - // compile command - t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchFlags << endl << endl; + QString compilerExecutable; + if (compiler == "C" || compiler == "OBJC") + compilerExecutable = "$(CC)"; + else + compilerExecutable = "$(CXX)"; + + // compile command + t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchArchFlags << endl << endl; + } } } -- cgit v1.2.3