From aae7a5e09db3d98ce74a523c06b8971a3672b309 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Mon, 15 Feb 2016 22:29:01 -0800 Subject: [PATCH] qmake: Add shallow bundle support This is a prerequisite for properly constructed framework bundles. On certain Apple platforms (iOS, tvOS, watchOS), bundles are used in "shallow" format, meaning that the directory structures are flattened compared to the one used in macOS bundles. shallow_bundle allows the difference to be expressed independently of the platform. Note that the term "shallow bundle" is used by Apple in Xcode internals. Change-Id: I1189c52b0ea66843c313783176c11cc2af97ad25 Reviewed-by: Oswald Buddenhagen --- mkspecs/common/uikit.conf | 2 +- mkspecs/features/qt.prf | 4 +- mkspecs/features/qt_functions.prf | 6 +- qmake/generators/mac/pbuilder_pbx.cpp | 6 +- qmake/generators/unix/unixmake.cpp | 9 ++- qmake/generators/unix/unixmake2.cpp | 80 ++++++++++++++++----------- 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/mkspecs/common/uikit.conf b/mkspecs/common/uikit.conf index edc0eddf004..6ffbe51fcec 100644 --- a/mkspecs/common/uikit.conf +++ b/mkspecs/common/uikit.conf @@ -3,7 +3,7 @@ # QMAKE_PLATFORM += uikit -CONFIG += bitcode reduce_exports +CONFIG += bitcode reduce_exports shallow_bundle INCLUDEPATH += $$PWD/uikit DEFINES += DARWIN_NO_CARBON QT_NO_PRINTER QT_NO_PRINTDIALOG diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 0c5f080ec19..7b669b902f3 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -244,13 +244,13 @@ contains(qt_module_deps, qml): \ # copy qml files. this part is platform spesific. mac { - osx { + !shallow_bundle { # Note: user can override QMAKE_BUNDLE_QML from pro file to change target bundle path isEmpty(QMAKE_QML_BUNDLE_PATH):QMAKE_QML_BUNDLE_PATH = "Resources/qt_qml" qmlTargetPath = $$OUT_PWD/$${TARGET}.app/Contents/$$QMAKE_QML_BUNDLE_PATH qtconfTargetPath = $$OUT_PWD/$${TARGET}.app/Contents/Resources/qt.conf } else { - # iOS: flat bundle layout (no Contents/Resources) + # shallow bundle layout (no Contents/Resources) isEmpty(QMAKE_QML_BUNDLE_PATH):QMAKE_QML_BUNDLE_PATH = "qt_qml" qmlTargetPath = $CODESIGNING_FOLDER_PATH/$$QMAKE_QML_BUNDLE_PATH qtconfTargetPath = $CODESIGNING_FOLDER_PATH/qt.conf diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 08c7c9f8991..e7d73adefb6 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -37,11 +37,13 @@ defineReplace(qtRelativeRPathBase) { darwin { if(equals(TEMPLATE, app):app_bundle)|\ if(equals(TEMPLATE, lib):plugin:plugin_bundle) { - ios: return($$target.path/$${TARGET}.app) + shallow_bundle: return($$target.path/$${TARGET}.app) return($$target.path/$${TARGET}.app/Contents/MacOS) } - equals(TEMPLATE, lib):!plugin:lib_bundle: \ + equals(TEMPLATE, lib):!plugin:lib_bundle { + shallow_bundle: return($$target.path/$${TARGET}.framework) return($$target.path/$${TARGET}.framework/Versions/Current) + } } return($$target.path) } diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index bf2e7746786..b53b862b87d 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1123,9 +1123,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) bundle_resources_files << s; } else { QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]); - if (!project->isEmpty(ProKey(bundle_data[i] + ".version"))) { - //### - } + //if (!project->isActiveConfig("shallow_bundle") + // && !project->isEmpty(ProKey(bundle_data[i] + ".version"))) { + //} project->values("QMAKE_PBX_BUILDPHASES").append(phase_key); t << "\t\t" << phase_key << " = {\n" diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index b0f7593fbee..0e29f469ef0 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -579,10 +579,13 @@ UnixMakefileGenerator::defaultInstall(const QString &t) plain_targ = escapeFilePath(plain_targ); if (bundle != NoBundle) { QString suffix; - if (project->first("TEMPLATE") == "lib") - suffix = "/Versions/" + project->first("QMAKE_FRAMEWORK_VERSION") + "/$(TARGET)"; - else + if (project->first("TEMPLATE") == "lib") { + if (!project->isActiveConfig("shallow_bundle")) + suffix += "/Versions/" + project->first("QMAKE_FRAMEWORK_VERSION"); + suffix += "/$(TARGET)"; + } else { suffix = "/" + project->first("QMAKE_BUNDLE_LOCATION") + "/$(QMAKE_TARGET)"; + } dst_targ += suffix; if (bundle == SolidBundle) { if (!ret.isEmpty()) diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index c53393e2681..be476a78060 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -596,9 +596,10 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) << var("QMAKE_LINK_SHLIB_CMD") << "\n\t" << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGETD)`\"", false) << "\n\t" << "-$(MOVE) $(TARGET) $(DESTDIR)$(TARGETD)\n\t" - << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGET0)`\"", false) << "\n\t" - << varGlue("QMAKE_LN_SHLIB", "-", " ", - " Versions/Current/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t"; + << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGET0)`\"", false) << "\n\t"; + if (!project->isActiveConfig("shallow_bundle")) + t << varGlue("QMAKE_LN_SHLIB", "-", " ", + " Versions/Current/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t"; if(!project->isEmpty("QMAKE_POST_LINK")) t << "\n\t" << var("QMAKE_POST_LINK"); t << endl << endl; @@ -778,9 +779,14 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) info_plist = escapeFilePath(fileFixify(info_plist)); } bool isFramework = project->first("TEMPLATE") == "lib" && project->isActiveConfig("lib_bundle"); + bool isShallowBundle = project->isActiveConfig("shallow_bundle"); QString info_plist_out = bundle_dir + - (isFramework ? ("Versions/" + project->first("QMAKE_FRAMEWORK_VERSION") + "/Resources/Info.plist") - : "Contents/Info.plist"); + (!isShallowBundle + ? (isFramework + ? ("Versions/" + project->first("QMAKE_FRAMEWORK_VERSION") + "/Resources/") + : "Contents/") + : QString()) + + "Info.plist"; bundledFiles << info_plist_out; alldeps << info_plist_out; QString destdir = info_plist_out.section(Option::dir_sep, 0, -2); @@ -838,7 +844,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) << "@$(COPY_FILE) " << escapeFilePath(icon) << ' ' << icon_path_f << endl; } } else { - symlinks[bundle_dir + "Resources"] = "Versions/Current/Resources"; + if (!isShallowBundle) + symlinks[bundle_dir + "Resources"] = "Versions/Current/Resources"; t << "@$(DEL_FILE) " << info_plist_out << "\n\t" << "@sed "; for (const ProString &arg : qAsConst(commonSedArgs)) @@ -857,18 +864,20 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) for(int i = 0; i < bundle_data.count(); i++) { const ProStringList &files = project->values(ProKey(bundle_data[i] + ".files")); QString path = bundle_dir; - const ProKey vkey(bundle_data[i] + ".version"); const ProKey pkey(bundle_data[i] + ".path"); - if (!project->isEmpty(vkey)) { - QString version = project->first(vkey) + "/" + - project->first("QMAKE_FRAMEWORK_VERSION") + "/"; - ProString name = project->first(pkey); - int pos = name.indexOf('/'); - if (pos > 0) - name = name.mid(0, pos); - symlinks[Option::fixPathToTargetOS(path + name)] = - project->first(vkey) + "/Current/" + name; - path += version; + if (!project->isActiveConfig("shallow_bundle")) { + const ProKey vkey(bundle_data[i] + ".version"); + if (!project->isEmpty(vkey)) { + QString version = project->first(vkey) + "/" + + project->first("QMAKE_FRAMEWORK_VERSION") + "/"; + ProString name = project->first(pkey); + int pos = name.indexOf('/'); + if (pos > 0) + name = name.mid(0, pos); + symlinks[Option::fixPathToTargetOS(path + name)] = + project->first(vkey) + "/Current/" + name; + path += version; + } } path += project->first(pkey).toQString(); path = Option::fixPathToTargetOS(path); @@ -906,15 +915,17 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) << "@$(SYMLINK) " << escapeFilePath(symIt.value()) << ' ' << bundle_dir_f << endl; } - QString currentLink = bundle_dir + "Versions/Current"; - QString currentLink_f = escapeDependencyPath(currentLink); - bundledFiles << currentLink; - alldeps << currentLink; - t << currentLink_f << ": $(MAKEFILE)\n\t" - << mkdir_p_asstring(bundle_dir + "Versions") << "\n\t" - << "@-$(DEL_FILE) " << currentLink_f << "\n\t" - << "@$(SYMLINK) " << project->first("QMAKE_FRAMEWORK_VERSION") - << ' ' << currentLink_f << endl; + if (!project->isActiveConfig("shallow_bundle")) { + QString currentLink = bundle_dir + "Versions/Current"; + QString currentLink_f = escapeDependencyPath(currentLink); + bundledFiles << currentLink; + alldeps << currentLink; + t << currentLink_f << ": $(MAKEFILE)\n\t" + << mkdir_p_asstring(bundle_dir + "Versions") << "\n\t" + << "@-$(DEL_FILE) " << currentLink_f << "\n\t" + << "@$(SYMLINK) " << project->first("QMAKE_FRAMEWORK_VERSION") + << ' ' << currentLink_f << endl; + } } } @@ -1157,12 +1168,17 @@ void UnixMakefileGenerator::init2() bundle_loc.prepend("/"); if(!bundle_loc.endsWith("/")) bundle_loc += "/"; - project->values("TARGET_").append(project->first("QMAKE_BUNDLE") + - bundle_loc + project->first("TARGET")); - project->values("TARGET_x.y").append(project->first("QMAKE_BUNDLE") + - "/Versions/" + - project->first("QMAKE_FRAMEWORK_VERSION") + - bundle_loc + project->first("TARGET")); + const QString target = project->first("QMAKE_BUNDLE") + + bundle_loc + project->first("TARGET"); + project->values("TARGET_").append(target); + if (!project->isActiveConfig("shallow_bundle")) { + project->values("TARGET_x.y").append(project->first("QMAKE_BUNDLE") + + "/Versions/" + + project->first("QMAKE_FRAMEWORK_VERSION") + + bundle_loc + project->first("TARGET")); + } else { + project->values("TARGET_x.y").append(target); + } } else if(project->isActiveConfig("plugin")) { QString prefix; if(!project->isActiveConfig("no_plugin_name_prefix"))