OSX: CMake+RPath confusion - xcode

I have a cmake project that is building, but at runtime (for ex, when running my unit tests executable) it is not able to link one of my dylib dependencies. Looking at the output of "otool -L" I see a long list of deps prefixed with #rpath except for one offending set of libs (which all came from same package) that do not have that. Here is a representative example, where the offenders are the libicu* libs:
#rpath/libboost_date_time.dylib ...
libicui18n.44.dylib ...
libicuio.44.dylib ...
#rpath/libQt5DBus_debug.5.dylib ...
Is there anything I can do at build time to get that #rpath prefix on those deps? Looking at the cmake RPATH docs it sounds to me like the RPATH can be set, but by default it will be correct, including all linked lib paths... it isn't clear to me how to make sure the libs themselves use the rpath. Is there anything I can do at build time to make sure that the #rpath prefix is on the dep name?

CMake has some special magic since version 2.8.12 which got additional settings later on and quickliy established as a default.
The proprty MACOSX_RPATH is used on targets to initialize rpath correctly on OSX.
The Policy CMP0042 controls if this is defautl behavior or not.
https://cmake.org/cmake/help/v3.0/prop_tgt/MACOSX_RPATH.html#prop_tgt:MACOSX_RPATH
https://cmake.org/cmake/help/v3.0/policy/CMP0042.html

Related

CMake warnings under OS X: MACOSX_RPATH is not specified for the following targets

I try to build a CMake-based software under OS X (Yosemite) which can be built successfully under Fedora 21. It uses a bunch of libraries. Both, big open ones like Boost and some self-written ones lying in /installation_folder/lib. I use CMake version 3.3.0.
After executing
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=/usr/local/Cellar/gcc/5.2.0/bin/gcc-5 -DCMAKE_CXX_COMPILER=/usr/local/Cellar/gcc/5.2.0/bin/g++-5 -DCMAKE_MODULE_PATH=${PWD}/../external/install/share/llvm/cmake
I get the following warnings:
CMake Warning (dev):
Policy CMP0042 is not set: MACOSX_RPATH is enabled by default. Run "cmake
--help-policy CMP0042" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
MACOSX_RPATH is not specified for the following targets:
ClangWrapper
Structure
WCETXML
This warning is for project developers. Use -Wno-dev to suppress it.
The CMakeLists.txt contains the following lines regarding RPATH:
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
IF("${isSystemDir}" STREQUAL "-1")
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
ENDIF("${isSystemDir}" STREQUAL "-1")
All I can say is that ${CMAKE_INSTALL_PREFIX}/lib is indeed the correct path, and that other libraries like Boost are found correctly.
Ignoring the warnings and continuing with "make" in the build directory results in a linking error.
I read the CMake Wiki RPATH handling article, but I am still not able to distinguish between these path variables and their correct use on OS X.
Adding set(CMAKE_MACOSX_RPATH 1) into CMakeLists.txt, before the above written statements, lets the warnings disappear. The linking problem after executing make stays. This brings me to the assumption that my RPATH setup has nothing to do with my linking problem.
Nevertheless, this thread's problem is solved. An explanation about the correct use of the RPATH options inside CMakeLists.txt is still very welcome!
Well, I'll just go one step forward from #fotinsky's answer. (Feel free to incorporate this into your answer.)
The output of the warning's suggestion to run cmake-policy --help-policy CMP0042 is:
CMake 2.8.12 and newer has support for using ``#rpath`` in a target's install
name. This was enabled by setting the target property
``MACOSX_RPATH``. The ``#rpath`` in an install name is a more
flexible and powerful mechanism than ``#executable_path`` or ``#loader_path``
for locating shared libraries.
CMake 3.0 and later prefer this property to be ON by default. Projects
wanting ``#rpath`` in a target's install name may remove any setting of
the ``INSTALL_NAME_DIR`` and ``CMAKE_INSTALL_NAME_DIR``
variables.
This policy was introduced in CMake version 3.0. CMake version
3.1.3 warns when the policy is not set and uses OLD behavior. Use
the cmake_policy command to set it to OLD or NEW explicitly.
This simply means that in later cmake versions, the user is required to explicitly enable or disable CMAKE_MACOSX_RPATH.
There's also more background info on the introduction of this variable in this CMake blog entry.
As mentioned in a comment above, if you don't need to target older versions of cmake, you can simply set:
cmake_minimum_required (VERSION 3.0)
This removes the ambiguity of default values between major versions and simply enables runtime path behaviors by default.

Building libraries that have ExternalProjects Added using CMake and Xcode

I am trying to use CMake to build a library (which in turn links to other libraries built via CMake). I am having a couple of issues with this process and would love to have some guidance.
For the library, I have a CMakeLists.txt which essentially has
set(SRC srcfile1.cpp srcfile2.cpp)
set(HEADERS srcfile1.h srcfile2.h)
add_library(myLib ${SRC} ${HEADERS})
INSTALL(FILES ${HEADERS} DESTINATION “include/myLib”)
For a “Unix Makefiles” generator, with cmake command
cmake -DCMAKE_INSTALL_PREFIX=. -DCMAKE_BUILD_TYPE=debug -G “Unix Makefiles” ..
I get an appropriate debug library libMyLib.a in build/src. For a release build type, a release build of libMyLib.a is placed in build/src
However, for an Xcode generator, the library is placed in src/Debug. The issues I am facing here are
a. Doing an Archive in Xcode doesn’t seem to have any effect. I don’t see a corresponding Release library being created anywhere
b. I also have a myLibTests target (which uses googles gtest) which is defined in it’s CMakeLists.txt as
set(SRC myTest.cpp)
add_executable(myLibTests ${SRC})
add_dependencies(myLibTests myLib gtest)
set(gTestLib External/src/gTestLib)
target_link_libraries(myLibTests myLib gTestLib)
When the cmake generator is “Unix Makefiles” myLibTests build, links and runs fine. gTestLib is placed in External/src/gtest-build/. But, when it is “Xcode”, it can’t find the gTest libraries. because, the library is placed in External/src/gTestLib/Debug(or Release) as the case may be (and the above path set in CMakeLists.txt is no longer valid). I am not sure how to set it’s path appropriately in the above set statement.
Since, debug/release is controlled in Xcode (and the configure process in CMake is unaware of this), I assume there isn’t a way to separate the release/debug builds of the gTestLib and also have CMake configure Xcode to pick up the appropriate version while building myLib i.e if I do a debug build of myLib it also does a debug build of gTest and links to it (similar for release builds)? Alternatively, is it possible to configure Xcode to place both the Debug and Release builds in the same location (and then hardcode it’s path above)? What would be the best way of configuring this?
Thanks

CMake with Xcode 5 : how to add external libraries as 'Target Dependencies' instead of linker flags?

We are building our software under OS X (10.8 at the moment). The project build is managed by CMake (2.8.12).
External dependencies (i.e. not target added by project's CMakeLists) are handled using what we undestood as the canonical way :
Calling find_package(${external_lib}) from a root CMakeLists.
If a given target needs to link against the previously found package, the target's CMakeLists calls target_link_libraries(${TARGET_NAME} ${${external_lib}_LIBRARIES})
The procedure works nicely from a building perspective (the target is actually linked against the external library). Yet the external library is actually given as an additional flag to the compiler, in Build Settings::Other Linker Flags, when it seems that Xcode native way for doing this would be to add the dirname to Build Settings::Library Search Path, and the basename to Build phases::Target Dependencies.
Is there a way to achieve this behavior (without breaking the behavior for other platforms) ?
The behavior of CMake was changed years ago to use full paths.
http://www.cmake.org/cmake/help/v3.0/policy/CMP0003.html
Why do you want to split it?

Xcode linker error, cannot find lib in /usr/lib

I am getting a linker error in XCode 3.2 where it claims to not be able to find libs in /usr/lib even though LIBRARY_SEARCH_PATHS = "/usr/lib" and the dylib has been added to the xcode project. The later copy build phase of the project manages to find this file without any problems, but the cannot.
I have tried to scrap the project settings window for a xcconfig setup instead, so may have done something wrong there. Any ideas as to what I am missing?
Note that paths such as /usr/lib are prefixed by your SDK setting, so what you think is /usr/lib may in fact be e.g. /Developer/SDKs/MacOSX10.6.sdk/usr/lib (if your SDK is set to 10.6).
If you want to link to something in /usr/lib and not in /Developer/SDKs/bla/usr/lib you'll need to use full path to the library when linking. Add it to "Other Linker Flags": /usr/lib/somelib.dylib (note that there is no -l in front of the path)

Why doesn't Xcode recognize my LIBRARY_SEARCH_PATHS?

I've set LIBRARY_SEARCH_PATHS to /opt/local/lib, and verified that the library in question is there (I'm linking to GLEW):
$ls /opt/local/lib
libGLEW.1.5.1.dylib libfreetype.a libz.a
libGLEW.1.5.dylib libfreetype.dylib libz.dylib
libGLEW.a libfreetype.la pkgconfig
libGLEW.dylib libz.1.2.3.dylib
libfreetype.6.dylib libz.1.dylib
but Xcode gives me the linker error
library not found for -lGLEW
I'm generating the Xcode project with CMake, so I don't want to explicitly modify the Xcode project (if someone suggests adding it as a framework, or something like that). Xcode recognizes USER_HEADER_SEARCH_PATHS fine (as in this question); why doesn't it work here?
Perhaps adding something like this to your CMakeLists.txt?
find_library(GLEW_LIB GLEW /opt/local/lib)
if(NOT ${GLEW_LIB})
message(FATAL_ERROR "Could not find GLEW")
endif()
target_link_libraries(myprogram ${GLEW_LIB} ...)
Where myprogram is the name of the target executable that needs to link with the library. You would replace the ... with the other libraries you are using on that executable.
This way CMake would handle the library path details for you.
Xcode works on potentially multiple SDK's, so whenever your define these kinds of things (like HEADER_SEARCH_PATHS or LIBRARY_SEARCH_PATHS) the current SDK root is prepended to the actual path that's getting passed to the linker.
So, one way to make this work would be to add your directory to the SDK. For example, assuming you're building with the Mac OS X 10.5 sdk, you could add your opt dir:
ln -s /opt /Developer/SDKs/MacOSX10.5.sdk/opt
Your library would now be found on your system.
If you don't want to do this, then you will have to look at CMake and find out how to get it to generate a library requirement for your actual library (I don't know anything about CMake, so I can't help you there). This is also why you see a difference between USER_HEADER_SEARCH_PATHS and HEADER_SEARCH_PATHS re your other question.
As another option, you could also specify this path with the OTHER_LDFLAGS build variable:
OTHER_LDFLAGS=-L/opt/local/lib
This would cause the linker to search /opt/local/lib as well as its standard paths and wouldn't require you to generate a different project file.

Resources