MantisBT - CMake
View Issue Details
0012382CMakeModulespublic2011-08-02 18:472016-06-10 14:31
Gregory Crosswhite 
Kitware Robot 
normalminoralways
closedmoved 
Apple MacOS X10.4.10
CMake 2.8.5 
 
0012382: fixup_bundle_item dies on libraries copied to a directory outside bundle directory
When using a Linux-style layout for the installation with bin/, lib/, etc. and directing the required shared libraries to be installed in lib/ instead of bin/, fixup_bundle_item does not recognize that they have been installed into the bundle and reports a fatal error.

The problem comes from the fact that when calling fixup_bundle on an executable in the bin/ directory, fixup_bundle sets the bundle directory to bin/ which is a sibling but not a parent of lib/, and so fixup_bundle_item does not recognize that the library it is fixing up has already been put in the bundle.
The attached file has an example setup that triggers the issue; inside the ZIPfile are three files which are listed below:

===== CMakeLists.txt =====
cmake_minimum_required(VERSION 2.8.5)

set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/bundle)

find_package( Boost COMPONENTS thread REQUIRED )
link_directories ( ${Boost_LIBRARY_DIRS} )
include_directories ( ${Boost_INCLUDE_DIRS} )

add_executable(hello hello)
target_link_libraries(hello ${Boost_LIBRARIES})
install (TARGETS hello RUNTIME DESTINATION bin)

configure_file(
    ${CMAKE_SOURCE_DIR}/FixBundle.cmake.in
    ${CMAKE_BINARY_DIR}/FixBundle.cmake
    @ONLY
)
install(SCRIPT ${CMAKE_BINARY_DIR}/FixBundle.cmake)

===== FixBundle.cmake =====
include (BundleUtilities)

function(gp_item_default_embedded_path item default_embedded_path_var)
  set(${default_embedded_path_var} "@executable_path/../lib" PARENT_SCOPE)
endfunction(gp_item_default_embedded_path)

fixup_bundle("${CMAKE_INSTALL_PREFIX}/bin/hello${CMAKE_EXECUTABLE_SUFFIX}" "" "@LIBRARY_OUTPUT_PATH@")
===== hello.cpp =====
#include <iostream>

using namespace std;

int main() {
  cout << "Hello, world!" << endl;
  return 0;
}
======================

Note that hello.cpp doesn't use Boost, I just included the dependency in order to make sure that an external non-system shared library was pulled in.
No tags attached.
related to 0013052closed Kitware Robot BundleUtilities (fixup_bundle_item): location checks are too strict 
zip cmake-issue-example.zip (1,342) 2011-08-02 18:47
https://public.kitware.com/Bug/file/3992/cmake-issue-example.zip
zip cmake-issue-example-2.zip (1,396) 2011-08-02 19:12
https://public.kitware.com/Bug/file/3993/cmake-issue-example-2.zip
Issue History
2011-08-02 18:47Gregory CrosswhiteNew Issue
2011-08-02 18:47Gregory CrosswhiteFile Added: cmake-issue-example.zip
2011-08-02 19:12Gregory CrosswhiteNote Added: 0027151
2011-08-02 19:12Gregory CrosswhiteFile Added: cmake-issue-example-2.zip
2011-08-02 19:13Gregory CrosswhiteNote Added: 0027152
2011-08-02 19:33Clinton StimpsonNote Added: 0027153
2011-08-02 19:49Gregory CrosswhiteNote Added: 0027154
2012-08-11 11:24David ColeAssigned To => David Cole
2012-08-11 11:24David ColeStatusnew => assigned
2012-08-11 11:28David ColeNote Added: 0030269
2012-08-11 12:45Clinton StimpsonNote Added: 0030323
2012-08-11 12:47Clinton StimpsonNote Added: 0030324
2012-08-11 17:08David ColeRelationship addedrelated to 0013052
2012-11-21 14:57David ColeNote Added: 0031656
2012-11-21 15:00David ColeAssigned ToDavid Cole =>
2012-11-21 15:11David ColeStatusassigned => new
2012-11-21 15:11David ColeNote Added: 0031663
2013-04-22 01:27Craig ScottNote Added: 0032915
2016-02-10 08:49Florian ApollonerNote Added: 0040459
2016-06-10 14:28Kitware RobotNote Added: 0041881
2016-06-10 14:28Kitware RobotStatusnew => resolved
2016-06-10 14:28Kitware RobotResolutionopen => moved
2016-06-10 14:28Kitware RobotAssigned To => Kitware Robot
2016-06-10 14:31Kitware RobotStatusresolved => closed

Notes
(0027151)
Gregory Crosswhite   
2011-08-02 19:12   
Note that this problem is triggered even when there are *no* outside shared libraries being pulled in if a build shared library is listed in the second argument of fixup_bundle but is not installed in the executable directory. See cmake-issue-example-2.zip for this; libhello.cpp is empty, and CMakeLists.txt and FixBundle.cmake.in are as follows:

===== CMakeLists.txt =====
cmake_minimum_required(VERSION 2.8.5)

set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/bundle)

add_executable(hello hello)
add_library(hellolib SHARED hellolib)
install (TARGETS hello DESTINATION bin)
install (TARGETS hellolib DESTINATION lib)

configure_file(
    ${CMAKE_SOURCE_DIR}/FixBundle.cmake.in
    ${CMAKE_BINARY_DIR}/FixBundle.cmake
    @ONLY
)
install(SCRIPT ${CMAKE_BINARY_DIR}/FixBundle.cmake)

===== FixBundle.cmake.in =====
include (BundleUtilities)

fixup_bundle(
  "${CMAKE_INSTALL_PREFIX}/bin/hello@CMAKE_EXECUTABLE_SUFFIX@"
  "${CMAKE_INSTALL_PREFIX}/lib/@CMAKE_SHARED_LIBRARY_PREFIX@hellolib@CMAKE_SHARED_LIBRARY_SUFFIX@"
  "@LIBRARY_OUTPUT_PATH@"
)

=====================

The resulting error message is

=====================
-- Install configuration: ""
-- Up-to-date: /Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/bin/hello
-- Installing: /Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/libhellolib.dylib
-- fixup_bundle
-- app='/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/bin/hello'
-- libs='/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/libhellolib.dylib'
-- dirs=''
-- fixup_bundle: preparing...
-- fixup_bundle: copying...
-- 1/4: *NOT* copying '/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/libhellolib.dylib'
-- 2/4: *NOT* copying '/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/bin/hello'
-- fixup_bundle: fixing...
-- 3/4: fixing up '/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/libhellolib.dylib'
  exe_dotapp_dir/='/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/bin/'
  item_substring='/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/'
  resolved_embedded_item='/Users/gcross/Documents/ThrowawayCode/cmake-issue-example/build/bundle/lib/libhellolib.dylib'

Install or copy the item into the bundle before calling fixup_bundle.
Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?

CMake Error at /Applications/CMake 2.8-5.app/Contents/share/cmake-2.8/Modules/BundleUtilities.cmake:568 (message):
  cannot fixup an item that is not in the bundle...
Call Stack (most recent call first):
  /Applications/CMake 2.8-5.app/Contents/share/cmake-2.8/Modules/BundleUtilities.cmake:656 (fixup_bundle_item)
  FixBundle.cmake:3 (fixup_bundle)
  cmake_install.cmake:54 (INCLUDE)
=====================
(0027152)
Gregory Crosswhite   
2011-08-02 19:13   
It seems to me like the best way to resolve this is to let the user override the way that the bundle directory is obtained from the path to the executable; this would also cause fixup_bundle to correctly scan through the entire bundle looking for libraries rather than just the subdirectory containing the executable specified in the first parameter of fixup_bundle.
(0027153)
Clinton Stimpson   
2011-08-02 19:33   
The fix for this bug is to modify the check that throws the "Install or copy..." error.
(0027154)
Gregory Crosswhite   
2011-08-02 19:49   
Okidoke; you're the developer, not me. :-)
(0030269)
David Cole   
2012-08-11 11:28   
Clinton,

How should we modify this?

The intent everywhere is to make sure the final bundle is truly stand-alone and may be relocated to another machine and another root directory and still work.

The intent on Mac was to make sure all files are contained within the .app directory structure to ensure that it is "stand-alone".

The intent on Windows is to make sure *all* files are in *the same* directory so that DLL loading "just works".

What is the intent with "fixup_bundle" on Linux? Is *any* directory structure ok, and if so, how do know the "bundle" will work when it is simply copied/moved to a new machine/location on Linux?

I'd be happy to take this one, but I still don't have a good grasp on how useful this is on Linux. One of these days, I've got to get into building my own little bundle example app on Linux, so I have a little sandbox app that I understand fully.

Thanks...
(0030323)
Clinton Stimpson   
2012-08-11 12:45   
BundleUtilities is likely less popular on Linux, and is most likely used by those shipping their own binaries with their own 3rd party libraries which may or may not exist on any given target machine. I don't think these users are bound to the bin/ lib/ convention, since the intent of BundleUtilities is to make a relocatable/standalone application.

Any directory structure is allowed on Linux when using rpaths.
When using a bin/ lib/ structure, an executable can have an rpath of "$ORIGIN/../lib" so any dependent shared library will be found. For a plugin down in "plugins/typeA/" directory, it could have an rpath of $ORIGIN/../../lib to find its dependencies.
So, if one were to copy/move the parent directory (containing bin/ lib/ plugins/), it would still work.

We had a discussion a while back about the user passing in a prefix which could be different than the executable directory or the .app directory. Perhaps that is the solution we need here.
That would also fix this one: http://www.cmake.org/Bug/view.php?id=13052. [^]

I'd also like to see full @rpath support someday on the Mac, and move away from @executable_path. Perhaps if you took the time to use @rpath on Mac, you would fully understand rpaths on Linux. Though on Linux, its a bit simpler.
(0030324)
Clinton Stimpson   
2012-08-11 12:47   
Oh, I just realized the Reporter is on Mac, not Linux, which means this is even more similar to bug 0013052.
(0031656)
David Cole   
2012-11-21 14:57   
Un-assigning bugs that are not on the active roadmap, which no developers are actively working on for the CMake 2.8.11 release.

If one gets put back on the roadmap, re-assign it appropriately at that time.
(0031663)
David Cole   
2012-11-21 15:11   
Re-setting status back to "new" for bugs that are "assigned" but not assigned to a specific developer. When/if these bugs go back on the roadmap for a specific version, assignment to an appropriate developer should take place then...
(0032915)
Craig Scott   
2013-04-22 01:27   
Any chance this one can make it back on someone's todo list? I've hit exactly this scenario on linux. We have a bin/ lib/ structure and we use the include(InstallRequiredSystemLibraries) feature to ensure we get packages which are fully self-contained. We use an RPATH of $ORIGIN/../lib as described by Clinton. The arrangement works well on Windows and would probably work well on Mac, but on linux it means the install step is broken because it doesn't find libraries in lib/. Strangely, the install step copies duplicates of those libraries into bin/ which is probably a direct consequence, but that just makes it even harder to understand why the verify_app step fails!

Not sure if it's related, but it might also be worth reviewing bug 0013433 just in case it is relevant. Personally though, I suspect the problem is more related to the fact that the RPATH substitution results in a full path containing /../ and somewhere in the CMake code it compares this against a canonical path or something similar.
(0040459)
Florian Apolloner   
2016-02-10 08:49   
@Craig: I've fixed it like this for me:

set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib")

set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/BAPGui")
install(TARGETS bap-gui DESTINATION bin)

get_target_property(QMAKE_PATH Qt5::qmake IMPORTED_LOCATION)
execute_process(COMMAND ${QMAKE_PATH} -query QT_INSTALL_PREFIX OUTPUT_VARIABLE QT_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)

install(CODE "
    function(gp_item_default_embedded_path_override item path_var)
        set(\${path_var} \"@executable_path/../lib\" PARENT_SCOPE)
    endfunction()
    function(gp_resolved_file_type_override item type_var)
        if(\${item} MATCHES \"\\\\.\\\\./lib\")
            set(\${type_var} \"local\" PARENT_SCOPE)
        endif()
    endfunction()
    include(${CMAKE_CURRENT_SOURCE_DIR}/BundleUtilitiesLocal.cmake)
    fixup_bundle(\"\$ENV{DESTDIR}/\${CMAKE_INSTALL_PREFIX}/bin/bap-gui\" \"\" \"${QT_PREFIX}/lib\")
")

set(CPACK_GENERATOR "TGZ")
(0041881)
Kitware Robot   
2016-06-10 14:28   
Resolving issue as `moved`.

This issue tracker is no longer used. Further discussion of this issue may take place in the current CMake Issues page linked in the banner at the top of this page.