From 66cd31938c4dc97a32a094d3906c21ecdd034f95 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte <jocelyn.turcotte@digia.com> Date: Thu, 6 Nov 2014 11:33:53 +0100 Subject: [PATCH] Deploy external data in QtWebEngineCore.framework for framework builds There is currently no convenient way to deploy QtWebEngine into an application bundle on OSX. macdeployqt copies frameworks into a .app bundle's Frameworks directory but this makes no sense unless all the needed files are also distributed with the bundle. This patch moves: - The ffmpegsumo.so library into Libraries/ - Locale .pak files, qtwebengine_resources.pak and icudtl.dat into Resources/ - QtWebEngineProcess into its own .app bundle, itself into Helpers/ QMAKE_BUNDLE_DATA is used to copy files into the bundle while INSTALLS is used when installing normally. A LOCALE_LIST is explicitly listed since QMAKE_BUNDLE_DATA can't handle the * glob to match all source files. Change-Id: I5c0df57b4b9e93f9cce34a74a6e024bf90d37b5c Task-number: QTBUG-41611 Reviewed-by: Zeno Albisser <zeno.albisser@digia.com> Reviewed-by: Andras Becsi <andras.becsi@digia.com> --- src/core/Info_mac.plist | 20 ++++++++++ src/core/core_module.pro | 43 +++++++++++++++------ src/core/web_engine_library_info.cpp | 56 +++++++++++++++++++++++++++- src/process/process.pro | 16 ++++++-- 4 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 src/core/Info_mac.plist diff --git a/src/core/Info_mac.plist b/src/core/Info_mac.plist new file mode 100644 index 000000000..58362c810 --- /dev/null +++ b/src/core/Info_mac.plist @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleShortVersionString</key> + <string>@SHORT_VERSION@</string> + <key>CFBundleVersion</key> + <string>@FULL_VERSION@</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleSignature</key> + <string>@TYPEINFO@</string> + <key>CFBundleExecutable</key> + <string>@LIBRARY@</string> + <key>CFBundleIdentifier</key> + <string>org.qt-project.Qt.QtWebEngineCore</string> +</dict> +</plist> diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 3ba65e301..66ab3ee4d 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -6,18 +6,21 @@ CMAKE_MODULE_TESTS = "-" QT += qml quick QT_PRIVATE += gui-private +# Needed to set a CFBundleIdentifier +QMAKE_INFO_PLIST = Info_mac.plist + # Look for linking information produced by gyp for our target according to core_generated.gyp !include($$OUT_PWD/$$getConfigDir()/$${TARGET}_linking.pri) { error("Could not find the linking information that gyp should have generated.") } REPACK_DIR = $$OUT_PWD/$$getConfigDir()/gen/repack -locales.files = "$$REPACK_DIR/qtwebengine_locales/*" -locales.CONFIG += no_check_exist -locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales +# Duplicated from resources/resources.gyp +LOCALE_LIST = am ar bg bn ca cs da de el en-GB en-US es-419 es et fa fi fil fr gu he hi hr hu id it ja kn ko lt lv ml mr ms nb nl pl pt-BR pt-PT ro ru sk sl sr sv sw ta te th tr uk vi zh-CN zh-TW +for(LOC, LOCALE_LIST) { + locales.files += $$REPACK_DIR/qtwebengine_locales/$${LOC}.pak +} resources.files = $$REPACK_DIR/qtwebengine_resources.pak -resources.CONFIG += no_check_exist -resources.path = $$[QT_INSTALL_DATA] PLUGIN_EXTENSION = .so PLUGIN_PREFIX = lib @@ -26,16 +29,34 @@ win32 { PLUGIN_EXTENSION = .dll PLUGIN_PREFIX = } - icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat -icu.CONFIG += no_check_exist -icu.path = $$[QT_INSTALL_DATA] plugins.files = $$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_EXTENSION} -plugins.CONFIG += no_check_exist -plugins.path = $$[QT_INSTALL_PLUGINS]/qtwebengine -INSTALLS += icu locales resources plugins +!debug_and_release|!build_all|CONFIG(release, debug|release):contains(QT_CONFIG, qt_framework) { + locales.version = Versions + locales.path = Resources/qtwebengine_locales + resources.version = Versions + resources.path = Resources + icu.version = Versions + icu.path = Resources + plugins.version = Versions + plugins.path = Libraries + # No files, this prepares the bundle Helpers symlink, process.pro will create the directories + qtwebengineprocessplaceholder.version = Versions + qtwebengineprocessplaceholder.path = Helpers + QMAKE_BUNDLE_DATA += icu locales resources plugins qtwebengineprocessplaceholder +} else { + locales.CONFIG += no_check_exist + locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales + resources.CONFIG += no_check_exist + resources.path = $$[QT_INSTALL_DATA] + icu.CONFIG += no_check_exist + icu.path = $$[QT_INSTALL_DATA] + plugins.CONFIG += no_check_exist + plugins.path = $$[QT_INSTALL_PLUGINS]/qtwebengine + INSTALLS += icu locales resources plugins +} # We distribute the module binary but headers are only available in-tree. CONFIG += no_module_headers diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 4cdf3813e..026f4db83 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -92,6 +92,39 @@ QString location(QLibraryInfo::LibraryLocation path) return QLibraryInfo::location(path); } +#if defined(OS_MACOSX) +static inline CFBundleRef frameworkBundle() +{ + return CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.Qt.QtWebEngineCore")); +} + +static QString getPath(CFBundleRef frameworkBundle) +{ + QString path; + if (frameworkBundle) { + CFURLRef bundleUrl = CFBundleCopyBundleURL(frameworkBundle); + CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle); + path = QString::fromCFString(bundlePath); + CFRelease(bundlePath); + CFRelease(bundleUrl); + } + return path; +} + +static QString getResourcesPath(CFBundleRef frameworkBundle) +{ + QString path; + if (frameworkBundle) { + CFURLRef resourcesRelativeUrl = CFBundleCopyResourcesDirectoryURL(frameworkBundle); + CFStringRef resourcesRelativePath = CFURLCopyFileSystemPath(resourcesRelativeUrl, kCFURLPOSIXPathStyle); + path = getPath(frameworkBundle) % QLatin1Char('/') % QString::fromCFString(resourcesRelativePath); + CFRelease(resourcesRelativePath); + CFRelease(resourcesRelativeUrl); + } + return path; +} +#endif + QString subProcessPath() { static bool initialized = false; @@ -100,14 +133,19 @@ QString subProcessPath() #else static QString processBinary (QLatin1String(QTWEBENGINEPROCESS_NAME)); #endif +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + static QString processPath (getPath(frameworkBundle()) + % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME)); +#else static QString processPath (location(QLibraryInfo::LibraryExecutablesPath) % QDir::separator() % processBinary); +#endif if (!initialized) { // Allow overriding at runtime for the time being. const QByteArray fromEnv = qgetenv("QTWEBENGINEPROCESS_PATH"); if (!fromEnv.isEmpty()) processPath = QString::fromLatin1(fromEnv); - if (processPath.isEmpty() || !QFileInfo(processPath).exists()) { + if (!QFileInfo(processPath).exists()) { qWarning("QtWebEngineProcess not found at location %s. Trying fallback path...", qPrintable(processPath)); processPath = QCoreApplication::applicationDirPath() % QDir::separator() % processBinary; } @@ -121,12 +159,20 @@ QString subProcessPath() QString pluginsPath() { +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + return getPath(frameworkBundle()) % QLatin1String("/Libraries"); +#else return location(QLibraryInfo::PluginsPath) % QDir::separator() % QLatin1String("qtwebengine"); +#endif } QString localesPath() { +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + return getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_locales"); +#else return location(QLibraryInfo::TranslationsPath) % QLatin1String("/qtwebengine_locales"); +#endif } QString fallbackDir() { @@ -155,7 +201,11 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) QString directory; switch (key) { case QT_RESOURCES_PAK: +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + return toFilePath(getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_resources.pak")); +#else return toFilePath(location(QLibraryInfo::DataPath) % QLatin1String("/qtwebengine_resources.pak")); +#endif case base::FILE_EXE: case content::CHILD_PROCESS_EXE: return toFilePath(subProcessPath()); @@ -171,7 +221,11 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) directory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); break; case base::DIR_QT_LIBRARY_DATA: +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + return toFilePath(getResourcesPath(frameworkBundle())); +#else return toFilePath(location(QLibraryInfo::DataPath)); +#endif #if defined(OS_ANDROID) case base::DIR_SOURCE_ROOT: case base::DIR_ANDROID_EXTERNAL_STORAGE: diff --git a/src/process/process.pro b/src/process/process.pro index a9f5d183f..8ed09612a 100644 --- a/src/process/process.pro +++ b/src/process/process.pro @@ -3,14 +3,22 @@ TEMPLATE = app QT_PRIVATE += webenginecore -CONFIG -= app_bundle - load(qt_build_paths) -DESTDIR = $$MODULE_BASE_OUTDIR/libexec +contains(QT_CONFIG, qt_framework) { + # Deploy the QtWebEngineProcess app bundle into the QtWebEngineCore framework. + DESTDIR = $$MODULE_BASE_OUTDIR/lib/QtWebEngineCore.framework/Versions/5/Helpers +} else { + CONFIG -= app_bundle + DESTDIR = $$MODULE_BASE_OUTDIR/libexec +} INCLUDEPATH += ../core SOURCES = main.cpp -target.path = $$[QT_INSTALL_LIBEXECS] +contains(QT_CONFIG, qt_framework) { + target.path = $$[QT_INSTALL_LIBS]/QtWebEngineCore.framework/Versions/5/Helpers +} else { + target.path = $$[QT_INSTALL_LIBEXECS] +} INSTALLS += target -- GitLab