set cmake output executable directory - cmake

I want to set the output executable using cmake. I've achieved this by using these:
SET( EXECUTABLE_OUTPUT_PATH ${dir}/bin )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin )
But the problem is now everything is set inside /bin including the binaries of all the libraries used in the project. I only want the executable created by my project to be inside /bin. How can I achieve this?

The cmake variable you set is just used to initialize the RUNTIME_OUTPUT_DIRECTORY property of the target, unless it's this property is specified. This target property is what's actually determining the directory the binary for the will be created in. You can simply set this property for the target:
set_target_properties(my_target PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
Instead of setting CMAKE_RUNTIME_OUTPUT_DIRECTORY.

Related

CMake: embedding path to imported shared library in executable

I have an external library. That I am bringing into a CMake build using an imported library target. The build is baking in relative path to the shared library with respect to the CMAKE_BINARY_DIR.
I have something like this:
add_library(libstring UNKNOWN IMPORTED)
set_target_properties(libstring PROPERTIES
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/external/libstring.so"
)
add_executable(my_exe "${CMAKE_CURRENT_BINARY_DIR}/my_exe.cpp")
target_link_libraries(my_exe PRIVATE libstring)
Then ldd my_exe returns
external/libstring.so => not found
If instead of linking to the imported target I link directly to the library giving the absolute file path it works fine.
target_link_libraries(my_exe PRIVATE "${CMAKE_BINARY_DIR}/external/libstring.so")
Then ldd returns
libstring.so => /<bin-dir>/external/libstring.so (0x00007fce27537000)
In both cases rpath is set to /<bin-dir>/external.
When linking to an imported target how to make CMake bake in just the name of the library in the executable?
Note, that when the imported library path is outside of the binary tree, then the absolute path is baked in the executable.
It turned out that it is not CMake causing this problem, but this particular library.
With Unix Makefiles, CMake passes to the linker relative paths with respect to the CMAKE_CURRENT_BINARY_DIR.
../external/libstring.so
Or with Ninja it passes relative to CMAKE_BINARY_DIR.
external/libstring.so
The linker then bakes-in this whole relative path. Not the name of the library only.
Other libs are not affected even when passed to the linker like that. I don't know what is different with this library.
The solution is to set IMPORTED_NO_SONAME property for the library:
set_property(TARGET libstring PROPERTY IMPORTED_NO_SONAME TRUE)
Documentation for this property says:
Set this property to true for an imported shared library file that has
no soname field. CMake may adjust generated link commands for some
platforms to prevent the linker from using the path to the library in
place of its missing soname.

Have cmake append a directory to the build RPATH

I'd like to add another directory to a target's BUILD_RPATH property, but I'd like it at the end of the list, so it's searched last, after the other directories that cmake automatically adds to target's BUILD_RPATH. But there doesn't seem to be way to add to the property after the automatic RPATH directories.
At build time, my system libraries are not in the normal locations, but in a staging area. In order to run uninstalled built binaries, I need to add this staging area to the binaries' RPATHs. And this part is straightforward to do and works fine, like this:
add_executable(mybinary ${BINARY_SOURCES})
set_property(TARGET mybinary APPEND PROPERTY BUILD_RPATH ${STAGING_LIB_DIR})
But mybinary also uses a library that it built as part of the same project:
add_library(mylib SHARED ${LIB_SOURCES})
target_link_libraries(mybinary PRIVATE mylib)
When mybinary is run, I'd like it to use the mylib that was just built and is in ${CMAKE_CURRENT_BINARY_DIR}, not another copy somewhere else, perhaps in the system library directory from the last time make install was run to install the project. Or, in my case, a copy of the library in ${STAGING_LIB_DIR}.
cmake will automatically add ${CMAKE_CURRENT_BINARY_DIR}, or whatever is appropriate, for any libraries not from the system to the build RPATH of produced binaries. So when one runs mybinary from the build directory it will search for the mylib in the build directory.
But the problem is it appends these automatic library directories to whatever I have set BUILD_RPATH to. So one gets a final RPATH of ${STAGING_LIB_DIR}:${CMAKE_CURRENT_BINARY_DIR} and the wrong copy of mylib is used.
You could set the SKIP_BUILD_RPATH target property:
SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic generation of an rpath allowing the target to run from the build tree. This property is initialized by the value of the variable CMAKE_SKIP_BUILD_RPATH if it is set when a target is created.
And then manually set the RPATH in whatever way/order you would like without worrying about CMake doing additional things to it.

Are there other means of obtaining the properties of a target in cmake?

I have created a C++ static library, and in order to make it searchable easily, I create the following cmake files:
lib.cmake
# The installation prefix configured by this project.
set(_IMPORT_PREFIX "C:/------/install/win32")
# Create imported target boost
add_library(lib STATIC IMPORTED)
set_target_properties(lib PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "lib_define1;lib_define2"
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/../include"
)
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/lib-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
lib-debug.cmake
# Import target "boost" for configuration "Debug"
set_property(TARGET lib APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(boost PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/Debug/staticlib/lib.lib"
)
When I want to use this library in an executable, I can simply invoke it by calling find_package command:
find_package(lib REQUIRED)
if(lib_FOUND)
message("lib has been found")
else()
message("lib cannot be found")
endif(boost_FOUND)
It works and if I want to know the head file directory of the library, I will have to call it this way:
get_target_property(lib_dir lib INTERFACE_INCLUDE_DIRECTORIES)
I was just wondering whether there are other ways of obtaining the properties of an target. In this case I expect some variable like lib_INCLUDE_DIRECTORIES will exist.
No, CMake does not automatically define variables for the properties of a target (or of anything else). If you need the value of a property, you have to query it explicitly (using get_property or the specific getters like get_target_property etc.).
In your specific case, INTERFACE_INCLUDE_DIRECTORIES is a property which I would expect you would not need to query at all. The whole point of INTERFACE_* properties is to propagate usage requirements automatically; their propagation is implemented in CMake itself.

How to get debug postfix in executable name

I am using cmake 2.8.12.2. I have set CMAKE_DEBUG_POSTFIX, and it is automatically used with the add_library command. But it is not automatically used with add_executable command. I have discovered that I can set the DEBUG_POSTFIX target property to get a debug postfix into the executable name, but this requires using an additional command.
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
Is the second command explicitly setting the DEBUG_POSTFIX target property required or is there an easier way?
The current cmake documentation for set_target_properties states
There is also a <CONFIG>_OUTPUT_NAME that can set the output name on a per-configuration basis. <CONFIG>_POSTFIX sets a postfix for the real name of the target when it is built under the configuration named by (in upper-case, such as “DEBUG_POSTFIX”). The value of this property is initialized when the target is created to the value of the variable CMAKE_<CONFIG>_POSTFIX (except for executable targets because earlier CMake versions which did not use this variable for executables).
So it seems to highlight the fact that cmake does not use the value of CMAKE_DEBUG_POSTFIX in the name of executables. Therefore
add_executable(myexe ${SOURCE_FILES})
set_target_properties(myexe PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
will use the value of the global variable ${CMAKE_DEBUG_POSTFIX} when building the myexe target for the DEBUG configuration.
Note that one of the commenters to this question was confused by the use of the variable ${PROJECT_NAME}. This variable is automatically set to myexe when using project(myexe). Using ${PROJECT_NAME} is equivalent to myexe and it makes it easier to copy/paste to new CMakeLists.txt.
Just to mention that, if you have in your project many sub-executables, it is worth having a look on CMAKE_EXECUTABLE_SUFFIX. The variable in this case would need to be changed when running CMake for a specific build (Release/Debug), but this suffix is auto-attached to every ADD_EXECUTABLE(...)-call executable name. Tested and verified with CMake 2.8.12.2 and 3.0.2

Retrieve target properties from cmake build

Suppose I have an existing project and it's cmake-configured build directory. How can I retreive some target's properties using this build, provided that I know the target name? I tried creating a separate script like this
get_target_property(VAR target property)
but it fails with error
Command get_target_property() is not scriptable
Are there any other methods?
Apparently get_target_property() can be called only when configuring a build directory with cmake. I am not aware of any method of getting targets properties on already configured build directory. But if modifying existing CMakeFiles.txt is an option, there is a workaround.
You can try locating target definition, get the target's properties there and dump them into a text file. Then, this file can be then used in any other scripts called after build directory configuration is done.
This example illustrates this workaround:
add_executable(app ${app_sources})
set_target_properties(app PROPERTIES COMPILE_DEFINITIONS SOME_DEF=1)
get_target_property(compile_defs app COMPILE_DEFINITIONS)
file(WRITE app_compile_defs.txt ${compile_defs})
Be sure to use get_target_property after every property changes for given target in CMakeFiles.txt are done. Otherwise you can miss something as in example below.
add_executable(app ${app_sources})
set_target_properties(app PROPERTIES COMPILE_DEFINITIONS SOME_DEF=1)
get_target_property(compile_defs app COMPILE_DEFINITIONS)
file(WRITE app_compile_defs.txt ${compile_defs})
set_target_properties(app PROPERTIES COMPILE_DEFINITIONS ANOTHER_DEF=0)
In the example above, the ANOTHER_DEF=0 definition will not be listed in app_compile_defs.txt.