Adding a rpath item to the build tree generated executable - macos

I always run my executable in the build tree (I don't run it from a cmake "install"). A library, let's call it fruit, is built as a framework:
add_library( fruit SHARED ${FRUIT_SOURCES} )
set_target_properties( fruit PROPERTIES FRAMEWORK TRUE)
set_target_properties( fruit PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_NAME_DIR "#rpath/Frameworks" )
Now I want to set a custom rpath for main application (called executable) with cmake. I thought I could use the INSTALL_RPATH target property of executable to define my rpaths for the generated program, but this seems to only work for an installed executable (remember I always run my application in the cmake build folder):
# this rpath is not shown in the generated executable (otool -l -v executable):
set_target_properties( executable PROPERTIES INSTALL_RPATH "#executable_path/lib/" )
How define/add a rpath item to the program generated in the build tree?
PS. This library fruit is just an example of my actual problem. The library is created in a sub cmake project (a git submodule) which adds the BUILD_WITH_INSTALL_RPATH property to the library. But I have the possibility to change the code for this project. Is there a better way to let my executable work in the build tree?

This is not an answer to the main question, but I figured out an answer to the post scriptum. This is a better solution than the one searced for in the main question, but I let that question persist.
set( CMAKE_MACOSX_RPATH TRUE )
set( CMAKE_SKIP_BUILD_RPATH FALSE )
set( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE )
################################################################################
# this is more interesting later when we implement install (i.e. creating a
# bundle on macOS)in this CMakeLists!
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# the RPATH to be used when installing, but only if it's not a system directory
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")
################################################################################
# add the dynamic library
add_library( fruit SHARED ${FRUIT_SOURCES} )
set_target_properties( fruit PROPERTIES FRAMEWORK TRUE)
# remove the properties INSTALL_NAME_DIR and BUILD_WITH_INSTALL_RPATH:
#set_target_properties( fruit PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE
# INSTALL_NAME_DIR "#rpath/Frameworks" )
The code is taken from here. Also see this blog post.

Related

Executable built using cmake cannot find shared library

I have been working on a Visual Studio 2019 project with the objective of porting the application to Centos 8. I'm using a CMake project in VS2019 with remote building on my Centos machine. Basically, all the files are transferred to the remote machine and the project is built. My project directory looks as
Child
| CMakeLists.txt
| source
|__public
| headers
| libs
Parent
| CMakeLists.txt
| source
Child generates a shared library (.so) and some public headers which are to be linked in Parent. The so files and public headers are present in the public directory of Child. The CMake files of both the files are as follows
Child/CMakeLists.txt
set(PROJECT_NAME "Child")
set(Header_Files
#set of public headers and source headers
)
set(Source_Files
#set of source files
)
set(ALL_FILES
${Header_Files}
${Source_Files}
)
if (UNIX)
#Target is an SO
add_library(${PROJECT_NAME} SHARED ${ALL_FILES})
set(BOOST_INCLUDEDIR "${CMAKE_HOME_DIRECTORY}/Boost")
set(BOOST_LIBRARYDIR "${CMAKE_HOME_DIRECTORY}/Boost/libs/linux64-clang-9.0.0/static/release")
find_package(Boost REQUIRED)
if (Boost_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
endif()
set(XercesC_INCLUDE_DIR "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/include")
set(XercesC_LIBRARY "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/lib64")
find_package(XercesC REQUIRED)
if (XercesC_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${XercesC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/lib64/libxerces-c.so")
endif()
endif()
Parent/CMakeLists.txt
set(PROJECT_NAME "Parent")
set(Header_Files
#set of headers
)
set(Source_Files
#set of source files
)
set(ALL_FILES
${Header_Files}
${Source_Files}
)
if (UNIX)
set(CHILD_HEADERS "${CMAKE_HOME_DIRECTORY}/Child/public/headers")
set(CHILD_LIB_DIR "${CMAKE_BINARY_DIR}/Child/libs")
link_directories(${CHILD_LIB_DIR})
add_executable(${PROJECT_NAME} ${ALL_FILES})
target_include_directories(${PROJECT_NAME} PRIVATE ${CHILD_HEADERS})
target_link_libraries(${PROJECT_NAME} PRIVATE Child)
#Copy libChild.so to Parent executable directory
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND
cp "${CHILD_LIB_DIR}/libChild.so"
"${CMAKE_CURRENT_BINARY_DIR}/libChild.so"
)
endif()
Problem
My objective is to have a build for my customer. Hence, I need to package all the executables and libs under a single zip folder. However, upon doing so I find the linker paths to have taken absolute path values of the sort
$ldd Parent
libChild.so => /root/.vs/Project/829a6827-2641-4552-a2fb-abec91ed47a2/out/build/Linux-Clang-Release/Child/libChild.so (0x00007f6934908000)
However, concerning my final build folder will be like this
Parent (executable)
libChild.so
libboost_regex...
libxerces... etc. etc.
I kinda want a relative path link to the same directory
libChild.so => ./libChild.so
Thus, when I export as a zip to another machine, it is unable to find the shared library. I have tried a couple of things (using other CMake functions) as well as copying the library into the executable directory first and then linking. However, it still links it as an absolute path which is likely to cause the same issue again. I have gone through the CMake documentation and perused through cmake-packages and relocatable packages but unable to fix the problem.
The issue can be resolved by placing these two statements in the CMake files for Project Child and Project Parent.
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_BUILD_WITH_INSTALL_RPATH true)
Details about what these variables mean can be found in the CMake documentation.
Although this resolves the issue at the moment, however, this is not the correct approach for creating builds for a customer, as pointed out here.

Necessity of include_directories command in cmake project

I'm following a tutorial on CMake and I have problems understanding the necessity of using the 'include_directories' command at one point.
Let me explain the project first:
In my working directory I have:
- a main.cpp function, a CMakeLists.txt(the main one), a configuration file, a 'MathFunction' directory and a 'build' directory
In the MathFunction directory I have:
- a CMakeLists.txt file that will be invoked by the main one
- A file 'mysqrt.cxx' that contains the implementation of a function which will be used in 'main.cpp' application
- A 'MathFunctions.h' header file that contains the prototype of that function
In the CMakeLists from 'MathFunction' directory I'm creating a library using code from 'mysqrt.cxx' like this:
add_library(MathFunctions mysqrt.cxx)
This snippet is a part of my main CMake code:
# add the MathFunctions library?
#
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") # WHY DO WE NEED THIS
add_subdirectory (MathFunctions)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
add_executable(Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)
Now I do not understand why I need too add that 'include_directories' command in order to use the library? Shouldn't it be enough that the last command 'target_link_libraries' links the already created executable and libraries togheter so there would be no need to also include_directories?
Thank you for reading and I'm sorry if I have not explained it very well but I hope you will understand what I mean :D
Command include_directories sets directories for header files (.h) to be searched. Linking (target_link_libraries) with a library basically specifies only a library file (.so, .dll or other type). As you see, these are different things.
When linking executable with a library target, CMake propagates (more precisely, "consumes") some properties of that library target to the executable. Among these properties there is INTERFACE_INCLUDE_DIRECTORIES property, which adds include directories to the executable.
So, when a library target has INTERFACE_INCLUDE_DIRECTORIES property correctly being set, you don't need to explicitly specify include directories for executable:
MathFunctions/CMakeLists.txt:
add_library(MathFunctions mysqrt.cxx)
# Among other things, this call sets INTERFACE_INCLUDE_DIRECTORIES property.
target_include_directories(MathFunctions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CMakeLsits.txt:
add_executable(Tutorial tutorial.cxx)
# This also propagates include directories from the library to executable
target_link_libraries (Tutorial MathFunctions)
Note, that using simple
# This *doesn't* set INTERFACE_INCLUDE_DIRECTORIES property.
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
in MathFunctions/CMakeLists.txt doesn't imply propagating include directories to the linked executable.

CMake Best Practice for using Targets

I compiled all the information and now iam trying to implement CMake build system for a super project and i really need a guidance here,it would be great to transform all data i acquired by reading about CMake across different sites to practical knowledge
i have a fundamental questions regarding understating CMake Targets
In case of multi directories structure,i want to achieve most portability thus having target for each directory and then use these different targets as link for others in another directories, my goal is to be agile as possible and not be coupled with a certain directory structure, make use of CMake to figure the dependency, where i would be only concerned about targets
my final target is a library of libraries
USE CASE :
First level directory {PROJECT} ( 2 folders ) :
CMakeLists.txt common_env source
​
​First level CMakeLists.txt :
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(dassys)
# iam using this because target scope change with sub-directory
include(common/CMakeLists.txt)
include(src/CMakeLists.txt)
#Add Library
add_library(dassys INTERFACE)
#Creating library
target_link_libraries(dassys INTERFACE
common
src
)
Second Level directory {{PROJECT} /common}(2 folders 1 file ):
cfgd_*** CMakeLists.txt dstdh header.h
Second Level CMakeLists.txt
#Adding Subdirectory
include(${CMAKE_CURRENT_LIST_DIR}/dstdh/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/cfgd_***/CMakeLists.txt)
#add_subdirectory(dstdh)
#add_subdirectory(cfgd_***)
#Add Library
add_library(common INTERFACE)
#Creating library
target_link_libraries(common INTERFACE
dstdh
cfgd_***
)
----------------------------------------------------------------------------------------------------------------------------------
​Thrid Level directory { {PROJECT} /common/dstdh }(6 files ):
CMakeLists.txt dassert.h dfloat.h dstdbit.h dstdbool.h dstdint.h dstdio.h dstring.h
Thrid Level CMakeLists.txt
#Adding Library
add_library(dstdh INTERFACE )
target_sources(dstd INTERFACE
${CMAKE_CURRENT_LIST_DIR}/dassert.h
${CMAKE_CURRENT_LIST_DIR}/dfloat.h
${CMAKE_CURRENT_LIST_DIR}/dstdbit.h
${CMAKE_CURRENT_LIST_DIR}/dstdbool.h
${CMAKE_CURRENT_LIST_DIR}/dstdint.h
${CMAKE_CURRENT_LIST_DIR}/dstdio.h
${CMAKE_CURRENT_LIST_DIR}/dstring.h
)
#Add include for Header only library
target_include_directories(dstdh INTERFACE
"${CMAKE_CURRENT_LIST_DIR}/dstdh/"
)
and here is my question, i need to link against dstd library in another directory
how can this be done because as far as i understand
target_link_libraries ( mylib dstd ) should work in different directory because i have target which is dstd INTERFACE library, and i need Cmake to resolve this dependency by finding this target and link against it
i get compilation error as dstdint.h is not found when mylib is being compiled

cmake import exist SimpleAmqp library

Now my CMakeList.txt looking like this.
cmake_minimum_required(VERSION 3.6)
project(RabbitMQClient)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
include_directories(src)
include_directories(dependentFile)
add_executable(RabbitMQClient ${SOURCE_FILES})
find_library(SimpleAmqpClient SimpleAmqpClient.2.lib PATHS ./SimpleAmqpClientLib/SimpleAmqpClient.2.lib)
set(IMPORTED_IMPLIB ./SimpleAmqpClientLib)
target_link_libraries(RabbitMQClient PUBLIC SimpleAmqpClient)
when Linking the RabbitMQClient it complains.
cannot find -lSimpleAmqpClient
I want to use the SimpleAmqpClient library in the project,however not quite familiar with cmake not sure the find_library,IMPORTED_IMPLIB,PUBLIC in target_link_libraries was correctly used.Any help would be appreciate.
You have messed up with variables, targets and properties.
Proper usage of IMPORTED libraries for linking would be:
# This command sets *variable* SimpleAmqpClient_LIBRARY
find_library(SimpleAmqpClient_LIBRARY SimpleAmqpClient.2.lib
PATHS ${CMAKE_SOURCE_DIR}/SimpleAmqpClientLib # Specify a *directory*, not a library *file*
)
# Next, create an IMPORTED *target*
add_library(SimpleAmqpClient SHARED IMPORTED)
# And set IMPORTED_LIB *property* for this target
set_target_properties(SimpleAmqpClient PROPERTIES IMPORTED_LIB ${SimpleAmqpClient_LIBRARY})
# Then use library *target* for linking with
target_link_libraries(RabbitMQClient PUBLIC SimpleAmqpClient)
However, there some simplifications which could be done:
Normally, find_library is used when you don't know complete path to the library file. E.g., its directory may be different on different machines, or its prefix/extension may be different on different plaforms.
If you know complete path to the library, just use this path directly (e.g., assign it to the variable).
Normally, property IMPORTED_LOCATION is used for specify library to link with. Property IMPORTED_LIB is specific for Windows .dlls, when linking requires not a library file (.dll), but some other one (.lib).
However, CMake perfectly understands .lib file in IMPORTED_LOCATION property even for Windows .dlls, so your code need not distinguish SHARED Windows libraries from others: just use IMPORTED_LOCATION property in all cases.
Simplified version of the code:
# Create an IMPORTED library *target*
add_library(SimpleAmqpClient IMPORTED)
# Set IMPORTED_LOCATION *property* for this target
set_target_properties(SimpleAmqpClient PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/SimpleAmqpClientLib/SimpleAmqpClient.2.lib)
# Then use library *target* for linking with
target_link_libraries(RabbitMQClient PUBLIC SimpleAmqpClient)

using xib in firebreath plugin

I've created a firebreath plugin on mac os which HAVE TO pop up a window to get user input(just a text field and two buttons).
This is my current projectDef.cmake for testing.
file (GLOB XIB RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
Mac/bundle_template/input.xib
)
# Make sure we can find the 'ibtool' program. If we can NOT find it we
# skip generation of this project
find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND")
message(SEND_ERROR "ibtool can not be found and is needed to compile the .xib files. It should have been installed with the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin")
endif()
# make the compiled nib file to desktop for testing
set (NIBFILE /Users/develop/Desktop/input.nib)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text --compile ${NIBFILE} ${XIB}
COMMENT "Compiling input.xib")
set (SOURCES
${SOURCES}
${PLATFORM}
${XIB}
)
the add_custom_command block takes no effect from cmake, no nib file compiled when my plugin target build successfully, but ibtool works from command line in terminal.
Looks like what you need to do is compile the .xib file to a .nib file. There is an example of how to do that here:
http://www.cmake.org/Wiki/CMake:OSX_InterfaceBuilderFiles
basically you'll do something similar to this:
# Make sure we can find the 'ibtool' program. If we can NOT find it we
# skip generation of this project
find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND")
message(SEND_ERROR "ibtool can not be found and is needed to compile the .xib files. It should have been installed with the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin")
endif()
set (NIBFILE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/input.nib)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text
--compile ${NIBFILE} ${XIB}
COMMENT "Compiling input.xib")
set (SOURCES
${SOURCES}
${PLATFORM}
${XIB}
${NIBFILE}
)
set_source_files_properties(${NIBFILE}
PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources/English.lproj"
GENERATED 1
)
You need to set the location for the NIB file, but remember that you also need to set it to GENERATED because it won't be there when the prep script is run for the first time.
Problem solved. See this link. That method works. My final solution is as follows:
//projectDef.cmake
set(XIB "Mac/bundle_template/input.xib")
add_mac_plugin(${PROJECT_NAME} ${PLIST} ${STRINGS} ${LOCALIZED} SOURCES ${XIB})
//Mac.cmake in "add_mac_plugin" macro
if (${ARGC} GREATER 5)
add_library( ${PROJECT_NAME} MODULE
${SOURCES}
${ARGN}
)
else()
add_library( ${PROJECT_NAME} MODULE
${SOURCES}
)
endif()
if (${ARGC} GREATER 5)
set_target_properties(${PROJECT_NAME} PROPERTIES
BUNDLE 1
BUNDLE_EXTENSION plugin
XCODE_ATTRIBUTE_WRAPPER_EXTENSION plugin #sets the extension to .plugin
XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
RESOURCE ${ARGN}
LINK_FLAGS "-Wl,- exported_symbols_list,${FB_ESC_ROOT_DIR}/gen_templates/ExportList_plugin.txt")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES
BUNDLE 1
BUNDLE_EXTENSION plugin
XCODE_ATTRIBUTE_WRAPPER_EXTENSION plugin #sets the extension to .plugin
XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
LINK_FLAGS "-Wl,-exported_symbols_list,${FB_ESC_ROOT_DIR}/gen_templates/ExportList_plugin.txt")
endif()
My modification seems not so beautiful, I don't understand cmake very well. hi taxilian, can you update the macro to support external resources like xib? By the way, thanks a lot, man.

Resources