dylibs and frameworks in bundle app

2019-08-13 02:09发布

问题:

Yesterday I was reading a lot about deploying MacOSX applications, but I still have some doubts. I have been deploying Qt4 applications for MacOSX for the past few years using macdeployqt. Now, mi application uses a library that doesn't belong to the Qt framework: Poppler.

I have installed poppler-qt4 using Homebrew :

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

After using macdeployqt, I know that I have to use install_name_tool to change the absolute paths by relative paths. Some of the dylibs have also dependencies:

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

After using macdeployqt I know that Qt frameworks have been copied inside the app bundle, How can I change /usr/local/lib/QtCore.framework/Versions/4/QtCore with a relative path using install_name_tool?

Are homebrew dylibs compiled using -headerpad_max_install_names?

Is there an automatic way to do this using brew?

What should I use with install_name_tool? @executable_path or @loader_path?

EDIT: It seems that macdeployqt is smart enough to deploy third party dylibs, poppler-qt4 and all its dependencies are copied to the Applicaciont.app/Frameworks folder, and install_name_tool is used automatically. BUT, now I am suffering this BUG : macdeployqt not copying plugins I suppose that the problem is "qt" on the name of poppler-qt4.4.

回答1:

You can change by hand all the paths but it is error-prone, long and painful to do. What I suggest is to use a tool to do it for you: cpack included with cmake.

Anyways since 10.5 you should use: @loader_path. See Dylib.

For MacOS X the following code creates a bundle and copy properly homebrew dylib even with root permissions. However, you will have to check that every lib compiled with homebrew had the right parameters.

Usually, for deployement it is better to compile by hand the libs. I had some problems with homebrew libs (ffmpeg). But not Qt nor 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 )