Cmake cannot find library using “link_directories”

2019-01-03 15:22发布

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?

4条回答
地球回转人心会变
2楼-- · 2019-01-03 15:50

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} )
查看更多
【Aperson】
3楼-- · 2019-01-03 15:51

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 manpage 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 manpage to track down why it doesn't find your library as intended.

查看更多
倾城 Initia
4楼-- · 2019-01-03 16:05

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.

查看更多
祖国的老花朵
5楼-- · 2019-01-03 16:05

Here is an extract from the documentation:

link_directories(directory1 directory2 ...): Specify the paths in which the linker should search for libraries. The command will apply only to targets created after it is called. Relative paths given to this command are interpreted as relative to the current source directory, see CMP0015.

the command

add_executable(test main.cpp)

creates a target names test. Also you musst put link_directories command above the add_executable.

查看更多
登录 后发表回答