diff --git a/src/assistant/help/qhelpcontentwidget.cpp b/src/assistant/help/qhelpcontentwidget.cpp
index aa06e29d84f4667d59b253430e652b6f85ee13a8..8f38bcfd3de322f82852543a2f3289056a459400 100644
--- a/src/assistant/help/qhelpcontentwidget.cpp
+++ b/src/assistant/help/qhelpcontentwidget.cpp
@@ -65,6 +65,7 @@ public:
 
 class QHelpContentProvider : public QThread
 {
+    Q_OBJECT
 public:
     QHelpContentProvider(QHelpEnginePrivate *helpEngine);
     ~QHelpContentProvider();
@@ -73,11 +74,13 @@ public:
     QHelpContentItem *rootItem();
     int nextChildCount() const;
 
+signals:
+    void finishedSuccessFully();
+
 private:
     void run();
 
     QHelpEnginePrivate *m_helpEngine;
-    QHelpContentItem *m_rootItem;
     QStringList m_filterAttributes;
     QQueue<QHelpContentItem*> m_rootItems;
     QMutex m_mutex;
@@ -188,7 +191,6 @@ QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine)
     : QThread(helpEngine)
 {
     m_helpEngine = helpEngine;
-    m_rootItem = 0;
     m_abort = false;
 }
 
@@ -212,22 +214,28 @@ void QHelpContentProvider::collectContents(const QString &customFilterName)
 
 void QHelpContentProvider::stopCollecting()
 {
-    if (!isRunning())
-        return;
-    m_mutex.lock();
-    m_abort = true;
-    m_mutex.unlock();
-    wait();
+    if (isRunning()) {
+        m_mutex.lock();
+        m_abort = true;
+        m_mutex.unlock();
+        wait();
+    }
+    qDeleteAll(m_rootItems);
+    m_rootItems.clear();
 }
 
 QHelpContentItem *QHelpContentProvider::rootItem()
 {
     QMutexLocker locker(&m_mutex);
+    if (m_rootItems.isEmpty())
+        return 0;
     return m_rootItems.dequeue();
 }
 
 int QHelpContentProvider::nextChildCount() const
 {
+    if (m_rootItems.isEmpty())
+        return 0;
     return m_rootItems.head()->childCount();
 }
 
@@ -239,8 +247,7 @@ void QHelpContentProvider::run()
     QHelpContentItem *item = 0;
 
     m_mutex.lock();
-    m_rootItem = new QHelpContentItem(QString(), QString(), 0);
-    m_rootItems.enqueue(m_rootItem);
+    QHelpContentItem * const rootItem = new QHelpContentItem(QString(), QString(), 0);
     QStringList atts = m_filterAttributes;
     const QStringList fileNames = m_helpEngine->orderedFileNameList;
     m_mutex.unlock();
@@ -248,9 +255,10 @@ void QHelpContentProvider::run()
     foreach (const QString &dbFileName, fileNames) {
         m_mutex.lock();
         if (m_abort) {
+            delete rootItem;
             m_abort = false;
             m_mutex.unlock();
-            break;
+            return;
         }
         m_mutex.unlock();
         QHelpDBReader reader(dbFileName,
@@ -278,8 +286,8 @@ CHECK_DEPTH:
                 if (depth == 0) {
                     m_mutex.lock();
                     item = new QHelpContentItem(title, link,
-                        m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem);
-                    m_rootItem->appendChild(item);
+                        m_helpEngine->fileNameReaderMap.value(dbFileName), rootItem);
+                    rootItem->appendChild(item);
                     m_mutex.unlock();
                     stack.push(item);
                     _depth = 1;
@@ -303,8 +311,10 @@ CHECK_DEPTH:
         }
     }
     m_mutex.lock();
+    m_rootItems.enqueue(rootItem);
     m_abort = false;
     m_mutex.unlock();
+    emit finishedSuccessFully();
 }
 
 
@@ -339,9 +349,9 @@ QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine)
     d->rootItem = 0;
     d->qhelpContentProvider = new QHelpContentProvider(helpEngine);
 
-    connect(d->qhelpContentProvider, SIGNAL(finished()),
+    connect(d->qhelpContentProvider, SIGNAL(finishedSuccessFully()),
         this, SLOT(insertContents()), Qt::QueuedConnection);
-    connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateContents()));
+    connect(helpEngine->q, SIGNAL(readersAboutToBeInvalidated()), this, SLOT(invalidateContents()));
 }
 
 /*!
@@ -381,6 +391,9 @@ void QHelpContentModel::createContents(const QString &customFilterName)
 
 void QHelpContentModel::insertContents()
 {
+    QHelpContentItem * const newRootItem = d->qhelpContentProvider->rootItem();
+    if (!newRootItem)
+        return;
     int count;
     if (d->rootItem) {
         count = d->rootItem->childCount() - 1;
@@ -392,7 +405,7 @@ void QHelpContentModel::insertContents()
 
     count = d->qhelpContentProvider->nextChildCount() - 1;
     beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0);
-    d->rootItem = d->qhelpContentProvider->rootItem();
+    d->rootItem = newRootItem;
     endInsertRows();
     emit contentsCreated();
 }
@@ -572,3 +585,5 @@ void QHelpContentWidget::showLink(const QModelIndex &index)
 }
 
 QT_END_NAMESPACE
+
+#include "qhelpcontentwidget.moc"
diff --git a/src/assistant/help/qhelpenginecore.cpp b/src/assistant/help/qhelpenginecore.cpp
index 00b55d078c7b4a3399854e8422b1268fa9132809..f502e1df458b630ca69c01e6d8caa872d993ec16 100644
--- a/src/assistant/help/qhelpenginecore.cpp
+++ b/src/assistant/help/qhelpenginecore.cpp
@@ -71,6 +71,7 @@ QHelpEngineCorePrivate::~QHelpEngineCorePrivate()
 
 void QHelpEngineCorePrivate::clearMaps()
 {
+    emit q->readersAboutToBeInvalidated();
     QMap<QString, QHelpDBReader*>::iterator it = readerMap.begin();
     while (it != readerMap.end()) {
         delete it.value();
diff --git a/src/assistant/help/qhelpenginecore.h b/src/assistant/help/qhelpenginecore.h
index bab84ee4ed0e73d437d63f1e469fef71f0c4c93f..8579165ff99fedb8804782e57a904f0ba8011424 100644
--- a/src/assistant/help/qhelpenginecore.h
+++ b/src/assistant/help/qhelpenginecore.h
@@ -108,6 +108,7 @@ Q_SIGNALS:
     void setupFinished();
     void currentFilterChanged(const QString &newFilter);
     void warning(const QString &msg);
+    void readersAboutToBeInvalidated();
 
 protected:
     QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate,
diff --git a/src/assistant/help/qhelpindexwidget.cpp b/src/assistant/help/qhelpindexwidget.cpp
index 7da09de53438d981961e32d1cecd416706a6caf5..33e83101770b22782c902043901cdfcad21d2035 100644
--- a/src/assistant/help/qhelpindexwidget.cpp
+++ b/src/assistant/help/qhelpindexwidget.cpp
@@ -224,7 +224,7 @@ QHelpIndexModel::QHelpIndexModel(QHelpEnginePrivate *helpEngine)
     d = new QHelpIndexModelPrivate(helpEngine);
 
     connect(d->indexProvider, SIGNAL(finished()), this, SLOT(insertIndices()));
-    connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateIndex()));
+    connect(helpEngine->q, SIGNAL(readersAboutToBeInvalidated()), this, SLOT(invalidateIndex()));
 }
 
 QHelpIndexModel::~QHelpIndexModel()
diff --git a/src/macdeployqt/macdeployqt/main.cpp b/src/macdeployqt/macdeployqt/main.cpp
index 865a22f03c238f54f634907330af9ee6c341f523..0f38cdfaf9579bc21c01396caaee84e17a8a56ba 100644
--- a/src/macdeployqt/macdeployqt/main.cpp
+++ b/src/macdeployqt/macdeployqt/main.cpp
@@ -51,6 +51,7 @@ int main(int argc, char **argv)
         qDebug() << "   -executable=<path> : Let the given executable use the deployed frameworks too";
         qDebug() << "   -qmldir=<path>     : Deploy imports used by .qml files in the given path";
         qDebug() << "   -always-overwrite  : Copy files enven if the target file exists";
+        qDebug() << "   -codesign=<ident>  : Run codesing with the given identity on all executables";
         qDebug() << "";
         qDebug() << "macdeployqt takes an application bundle as input and makes it";
         qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
@@ -81,6 +82,8 @@ int main(int argc, char **argv)
     extern bool alwaysOwerwriteEnabled;
     QStringList additionalExecutables;
     QStringList qmlDirs;
+    extern bool runCodesign;
+    extern QString codesignIdentiy;
 
     for (int i = 2; i < argc; ++i) {
         QByteArray argument = QByteArray(argv[i]);
@@ -123,6 +126,15 @@ int main(int argc, char **argv)
         } else if (argument == QByteArray("-always-overwrite")) {
             LogDebug() << "Argument found:" << argument;
             alwaysOwerwriteEnabled = true;
+        } else if (argument.startsWith(QByteArray("-codesign"))) {
+            LogDebug() << "Argument found:" << argument;
+            int index = argument.indexOf("=");
+            if (index < 0 || index >= argument.size()) {
+                LogError() << "Missing code signing identity";
+            } else {
+                runCodesign = true;
+                codesignIdentiy = argument.mid(index+1);
+            }
         } else if (argument.startsWith("-")) {
             LogError() << "Unknown argument" << argument << "\n";
             return 0;
@@ -149,6 +161,9 @@ int main(int argc, char **argv)
     if (!qmlDirs.isEmpty())
         deployQmlImports(appBundlePath, qmlDirs);
 
+    if (runCodesign)
+        codesign(codesignIdentiy, appBundlePath);
+
     if (dmg) {
         LogNormal();
         createDiskImage(appBundlePath);
diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp
index 314bc2cc5757751871ee45a70f747c34c888552f..a8716d753d6a36a7b92eee8430c7904fbd2e2ece 100644
--- a/src/macdeployqt/shared/shared.cpp
+++ b/src/macdeployqt/shared/shared.cpp
@@ -38,6 +38,7 @@
 #include <QDir>
 #include <QRegExp>
 #include <QSet>
+#include <QStack>
 #include <QDirIterator>
 #include <QLibraryInfo>
 #include <QJsonDocument>
@@ -48,6 +49,8 @@
 
 bool runStripEnabled = true;
 bool alwaysOwerwriteEnabled = false;
+bool runCodesign = false;
+QString codesignIdentiy;
 int logLevel = 1;
 
 using std::cout;
@@ -70,7 +73,8 @@ QDebug operator<<(QDebug debug, const FrameworkInfo &info)
     debug << "Install name" << info.installName << "\n";
     debug << "Deployed install name" << info.deployedInstallName << "\n";
     debug << "Source file Path" << info.sourceFilePath << "\n";
-    debug << "Destination Directory (relative to bundle)" << info.destinationDirectory << "\n";
+    debug << "Framework Destination Directory (relative to bundle)" << info.frameworkDestinationDirectory << "\n";
+    debug << "Binary Destination Directory (relative to bundle)" << info.binaryDestinationDirectory << "\n";
 
     return debug;
 }
@@ -123,6 +127,38 @@ bool copyFilePrintStatus(const QString &from, const QString &to)
     }
 }
 
+bool linkFilePrintStatus(const QString &file, const QString &link)
+{
+    if (QFile(link).exists()) {
+        if (QFile(link).symLinkTarget().isEmpty())
+            LogError() << link << "exists but it's a file.";
+        else
+            LogNormal() << "Symlink exists, skipping:" << link;
+        return false;
+    } else if (QFile::link(file, link)) {
+        LogNormal() << " symlink" << link;
+        LogNormal() << " points to" << file;
+        return true;
+    } else {
+        LogError() << "failed to symlink" << link;
+        LogError() << " to" << file;
+        return false;
+    }
+}
+
+void patch_debugInInfoPlist(const QString &infoPlistPath)
+{
+    // Older versions of qmake may have the "_debug" binary as
+    // the value for CFBundleExecutable. Remove it.
+    QFile infoPlist(infoPlistPath);
+    infoPlist.open(QIODevice::ReadOnly);
+    QByteArray contents = infoPlist.readAll();
+    infoPlist.close();
+    infoPlist.open(QIODevice::WriteOnly | QIODevice::Truncate);
+    contents.replace("_debug", ""); // surely there are no legit uses of "_debug" in an Info.plist
+    infoPlist.write(contents);
+}
+
 FrameworkInfo parseOtoolLibraryLine(const QString &line, bool useDebugLibs)
 {
     FrameworkInfo info;
@@ -182,19 +218,22 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, bool useDebugLibs)
             // remove ".framework"
             name = currentPart;
             name.chop(QString(".framework").length());
+            info.isDylib = false;
             info.frameworkName = currentPart;
             state = Version;
             ++part;
             continue;
         } if (state == DylibName) {
             name = currentPart.split(" (compatibility").at(0);
+            info.isDylib = true;
             info.frameworkName = name;
             info.binaryName = name.left(name.indexOf('.')) + suffix + name.mid(name.indexOf('.'));
             info.installName += name;
             info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName;
             info.frameworkPath = info.frameworkDirectory + info.binaryName;
             info.sourceFilePath = info.frameworkPath;
-            info.destinationDirectory = bundleFrameworkDirectory + "/";
+            info.frameworkDestinationDirectory = bundleFrameworkDirectory + "/";
+            info.binaryDestinationDirectory = info.frameworkDestinationDirectory;
             info.binaryDirectory = info.frameworkDirectory;
             info.binaryPath = info.frameworkPath;
             state = End;
@@ -209,7 +248,8 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, bool useDebugLibs)
             info.deployedInstallName = "@executable_path/../Frameworks/" + info.frameworkName + info.binaryPath;
             info.frameworkPath = info.frameworkDirectory + info.frameworkName;
             info.sourceFilePath = info.frameworkPath + info.binaryPath;
-            info.destinationDirectory = bundleFrameworkDirectory + "/" + info.frameworkName + "/" + info.binaryDirectory;
+            info.frameworkDestinationDirectory = bundleFrameworkDirectory + "/" + info.frameworkName;
+            info.binaryDestinationDirectory = info.frameworkDestinationDirectory + "/" + info.binaryDirectory;
             state = End;
         } else if (state == End) {
             break;
@@ -244,6 +284,22 @@ QStringList findAppLibraries(const QString &appBundlePath)
     return result;
 }
 
+QStringList findAppBundleFiles(const QString &appBundlePath)
+{
+    QStringList result;
+
+    QDirIterator iter(appBundlePath, QStringList() << QString::fromLatin1("*"),
+            QDir::Files, QDirIterator::Subdirectories);
+
+    while (iter.hasNext()) {
+        iter.next();
+        if (iter.fileInfo().isSymLink())
+            continue;
+        result << iter.fileInfo().filePath();
+    }
+
+    return result;
+}
 
 QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, bool useDebugLibs)
 {
@@ -257,7 +313,7 @@ QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, bool useDebu
         }
     }
     return libraries;
-}
+};
 
 QList<FrameworkInfo> getQtFrameworks(const QString &path, bool useDebugLibs)
 {
@@ -295,6 +351,35 @@ QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, bool useD
     return result;
 }
 
+QStringList getBinaryDependencies(const QString executablePath, const QString &path)
+{
+    QStringList binaries;
+
+    QProcess otool;
+    otool.start("otool", QStringList() << "-L" << path);
+    otool.waitForFinished();
+
+    if (otool.exitCode() != 0) {
+        LogError() << otool.readAllStandardError();
+    }
+
+    QString output = otool.readAllStandardOutput();
+    QStringList outputLines = output.split("\n");
+    outputLines.removeFirst(); // remove line containing the binary path
+
+    // return bundle-local dependencies. (those starting with @executable_path)
+    foreach (const QString &line, outputLines) {
+        QString trimmedLine = line.mid(0, line.indexOf("(")).trimmed(); // remove "(compatibility version ...)" and whitespace
+        if (trimmedLine.startsWith("@executable_path/")) {
+            QString binary = QDir::cleanPath(executablePath + trimmedLine.mid(QStringLiteral("@executable_path/").length()));
+            if (binary != path)
+                binaries.append(binary);
+        }
+    }
+
+    return binaries;
+}
+
 // copies everything _inside_ sourcePath to destinationPath
 void recursiveCopy(const QString &sourcePath, const QString &destinationPath)
 {
@@ -324,12 +409,37 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QString &sourceP
     QStringList files = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Files | QDir::NoDotAndDotDot);
     foreach (QString file, files) {
         const QString fileSourcePath = sourcePath + QLatin1Char('/') + file;
-        const QString fileDestinationPath = destinationPath + QLatin1Char('/') + file;
 
         if (file.endsWith("_debug.dylib")) {
             continue; // Skip debug versions
         } else if (file.endsWith(QStringLiteral(".dylib"))) {
+            // App store code signing rules forbids code binaries in Contents/Resources/,
+            // which poses a problem for deploying mixed .qml/.dylib Qt Quick imports.
+            // Solve this by placing the dylibs in Contents/PlugIns/quick, and then
+            // creting a symlink to there from the Qt Quick import in Contents/Resources/.
+            //
+            // Example:
+            // MyApp.app/Contents/Resources/qml/QtQuick/Controls/libqtquickcontrolsplugin.dylib ->
+            // ../../../../PlugIns/quick/libqtquickcontrolsplugin.dylib
+            //
+
+            // The .dylib destination path:
+            QString fileDestinationDir = appBundlePath + QStringLiteral("/Contents/PlugIns/quick/");
+            QDir().mkpath(fileDestinationDir);
+            QString fileDestinationPath = fileDestinationDir + file;
+
+            // The .dylib symlink destination path:
+            QString linkDestinationPath = destinationPath + QLatin1Char('/') + file;
+
+            // The (relative) link; with a correct number of "../"'s.
+            QString linkPath = QStringLiteral("PlugIns/quick/") + file;
+            int cdupCount = linkDestinationPath.count(QStringLiteral("/"));
+            for (int i = 0; i < cdupCount - 2; ++i)
+                linkPath.prepend("../");
+
             if (copyFilePrintStatus(fileSourcePath, fileDestinationPath)) {
+                linkFilePrintStatus(linkPath, linkDestinationPath);
+
                 runStrip(fileDestinationPath);
                 bool useDebugLibs = false;
                 bool useLoaderPath = false;
@@ -337,6 +447,7 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QString &sourceP
                 deployQtFrameworks(frameworks, appBundlePath, QStringList(fileDestinationPath), useDebugLibs, useLoaderPath);
             }
         } else {
+            QString fileDestinationPath = destinationPath + QLatin1Char('/') + file;
             copyFilePrintStatus(fileSourcePath, fileDestinationPath);
         }
     }
@@ -347,56 +458,87 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QString &sourceP
     }
 }
 
-
-QString copyFramework(const FrameworkInfo &framework, const QString path)
+QString copyDylib(const FrameworkInfo &framework, const QString path)
 {
-    QString from = framework.sourceFilePath;
-
-    if (!QFile::exists(from)) {
-        LogError() << "no file at" << from;
+    if (!QFile::exists(framework.sourceFilePath)) {
+        LogError() << "no file at" << framework.sourceFilePath;
         return QString();
     }
 
-    QFileInfo fromDirInfo(framework.frameworkPath + QLatin1Char('/')
-                      + framework.binaryDirectory);
-    bool fromDirIsSymLink = fromDirInfo.isSymLink();
-    QString unresolvedToDir = path + QLatin1Char('/') + framework.destinationDirectory;
-    QString resolvedToDir;
-    QString relativeLinkTarget; // will contain the link from Current to e.g. 4 in the Versions directory
-    if (fromDirIsSymLink) {
-        // handle the case where framework is referenced with Versions/Current
-        // which is a symbolic link, so copy to target and recreate as symbolic link
-        relativeLinkTarget = QDir(fromDirInfo.canonicalPath())
-                .relativeFilePath(QFileInfo(fromDirInfo.symLinkTarget()).canonicalFilePath());
-        resolvedToDir = QFileInfo(unresolvedToDir).path() + QLatin1Char('/') + relativeLinkTarget;
-    } else {
-        resolvedToDir = unresolvedToDir;
+    // Construct destination paths. The full path typically looks like
+    // MyApp.app/Contents/Frameworks/libfoo.dylib
+    QString dylibDestinationDirectory = path + QLatin1Char('/') + framework.frameworkDestinationDirectory;
+    QString dylibDestinationBinaryPath = dylibDestinationDirectory + QLatin1Char('/') + framework.binaryName;
+
+    // Create destination directory
+    if (!QDir().mkpath(dylibDestinationDirectory)) {
+        LogError() << "could not create destination directory" << dylibDestinationDirectory;
+        return QString();
     }
 
-    QString to = resolvedToDir + "/" + framework.binaryName;
+    // Retrun if the dylib has aleardy been deployed
+    if (QFileInfo(dylibDestinationBinaryPath).exists() && !alwaysOwerwriteEnabled)
+        return dylibDestinationBinaryPath;
+
+    // Copy dylib binary
+    copyFilePrintStatus(framework.sourceFilePath, dylibDestinationBinaryPath);
+    return dylibDestinationBinaryPath;
+}
 
-    // create the (non-symlink) dir
-    QDir dir;
-    if (!dir.mkpath(resolvedToDir)) {
-        LogError() << "could not create destination directory" << to;
+QString copyFramework(const FrameworkInfo &framework, const QString path)
+{
+    if (!QFile::exists(framework.sourceFilePath)) {
+        LogError() << "no file at" << framework.sourceFilePath;
         return QString();
     }
 
-    if (!QFile::exists(to) || alwaysOwerwriteEnabled) { // copy the binary and resources if that wasn't done before
-        copyFilePrintStatus(from, to);
+    // Construct destination paths. The full path typically looks like
+    // MyApp.app/Contents/Frameworks/Foo.framework/Versions/5/QtFoo
+    QString frameworkDestinationDirectory = path + QLatin1Char('/') + framework.frameworkDestinationDirectory;
+    QString frameworkBinaryDestinationDirectory = frameworkDestinationDirectory + QLatin1Char('/') + framework.binaryDirectory;
+    QString frameworkDestinationBinaryPath = frameworkBinaryDestinationDirectory + QLatin1Char('/') + framework.binaryName;
 
-        const QString resourcesSourcePath = framework.frameworkPath + "/Resources";
-        const QString resourcesDestianationPath = path + "/Contents/Frameworks/" + framework.frameworkName + "/Resources";
-        recursiveCopy(resourcesSourcePath, resourcesDestianationPath);
+    // Return if the framework has aleardy been deployed
+    if (QDir(frameworkDestinationDirectory).exists() && !alwaysOwerwriteEnabled)
+        return QString();
+
+    // Create destination directory
+    if (!QDir().mkpath(frameworkBinaryDestinationDirectory)) {
+        LogError() << "could not create destination directory" << frameworkBinaryDestinationDirectory;
+        return QString();
     }
 
-    // create the Versions/Current symlink dir if necessary
-    if (fromDirIsSymLink) {
-        QFile::link(relativeLinkTarget, unresolvedToDir);
-        LogNormal() << " linked:" << unresolvedToDir;
-        LogNormal() << " to" << resolvedToDir << "(" << relativeLinkTarget << ")";
+    // Now copy the framework. Some parts should be left out (headers/, .prl files).
+    // Some parts should be included (Resources/, symlink structure). We want this
+    // function to make as few assumtions about the framework as possible while at
+    // the same time producing a codesign-compatible framework.
+
+    // Copy framework binary
+    copyFilePrintStatus(framework.sourceFilePath, frameworkDestinationBinaryPath);
+
+    // Copy Resouces/
+    const QString resourcesSourcePath = framework.frameworkPath + "/Resources";
+    const QString resourcesDestianationPath = frameworkDestinationDirectory + "/Versions/" + framework.version + "/Resources";
+    recursiveCopy(resourcesSourcePath, resourcesDestianationPath);
+
+    // Create symlink structure. Links at the framework root point to Versions/Current/
+    // which again points to the actual version:
+    // QtFoo.framework/QtFoo -> Versions/Current/QtFoo
+    // QtFoo.framework/Resources -> Versions/Current/Resources
+    // QtFoo.framework/Versions/Current -> 5
+    linkFilePrintStatus("Versions/Current/" + framework.binaryName, frameworkDestinationDirectory + "/" + framework.binaryName);
+    linkFilePrintStatus("Versions/Current/Resources", frameworkDestinationDirectory + "/Resources");
+    linkFilePrintStatus(framework.version, frameworkDestinationDirectory + "/Versions/Current");
+
+    // Correct Info.plist location for frameworks produced by older versions of qmake
+    // Contents/Info.plist should be Versions/5/Resources/Info.plist
+    const QString legacyInfoPlistPath = framework.frameworkPath + "/Contents/Info.plist";
+    const QString correctInfoPlistPath = frameworkDestinationDirectory + "/Resources/Info.plist";
+    if (QFile(legacyInfoPlistPath).exists()) {
+        copyFilePrintStatus(legacyInfoPlistPath, correctInfoPlistPath);
+        patch_debugInInfoPlist(correctInfoPlistPath);
     }
-    return to;
+    return frameworkDestinationBinaryPath;
 }
 
 void runInstallNameTool(QStringList options)
@@ -425,7 +567,7 @@ void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework
         QString deployedInstallName;
         if (useLoaderPath) {
             deployedInstallName = QLatin1String("@loader_path/")
-                    + QFileInfo(binary).absoluteDir().relativeFilePath(absBundlePath + QLatin1Char('/') + framework.destinationDirectory + QLatin1Char('/') + framework.binaryName);
+                    + QFileInfo(binary).absoluteDir().relativeFilePath(absBundlePath + QLatin1Char('/') + framework.binaryDestinationDirectory + QLatin1Char('/') + framework.binaryName);
         } else {
             deployedInstallName = framework.deployedInstallName;
         }
@@ -495,8 +637,9 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
         // Install_name_tool the new id into the binaries
         changeInstallName(bundlePath, framework, binaryPaths, useLoaderPath);
 
-        // Copy farmework to app bundle.
-        const QString deployedBinaryPath = copyFramework(framework, bundlePath);
+        // Copy the framework/dylib to the app bundle.
+        const QString deployedBinaryPath = framework.isDylib ? copyDylib(framework, bundlePath)
+                                                             : copyFramework(framework, bundlePath);
         // Skip the rest if already was deployed.
         if (deployedBinaryPath.isNull())
             continue;
@@ -505,6 +648,8 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
 
         // Install_name_tool it a new id.
         changeIdentification(framework.deployedInstallName, deployedBinaryPath);
+
+
         // Check for framework dependencies
         QList<FrameworkInfo> dependencies = getQtFrameworks(deployedBinaryPath, useDebugLibs);
 
@@ -617,8 +762,10 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
 
         if (copyFilePrintStatus(sourcePath, destinationPath)) {
             runStrip(destinationPath);
+
             QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, useDebugLibs);
             deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
+
         }
     }
 }
@@ -667,6 +814,12 @@ void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo,
 void deployQmlImport(const QString &appBundlePath, const QString &importSourcePath, const QString &importName)
 {
     QString importDestinationPath = appBundlePath + "/Contents/Resources/qml/" + importName;
+
+    // Skip already deployed imports. This can happen in cases like "QtQuick.Controls.Styles",
+    // where deploying QtQuick.Controls will also deploy the "Styles" sub-import.
+    if (QDir().exists(importDestinationPath))
+        return;
+
     recursiveCopyAndDeploy(appBundlePath, importSourcePath, importDestinationPath);
 }
 
@@ -796,6 +949,85 @@ void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDe
     }
 }
 
+void codesignFile(const QString &identity, const QString &filePath)
+{
+    if (!runCodesign)
+        return;
+
+    LogNormal() << "codesign" << filePath;
+
+    QProcess codesign;
+    codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements,resource-rules"
+                                             << "--force" << "-s" << identity << filePath);
+    codesign.waitForFinished(-1);
+
+    QByteArray err = codesign.readAllStandardError();
+    if (codesign.exitCode() > 0) {
+        LogError() << "Codesign signing error:";
+        LogError() << err;
+    } else if (!err.isEmpty()) {
+        LogDebug() << err;
+    }
+}
+
+void codesign(const QString &identity, const QString &appBundlePath)
+{
+    // Code sign all binaries in the app bundle. This needs to
+    // be done inside-out, e.g sign framework dependencies
+    // before the main app binary. The codesign tool itself has
+    // a "--deep" option to do this, but usage when signing is
+    // not recommended: "Signing with --deep is for emergency
+    // repairs and temporary adjustments only."
+
+    LogNormal() << "";
+    LogNormal() << "Signing" << appBundlePath << "with identity" << identity;
+
+    QStack<QString> pendingBinaries;
+    QSet<QString> signedBinaries;
+
+    // Create the root code-binary set. This set consists of the application
+    // executable(s) and the plugins.
+    QString rootBinariesPath = appBundlePath + "/Contents/MacOS/";
+    QStringList foundRootBinaries = QDir(rootBinariesPath).entryList(QStringList() << "*", QDir::Files);
+    foreach (const QString &binary, foundRootBinaries)
+        pendingBinaries.push(rootBinariesPath + binary);
+
+    QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/");
+    foreach (const QString &binary, foundPluginBinaries)
+         pendingBinaries.push(binary);
+
+
+    // Sign all binares; use otool to find and sign dependencies first.
+    while (!pendingBinaries.isEmpty()) {
+        QString binary = pendingBinaries.pop();
+        if (signedBinaries.contains(binary))
+            continue;
+
+        // Check if there are unsigned dependencies, sign these first
+        QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary).toSet().subtract(signedBinaries).toList();
+        if (!dependencies.isEmpty()) {
+            pendingBinaries.push(binary);
+            foreach (const QString &dependency, dependencies)
+                pendingBinaries.push(dependency);
+            continue;
+        }
+        // All dependencies are signed, now sign this binary
+        codesignFile(identity, binary);
+        signedBinaries.insert(binary);
+    }
+
+    // Verify code signature
+    QProcess codesign;
+    codesign.start("codesign", QStringList() << "--deep" << "-v" << appBundlePath);
+    codesign.waitForFinished(-1);
+    QByteArray err = codesign.readAllStandardError();
+    if (codesign.exitCode() > 0) {
+        LogError() << "codesign verification error:";
+        LogError() << err;
+    } else if (!err.isEmpty()) {
+        LogDebug() << err;
+    }
+}
 
 void createDiskImage(const QString &appBundlePath)
 {
diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h
index 9a8ff1786e8ccdc3fc2deea54228c7a52c68563c..07e4914c5d5a171a6d4b4e73f8504e8228369da8 100644
--- a/src/macdeployqt/shared/shared.h
+++ b/src/macdeployqt/shared/shared.h
@@ -48,6 +48,7 @@ extern bool runStripEnabled;
 class FrameworkInfo
 {
 public:
+    bool isDylib;
     QString frameworkDirectory;
     QString frameworkName;
     QString frameworkPath;
@@ -58,7 +59,8 @@ public:
     QString installName;
     QString deployedInstallName;
     QString sourceFilePath;
-    QString destinationDirectory;
+    QString frameworkDestinationDirectory;
+    QString binaryDestinationDirectory;
 };
 
 bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
@@ -101,6 +103,8 @@ void changeIdentification(const QString &id, const QString &binaryPath);
 void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath);
 void runStrip(const QString &binaryPath);
 QString findAppBinary(const QString &appBundlePath);
+void codesignFile(const QString &identity, const QString &filePath);
+void codesign(const QString &identity, const QString &appBundlePath);
 void createDiskImage(const QString &appBundlePath);
 
 
diff --git a/src/qconfig/main.cpp b/src/qconfig/main.cpp
index 7d0d8e8f6e733a4113f3a0b5669e10a696598b21..db6b0a673e9206130c265050f6b3222d5899db9c 100644
--- a/src/qconfig/main.cpp
+++ b/src/qconfig/main.cpp
@@ -511,7 +511,7 @@ void Main::about()
     "<p><b><font size=\"+2\">Qtopia Core build configuration</font></b></p>"
     "<p></p>"
     "<p>Version 2.0</p>"
-    "<p>Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).</p>"
+    "<p>Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).</p>"
     "<p></p>"
     );
 }