捆绑应用程序中的 dylib 和框架

Posted

技术标签:

【中文标题】捆绑应用程序中的 dylib 和框架【英文标题】:dylibs and frameworks in bundle app 【发布时间】:2013-01-12 08:29:44 【问题描述】:

昨天我阅读了很多关于部署 MacOSX 应用程序的信息,但我仍然有些疑惑。在过去的几年里,我一直在使用 macdeployqt 为 MacOSX 部署 Qt4 应用程序。现在,mi 应用程序使用了一个不属于 Qt 框架的库:Poppler。

我已经使用 Homebrew 安装了 poppler-qt4:

brew install poppler --with-qt4 --enable-xpdf-headers

使用macdeployqt后,我知道我必须使用install_name_tool通过相对路径来改变绝对路径。一些 dylib 也有依赖关系:

MyApp.app/Contents/MacOS/MyApp:
    /usr/local/lib/libpoppler-qt4.4.dylib

/usr/local/lib/libpoppler-qt4.4.dylib:
  /usr/local/Cellar/poppler/0.20.5/lib/libpoppler.28.dylib
  /usr/local/lib/libfontconfig.1.dylib
  /usr/local/lib/QtCore.framework/Versions/4/QtCore
  /usr/local/lib/QtGui.framework/Versions/4/QtGui
  /usr/local/lib/QtXml.framework/Versions/4/QtXml

使用macdeployqt后,我知道Qt框架已经被复制到app bundle中,我该如何更改/usr/local/lib/QtCore.framework/Versions/4/QtCore 使用 install_name_tool 的相对路径?

自制 dylib 是否使用 -headerpad_max_install_names 编译

是否有使用 brew 自动执行此操作的方法?

我应该使用 install_name_tool 做什么? @executable_path 还是 @loader_path?

编辑:似乎 macdeployqt 足够聪明,可以部署第三方 dylib,poppler-qt4 及其所有依赖项都被复制到 Applicaciont.app/Frameworks 文件夹,并自动使用 install_name_tool。但是,现在我正在遭受这个 BUG:macdeployqt not copying plugins 我想问题是 poppler-qt4.4 名称上的“qt”。

【问题讨论】:

【参考方案1】:

您可以手动更改所有路径,但这样做容易出错、耗时且痛苦。 我的建议是使用一个工具来为你做这件事:cmake 中包含的 cpack。

从 10.5 开始,您应该使用:@loader_path。见Dylib。

对于 MacOS X,以下代码创建一个包并正确复制 homebrew dylib,即使具有 root 权限。 但是,您必须检查使用 homebrew 编译的每个库是否具有正确的参数。

通常,对于部署,最好手动编译库。我在自制库(ffmpeg)方面遇到了一些问题。但不是 Qt 也不是 Boost :-)。

if( USE_QT5 )
     qt5_use_modules( MyApp Core OpenGL Sql Multimedia Concurrent )
endif()

# Install stuff
set( plugin_dest_dir bin )
set( qtconf_dest_dir bin )
set( APPS "\$CMAKE_INSTALL_PREFIX/bin/MyApp" )
if( APPLE )
    set( plugin_dest_dir MyApp.app/Contents/ )
    set( qtconf_dest_dir MyApp.app/Contents/Resources )
    set( APPS "\$CMAKE_INSTALL_PREFIX/MyApp.app" )
endif( APPLE )
if( WIN32 )
    set( APPS "\$CMAKE_INSTALL_PREFIX/bin/MyApp.exe" )
endif( WIN32 )

#--------------------------------------------------------------------------------
# Install the MyApp application, on Apple, the bundle is at the root of the
# install tree, and on other platforms it'll go into the bin directory.
install( TARGETS MyApp
    BUNDLE DESTINATION . COMPONENT Runtime
    RUNTIME DESTINATION bin COMPONENT Runtime
)

#--------------------------------------------------------------------------------
# Install needed Qt plugins by copying directories from the qt installation
# One can cull what gets copied by using 'REGEX "..." EXCLUDE'
install( DIRECTORY "$QT_PLUGINS_DIR/imageformats"
    "$QT_PLUGINS_DIR/codecs"
    "$QT_PLUGINS_DIR/phonon_backend"
    "$QT_PLUGINS_DIR/sqldrivers"
    "$QT_PLUGINS_DIR/accessible"
    "$QT_PLUGINS_DIR/bearer"
    "$QT_PLUGINS_DIR/graphicssystems"
    DESTINATION $plugin_dest_dir/PlugIns
    COMPONENT Runtime
    FILES_MATCHING
    PATTERN "*.dylib"
    PATTERN "*_debug.dylib" EXCLUDE
)

#--------------------------------------------------------------------------------
# install a qt.conf file
# this inserts some cmake code into the install script to write the file
install( CODE "
    file(WRITE \"\$CMAKE_INSTALL_PREFIX/$qtconf_dest_dir/qt.conf\" \"\")
    " COMPONENT Runtime
)


#--------------------------------------------------------------------------------
# Use BundleUtilities to get all other dependencies for the application to work.
# It takes a bundle or executable along with possible plugins and inspects it
# for dependencies.  If they are not system dependencies, they are copied.

# directories to look for dependencies
set( DIRS $QT_LIBRARY_DIRS $MYAPP_LIBRARIES )

# Now the work of copying dependencies into the bundle/package
# The quotes are escaped and variables to use at install time have their $ escaped
# An alternative is the do a configure_file() on a script and use install(SCRIPT  ...).
# Note that the image plugins depend on QtSvg and QtXml, and it got those copied
# over.

install( CODE "
    file(GLOB_RECURSE QTPLUGINS
      \"\$CMAKE_INSTALL_PREFIX/$plugin_dest_dir/plugins/*$CMAKE_SHARED_LIBRARY_SUFFIX\")
    set(BU_CHMOD_BUNDLE_ITEMS ON)
    include(BundleUtilities)
    fixup_bundle(\"$APPS\" \"\$QTPLUGINS\" \"$DIRS\")
    " COMPONENT Runtime
)

# To Create a package, one can run "cpack -G DragNDrop CPackConfig.cmake" on Mac OS X
# where CPackConfig.cmake is created by including CPack
# And then there's ways to customize this as well
set( CPACK_BINARY_DRAGNDROP ON )
include( CPack )

【讨论】:

感谢分享您的脚本

以上是关于捆绑应用程序中的 dylib 和框架的主要内容,如果未能解决你的问题,请参考以下文章

错误 ITMS-90171:“无效的捆绑结构不允许二进制文件 APP.app/libswiftRemoteMirror.dylib

自定义捆绑在 iOS 框架文件中的故事板

链接到在应用程序扩展中使用不安全的 dylib

捆绑框架与XCode中的应用程序

提交快速应用程序+框架时捆绑无效

Mac 应用程序在启动时崩溃,链接框架未捆绑