如何使用调用其他 .dylib 的外部 .dylib 部署应用程序?

How deploy an application with external .dylib who calls an other .dylib?

我构建了一个加载自制 .dylib 的应用程序,而这个 .dylib 必须调用另一个 .dylib。

我在 OS X 上,我使用 Qt。当我在 Qt Creator 中时,我可以 Debug/Release 并且它有效。当我单击位于 .app/Contents/ Frameworks 中的 .app 和我的应用程序使用的所有 .dylib 时,它也有效。我的问题是部署。当我 运行 macdeployqt 时,一切正常并生成一个 .dmg,但是当我启动这个 .dmg 时,出现错误。

这个错误是合乎逻辑的,因为main.dylib调用的.dylib不在文件夹.app/Contents/Frameworks中。如果我在这个文件夹中有它,我不知道如何添加它,它会失败。这也是合乎逻辑的,因为应用程序不调用第二个 .dylib,而是调用主 dylib。没有应用程序文件夹所以...

在使用 macdeployqt 工具之前,您必须将所需的库复制到应用程序包中。您可以通过添加主要目标所依赖的 custom targets 从应用程序本身的项目文件执行复制。这些目标将是 dylib 的副本,您将从构建目录中的其他地方复制它们。

通常,您会有一个构建库和应用程序的顶级子目录项目,例如:

+--- lib-dylib-32920629
    +--- lib-dylib-32920629.pro
    +--- lib1
    |   +--- lib1.pro
    |   +--- lib1.cpp
    |   \--- lib1.h
    \--- main
        +--- main.pro
        \--- main.cpp

从以下位置下载此项目:https://github.com/KubaO/Whosebugn/tree/master/questions/lib-dylib-39206929

lib-dylib-39206929.pro

TEMPLATE = subdirs
SUBDIRS += lib1 main
main.depends += lib1

lib1/lib1.pro

QT = core
CONFIG += c++11
TEMPLATE = lib
HEADERS += lib1.h
SOURCES += lib1.cpp

lib1/lib1.h

#ifndef LIB1_H
#define LIB1_H

#include <QObject>

class Lib1 {
public:
    QString text();
};

#endif

lib1/lib1.cpp

#include "lib1.h"

QString Lib1::text() {
    return QStringLiteral("Hello from Lib1");
}

main/main.pro

可以使用自定义 deployLib 函数将库部署到应用程序包中:

QT = widgets
CONFIG += c++11
TEMPLATE = app
SOURCES += main.cpp
LIBS += -L../lib1 -llib1
INCLUDEPATH += ..
DEPENDPATH += ..

defineReplace(libVersions) {
   # libVersions(1,2,3) - returns .1.2.3. .1.2. .1. .
   versions=.$.$.$. .$.$. .$. .
   return($$versions)
}
defineReplace(dylibs) {
   # dylibs(base,1,2,3) - returns libbase.1.2.3.dylib libbase.1.2.dylib ... libbase.dylib
   base = $
   versions = $$libVersions("$","$","$")
   libs =
   for (version, versions): libs += lib$${base}$${version}dylib
   return($$libs)
}
defineTest(deployLib) {
   # deployLib(target,target2path,target2,1,2,3)
   #   deploys target2path/libtarget2.1.2.3.dylib,... to the target's application bundle
   target = $
   libpath = $
   libtarget = $
   libs = $$dylibs($$libtarget,$,$,$)
   targetdir = $${target}.app/Contents/MacOS
   mktargetdir = "(test -d $$targetdir/ || mkdir -p $$targetdir/)"
   for (lib, libs) {
      out = $$targetdir/$$lib
      $${lib}.target = $$out
      $${lib}.commands = $$mktargetdir
      $${lib}.commands += "&& $$QMAKE_COPY_FILE $$libpath/$$libtarget/$$lib $$out"
      export($${lib}.target)
      export($${lib}.commands)
      QMAKE_EXTRA_TARGETS += $$lib
      PRE_TARGETDEPS += $$out
   }
   export(QMAKE_EXTRA_TARGETS)
   export(PRE_TARGETDEPS)
   return(true)
}

macx {
   deployLib(main, .., lib1, 1, 0, 0)
}

main/main.cpp

#include "lib1/lib1.h"
#include <QtWidgets>

int main(int argc, char ** argv) {
    QApplication app{argc, argv};
    Lib1 lib1;
    QLabel label{lib1.text()};
    label.setMinimumSize(200, 200);
    label.setFont(QFont{"Helvetica", 20});
    label.show();
    return app.exec();
}