[CMake] cpack bundle on osx

Yngve Inntjore Levinsen yngve.levinsen at gmail.com
Thu Jan 20 06:15:05 EST 2011


Thank you for your kind reply Michael, it got me some bit further and I 
think I understand a bit more. I could not see any examples of the usage 
of the BundleUtilities in CMake, but the example given in the Wiki works 
as expected on my machine.

I forgot to add some significant parts of my CMakeLists.txt file. I have 
also made some fixes, so the current parts look like this:
...
if (APPLE)
   # So that we get the system X11 libraries if they exist:
   set(CMAKE_LIBRARY_PATH /usr/lib/ /usr/X11/lib/ ${CMAKE_LIBRARY_PATH})
endif (APPLE)
...
if(APPLE)
   SET(MACOSX_BUNDLE_STARTUP_COMMAND madx${BINARY_POSTFIX})
   SET(MACOSX_BUNDLE_ICON_FILE 
"${CMAKE_CURRENT_SOURCE_DIR}/cmakesrc/MadX.icns")
   SET(MACOSX_BUNDLE_LONG_VERSION_STRING "MadX ${BINARY_POSTFIX} version 
${madX_MAJOR_VERSION}.${madX_MINOR_VERSION}.${madX_PATCH_LEVEL}")
   SET(MACOSX_BUNDLE_BUNDLE_NAME "MadX${BINARY_POSTFIX}")
   SET(MACOSX_BUNDLE_GUI_IDENTIFIER "MadX${BINARY_POSTFIX}")
   # add icns to the .app/Resources with these TWO commands:
   SET(srcfiles ${srcfiles} ${CMAKE_CURRENT_SOURCE_DIR}/cmakesrc/MadX.icns)
   
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/cmakesrc/MadX.icns 
PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endif(APPLE)

add_executable(madx${BINARY_POSTFIX} MACOSX_BUNDLE ${srcfiles})
SET_TARGET_PROPERTIES(madx${BINARY_POSTFIX} PROPERTIES LINKER_LANGUAGE 
Fortran)
...
FIND_PACKAGE(X11)
IF(X11_FOUND)
    message("Found X11 libraries")
    INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR})
    TARGET_LINK_LIBRARIES(madx${BINARY_POSTFIX} ${X11_X11_LIB})
ENDIF(X11_FOUND)
...
target_link_libraries(madx${BINARY_POSTFIX} z)
target_link_libraries(madx${BINARY_POSTFIX} pthread)
target_link_libraries(madx${BINARY_POSTFIX} c)
target_link_libraries(madx${BINARY_POSTFIX} gcc_eh)
...
if(APPLE)
   set(APPS "\${CMAKE_INSTALL_PREFIX}/madx${BINARY_POSTFIX}.app")  # 
paths to executables
   set(DIRS "")
   message("aps: ${APPS}")
   INSTALL(CODE "
     include(BundleUtilities)
     message(\"aps: ${APPS}\")
     fixup_bundle(\"${APPS}\"   \"\"   \"${DIRS}\")
     " COMPONENT Runtime)
   INSTALL(TARGETS madx${BINARY_POSTFIX}
    BUNDLE DESTINATION . COMPONENT Runtime
    RUNTIME DESTINATION bin COMPONENT Runtime
    )
else(APPLE)
   INSTALL(TARGETS madx${BINARY_POSTFIX}
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
   )
endif(APPLE)
...
  # so that we can build dragndrop on osx (actually needed?):
  set(CPACK_BINARY_DRAGNDROP ON)
  include (CPack)
...


What I don't understand is why it does not work on my own project. From 
what I can see you can actually replace the fixup_bundle() in the 
example with simply fixup_bundle(\"${APPS}\" \"\" \"\"). This still 
gives the following result when I check the binary with otools:
otool -L 
_CPack_Packages/Darwin/DragNDrop/QtTest-0.1.1-Darwin/QtTest.app/Contents/MacOS/QtTest 

_CPack_Packages/Darwin/DragNDrop/QtTest-0.1.1-Darwin/QtTest.app/Contents/MacOS/QtTest:
     @executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui 
(compatibility version 4.7.0, current version 4.7.0)
     @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore 
(compatibility version 4.7.0, current version 4.7.0)
     @executable_path/../MacOS/libstdc++.6.dylib (compatibility version 
7.0.0, current version 7.13.0)
     @executable_path/../MacOS/libgcc_s.1.dylib (compatibility version 
1.0.0, current version 1.0.0)
     /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current 
version 125.2.1)
The original shows:
otool -L QtTest.app/Contents/MacOS/QtTest
QtTest.app/Contents/MacOS/QtTest:
     
/opt/local/libexec/qt4-mac-devel/lib/QtGui.framework/Versions/4/QtGui 
(compatibility version 4.7.0, current version 4.7.0)
     
/opt/local/libexec/qt4-mac-devel/lib/QtCore.framework/Versions/4/QtCore 
(compatibility version 4.7.0, current version 4.7.0)
     /opt/local/lib/gcc44/libstdc++.6.dylib (compatibility version 
7.0.0, current version 7.13.0)
     /opt/local/lib/gcc44/libgcc_s.1.dylib (compatibility version 1.0.0, 
current version 1.0.0)
     /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current 
version 125.2.1)

So it seems that it by itself figured out that libraries in /opt/local 
should be relinked and added to the bundle, whereas the /usr/lib library 
can stay as it is. This is great stuff.

Doing the same with mine it fails with the "not a valid bundle" error. I 
have the following original output from otools:
otool -L madx_dev.app/Contents/MacOS/madx_dev
madx_dev.app/Contents/MacOS/madx_dev:
     /usr/X11/lib/libX11.6.dylib (compatibility version 9.0.0, current 
version 9.0.0)
     /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 
1.2.3)
     /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current 
version 125.2.1)
     /opt/local/lib/gcc44/libstdc++.6.dylib (compatibility version 
7.0.0, current version 7.13.0)
     /opt/local/lib/gcc44/libgfortran.3.dylib (compatibility version 
4.0.0, current version 4.0.0)
     /opt/local/lib/gcc44/libgcc_s.1.dylib (compatibility version 1.0.0, 
current version 1.0.0)

In principle the only thing not available in /usr/ is the gfortran 
library (right), but I guess I should expect that it would copy 
everything that is linked to a library residing in /opt/local in the 
same manner as for QtTest. However, the fixup_utilities does not relink 
any of those libraries. What am I doing wrong? Are there anything you 
need to set prior to the install(CODE "... command? I have been trying 
to read through the QtTest example, and I don't see anything that should 
imply so.

I have too many questions at once I suppose, but there is still one more 
important: My application is a "terminal app", so it does not come with 
a GUI. Does this mean that the bundle-concept of osx is not fitted very 
well to my application? Can I somehow run a script that will open my 
application in a new Terminal.app window or something of that sort? I 
realized that other applications work so that if you click on the 
Name.app you see the GUI only, whereas if you click on the executable 
Contents/MacOS/Name you first see a terminal that then opens the GUI...? 
Is e.g. Octave bundled, and how is that done?

Cheers
Yngve




On 1/19/11 4:42 PM, Michael Jackson wrote:
> You will need to look into the "BundleUtilities" functionality, specifically the "fixup_bundle()" function. This will copy and fixup dependent dylibs/frameworks needed by your project. There is a short example that uses Qt that you can download.
>
>    You will also probably need to properly configure a plist that resides in your Application bundle. THere are CMake variables for this that you can set then CMake will create a default plist for you.
>
>    There are a number of examples, CMake itself is one, that uses the "fixup_bundle()" in its own code.
>
>    Separate from all of that is all the CPack variables that you probably need to set.
>
> Here is a macro that I wrote for one of my own projects:
>
> #-------------------------------------------------------------------------------
> # This macro will set all the variables necessary to have a "good" OS X Application
> # bundle. The variables are as follows:
> #  PROJECT_NAME - which can be taken from the ${PROJECT_NAME} variable is needed
> #  DEBUG_EXTENSION - The extension used to denote a debug built Application. Typically
> #   this is '_debug'
> #  ICON_FILE_PATH - The complete path to the bundle icon file
> #  VERSION_STRING - The version string that you wish to use for the bundle. For OS X
> #   this string is usually XXXX.YY.ZZ in type. Look at the Apple docs for more info
> #-------------------------------------------------------------------------------
> macro(ConfigureMacOSXBundlePlist PROJECT_NAME DEBUG_EXTENSION ICON_FILE_PATH VERSION_STRING)
>    # message(STATUS "ConfigureMacOSXBundlePlist for ${PROJECT_NAME} ")
>    IF(CMAKE_BUILD_TYPE MATCHES "Release")
>      SET(DBG_EXTENSION "")
>    else()
>      set(DBG_EXTENSION ${DEBUG_EXTENSION})
>    endif()
>    get_filename_component(ICON_FILE_NAME "${ICON_FILE_PATH}" NAME)
>
>   #CFBundleGetInfoString
>   SET(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}${DBG_EXTENSION} Version ${VERSION_STRING}, Copyright 2009 BlueQuartz Software.")
>   SET(MACOSX_BUNDLE_ICON_FILE ${ICON_FILE_NAME})
>   SET(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_NAME}${DBG_EXTENSION}")
>   #CFBundleLongVersionString
>   SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME}${DBG_EXTENSION} Version ${VERSION_STRING}")
>   SET(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}${DBG_EXTENSION})
>   SET(MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION_STRING})
>   SET(MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION_STRING})
>   SET(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010, BlueQuartz Software. All Rights Reserved.")
>
>   SET(${PROJECT_NAME}_PROJECT_SRCS ${${PROJECT_NAME}_PROJECT_SRCS} ${ICON_FILE_PATH})
>   SET_SOURCE_FILES_PROPERTIES(${ICON_FILE_PATH} PROPERTIES
>                               MACOSX_PACKAGE_LOCATION Resources)
>
> endmacro()
>
> Hope that helps
> ___________________________________________________________
> Mike Jackson                      www.bluequartz.net
> Principal Software Engineer       mike.jackson at bluequartz.net
> BlueQuartz Software               Dayton, Ohio
>
> On Jan 19, 2011, at 7:08 AM, Yngve Inntjore Levinsen wrote:
>
>> Dear fellow cmake users,
>>
>> I am trying to create a bundle of my project that I build using CMake. I have tried using the DragNDrop generator, which works to some extent. I do manage to create a .app folder which contains the one binary that is the outcome of the project in the Contents/MacOS folder. I do also create a .dmg file. However:
>> - When clicking the .dmg I am first presented with the license (great!) before the dmg is mounted and I see an empty folder (??)
>> - When clicking on the<package>.app nothing happens. However, clicking on the binary in Contents/MacOS works as expected.
>> - I would also like to know how to include the shared libraries (dylib) that I need. I currently depend on stuff that is installed with MacPorts, and I don't want to require that the user have to install all that stuff. Isn't the bundle supposed to be "self-contained"? Ideally I would like the bundle to automatically include the libraries that are listed with the "otools -L<binary>" command...
>>
>> Question: Where do I find the DragNDrop documentation/examples? On the wiki ( http://www.paraview.org/Wiki/CMake:CPackPackageGenerators#DragNDrop_.28OSX_only.29 ) there are only two small lines, and my googling skills are apparently not good enough..
>>
>> Here is an extraction of the relevant part of my CMakeLists.txt:
>> ...
>> if(APPLE)
>>   add_executable(madx${BINARY_POSTFIX} MACOSX_BUNDLE ${srcfiles})
>>   SET_TARGET_PROPERTIES(madx${BINARY_POSTFIX} PROPERTIES CPACK_BUNDLE_STARTUP_COMMAND madx${BINARY_POSTFIX})
>>   SET_TARGET_PROPERTIES(madx${BINARY_POSTFIX} PROPERTIES CPACK_BUNDLE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cmakesrc/MadX.icns")
>> else(APPLE)
>>   add_executable(madx${BINARY_POSTFIX} ${srcfiles})
>> endif(APPLE)
>> ...
>>
>> I also set some CPACK_BUNDLE properties because I earlier on tried to use the BUNDLE generator, but from what I understand this should have nothing to do with the DragNDrop generator?
>>
>> Thank you all for reading and thanks in advance for all help you might provide!
>>
>> Cheers,
>> Yngve
>>
>



More information about the CMake mailing list