CMAKE library not linking - c++

Why this code does not produce anything?
link_directories(${CMAKE_SOURCE_DIR}/libs/mylib1)
message("DIR: ${LINK_DIRECTORIES}")
I have problem on Windows that though I do link_directories() there is NO -L... flag when linking. I do create target after link_directories command as documentation suggests.

By using "link_directories(${CMAKE_SOURCE_DIR}/libs/mylib1)" you are telling CMake to tell the linker to look for libraries in "${CMAKE_SOURCE_DIR}/libs/mylib1" when it needs to link against a library with a plain name, as in "png" or "zlib".
Using link_directories is not even recommended anymore, however. We always recommend to use target_link_libraries with the full path name to the library files that you want to link to. Then CMake takes care of arranging all the -L and -l arguments to the linker on all the different platforms for you.
Please add more information to your question if you would like more help. It's a bit unclear what you are trying to do, or what you are expecting.

Because LINK_DIRECTORIES is not variable, but a directory property. You can obtain it in such way:
get_directory_property(OUT_VAR LINK_DIRECTORIES)
message(STATUS "DIR: ${OUT_VAR}")
See documentation.

I'm not sure what you are trying to achieve overall.
Would target_link_libraries do a better overall job?
target_link_libraries( TARGET LIB1 LIB2 LIB3 ... )

Related

How to configure DBus dependencies with CMake

I am new to CMake and DBus. I am following along the guide here and make a basic program compile and execute.
The first problem that I ran into was my program will not find
<dbus/dbus.h>
I got around that issue by adding some include directories to my CMakeList.txt.
Currently, my CMakeLists.txt looks like this:
...
include_directories(/usr/lib/)
include_directories(/usr/include/dbus-1.0/)
include_directories(/usr/lib/x86_64-linux-gnu/dbus-1.0/include)
include_directories(/usr/include/glib-2.0)
include_directories(/usr/lib/x86_64-linux-gnu/glib-2.0/include/)
set (LIBS
dbus-1
dbus-glib-1
)
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${LIBS} )
Now, my program is complaining about not being able to find dbus-arch-deps.h
/usr/include/dbus-1.0/dbus/dbus.h:29:33: fatal error: dbus/dbus-arch-deps.h: No such file or directory
#include <dbus/dbus-arch-deps.h>
I know that the solution for this is to use proper command line flags or pkg-config. As discussed here and numerous other posts.
However, I do not know how to configure CMakeLists.txt to have similar effect.
My guess would be to add something like find_package(dbus-1) to CMakeLists.txt. And if that is correct, I am going to have to write my own Finddbus-1.cmake. Does this sound correct? Or is there an easier way?
I will appreciate any pointers.
You may get an existing FindDBus.cmake script (e.g., this one), copy it into your project, and use as
find_package(DBus REQUIRED)
# Use results of find_package() call.
include_directories(${DBUS_INCLUDE_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
Alternatively, as you know pkgconfig can find DBus, you may use CMake module PkgConfig. Actually, FindDBus.cmake script, referenced above, uses PkgConfig module in its implementation. Possible usage could be:
find_package(PkgConfig REQUIRED) # Include functions provided by PkgConfig module.
pkg_check_modules(DBUS REQUIRED dbus-1) # This calls pkgconfig with appropriate arguments
# Use results of pkg_check_modules() call.
include_directories(${DBUS_INCLUDE_DIRS})
link_directories(${DBUS_LIBRARY_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
However, using link_directories is not recommended, it is better to use absolute paths to libraries in target_link_libraries() call. That is why it is better to combine pkg_check_modules with find_library, as it is done in the referenced Find script. That answer describes generic way for use result of pkgconfig in CMake.

Link External Library when using CMakeLists used by CLion

I have build libmemcached.a and copied it to /usr/local/lib on my mac and I have tried all the following options to link libmemcached.a and yet get compile time errors that libmemcached/memcached.h is not found.
link_libraries (${libmemcached})
include_directories(SYSTEM ${libmemcached})
link_directories("/usr/local/lib")
find_package(libmemcached.a REQUIRED)
link_libraries`enter code here`(libmemcached.a)
find_library(RESULT libmemcached.a PATHS /usr/local/lib)
target_link_libraries(dnsa_pcl libmemcached.a)
It is a simple -L -l using MakeFile. Not sure what needs to be done to make this work using CMakeLists. Any help is much appreciated.
you should use so called imported library, like it's described in the official documentation
The solution that worked for me is a bit weird. I had to both set the CMAKE_PREFIX_PATH to the directory that has the lib and also have include_directories() with the include folder of the source. For some reason, I was under the impression that the libmemcached.a had the header files as well.

Cmake cannot find library using "link_directories"

I Ubuntu, I am learning about cmake and make, and just trying a simple example. I have two directories: src and build. In src, I have two files: main.cpp, and CMakeLists.txt, which has (only) the following text:
add_executable(test main.cpp)
link_directories(/usr/lib/x86_64-linux-gnu)
target_link_libraries(test protobuf)
In /usr/lib/x86_64-linux-gnu, there is a shared library called libprotobuf.so, which I want to link against. My main.cpp uses functions in this library, by including the releveant header file, #include <google/protobuf/message.h>.
Now, in my build directory, I run cmake ../src, and then make. However, I then get linker errors telling me that there are undefined references to some of the functions in the protobuf library. If I do a search through all the files and subdirectories in build, there is not mention of anything related to protobuf.
However, if I remove the link_directories line in my CMakeLists.txt file, and instead write the full path to the library when specifying the executable, i.e. target_link_libraries(test /usr/lib/x86_64-linux-gnu/libprotobuf.so), it compiles and links fine.
Why is link_directories not allowing cmake to find this library?
Do not use link_directories like this in CMake.
This is a common beginner's mistake, as many other build environments work like this, but in CMake it's just asking for trouble. Even the official documentation specifically advises against it:
Note that this command [link_directories] is rarely necessary. Library locations returned
by find_package() and find_library() are absolute paths. Pass these
absolute library file paths directly to the target_link_libraries()
command. CMake will ensure the linker finds them.
So instead, always pass absolute paths to target_link_libraries and use find_library to resolve the link directory:
find_library(PROTOBUF_LIBRARY protobuf HINTS /usr/lib/x86_64-linux-gnu)
target_link_libraries(test PUBLIC ${PROTOBUF_LIBRARY})
This has the huge benefit that you will probably get a diagnostic at CMake configure time if the expected library cannot be found, instead of a random linker error at compile time. Also, this allows the user to specify a library location via the GUI if the target machine has a non-standard directory layout.
So if it doesn't work right away, be sure to check the result of the find_library call and consult the official documentation to track down why it doesn't find your library as intended.
Make sure that your call to link_directories takes place before your call to the relevant add_executable.
I had mistakenly believed it only needed to be before the call to target_link_libraries, but that's not the case. After moving the call, the library is linked properly.
Make sure that the order will be link_directories, set PROJECT_LINK_LIBS, add_executable and then target_link_libraries.
Below is example to demonstarte it:
cmake_minimum_required(VERSION 2.8.9)
project (Logging)
include_directories(include)
file(GLOB LOGGINGSOURCES "libsrc/*.cpp")
file(GLOB SOURCES "src/*.cpp")
add_library(convertString SHARED ${LOGGINGSOURCES})
install(TARGETS convertString DESTINATION /root/Deepak/)
link_directories( /root/Deepak/ )
set(PROJECT_LINK_LIBS libconvertString.so)
add_executable(hello ${SOURCES})
target_link_libraries(hello ${PROJECT_LINK_LIBS} )
Perhaps it's very old topic but none of proposed solutions worked for me. So I had to make my own dirty hack. I do crosscompiling with buildroot and include toolchainfile.cmake.
#...
set(LIB_PATH ${PROJECT_SOURCE_DIR}/relative/path/to/your/lib)
#...
include_directories(/path/to/library/include)
set(LIB_MYLIB ${LIB_PATH}/libmylib.so)
#...
add_executable(${PROJECT_NAME} ${APP_SOURCES})
target_link_libraries(${PROJECT_NAME}
${LIB_MYLIB}
)
Hope this will help

CMake: include library dependencies in a static library

I am building a static library in CMake, which is dependent on many other static libraries. I would like them all to be included in the output .lib/.a file, so I can just ship a big lib file to customers. In Visual Studio 2010 there is an option, "Link Library Dependencies", which does exactly this.
But I can't find how to do it in CMake. Can you set this flag via CMake, or get the same result some other way? I have tried target_link_libraries(...) and also add_dependencies(...), but CMake seems to simply ignore this line for static libraries.
Okay, so I have a solution. First it's important to recognize that static libraries do not link other static libraries into the code. A combined library must be created, which on Linux can be done with ar. See Linking static libraries to other static libraries for more info there.
Consider two source files:
test1.c:
int hi()
{
return 0;
}
test2.c:
int bye()
{
return 1;
}
The CMakeLists.txt file is to create two libraries and then create a combined library looks like:
project(test)
add_library(lib1 STATIC test1.c)
add_library(lib2 STATIC test2.c)
add_custom_target(combined ALL
COMMAND ${CMAKE_AR} rc libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)
The options to the ar command are platform-dependent in this case, although the CMAKE_AR variable is platform-independent. I will poke around to see if there is a more general way to do this, but this approach will work on systems that use ar.
Based on How do I set the options for CMAKE_AR?, it looks like the better way to do this would be:
add_custom_target(combined ALL
COMMAND ${CMAKE_CXX_ARCHIVE_CREATE} libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)
This should be platform-independent, because this is the command structure used to create archives internally by CMake. Provided of course the only options you want to pass to your archive command are rc as these are hardwired into CMake for the ar command.
I'd like to enhance the other solutions by providing my CMakeLists.txt file that actually works also in terms of building dependencies.
Solution misusing CMake
cmake_minimum_required(VERSION 2.8)
add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)
target_link_libraries(mainexec combinedLib) # Important to place before add_custom_target
set(LIBNAME "combinedLib.lib")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
add_custom_target(combinedLib
DEPENDS ${LIBNAME}
)
Note that this solution works so far with Visual Studio but I guess it can be made multi-platform compliant. I can imagine that the following version might work for Unix-based platforms:
set(LIBNAME "libCombinedLib.a")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND ar -rcT ${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
Note that these solutions somehow misuse CMake as it would complain about a target of type UTILITY (instead of STATIC or SHARED) if you place the target_link_libraries call after the add_custom_target declaration.
CMake target-declaration-compliant solution
To make it CMake compliant, you can replace the `target_link_libraries' call by
target_link_libraries(mainexec ${LIBNAME})
add_dependencies(mainexec combinedLib)
In my case it is not entirely satisfactory because mainexec has to know about combinedLib although it expects all dependencies to be handled by the target_link_libraries call.
Alternative solution with less coupling
Looking a bit further towards imported targets I eventually found a solution that solves my last problem:
cmake_minimum_required(VERSION 2.8)
add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)
set(LIBNAME "combinedLib.lib")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
add_custom_target(combinedLibGenerator
DEPENDS ${LIBNAME}
)
add_library(combinedLib STATIC IMPORTED)
set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME})
add_dependencies(combinedLib combinedLibGenerator)
target_link_libraries(mainexec combinedLib)
If you intend to modularize the whole add GLOBAL after STATIC IMPORTED to make the imported target globally visible.
Portable CMake solution
With the current CMake versions CMake provides full support for transitive dependencies and interface libraries. An interface library can then "link" against other libraries and this interface library can, in turn, be "linked" against. Why quotation marks? While this works good, this actually doesn't create a physical, combined library but rather creates a kind of an alias to the set of "sub-libs". Still this was the solution we eventually needed, which is why I wanted to add it here.
add_library(combinedLib INTERFACE)
target_link_libraries(combinedLib INTERFACE lib1 lib2)
target_link_libraries(mainexec combinedLib)
That's it!

CMake is linking againts library's full path

Okay I have a project in CMake structured like this:
CMakeLists.txt
/libfoo/CMakeLists.txt
/frontend/qt/CMakeLists.txt
libfoo is a library I'm writing and frontend/qt is a small frontend and also an example of usage. The problem is that CMake passes the relative path to libfoo.so.x to the linker instead of an -l option. The Qt gui target is declared like this:
add_executable(qtgui ${qtgui_sources} ${qtgui_moced} ${qtgui_ui_h})
target_link_libraries(qtgui ${QT_LIBRARIES} foo)
I'd rather it just linked againts -lfoo like all other libs, not the full path.
How to do that?
Thank you!
Ah, never mind, found it:
http://www.cmake.org/Wiki/CMake_RPATH_handling
I obviously didn't google enough, sorry.