hankyuan
hankyuan

Reputation: 41

How to link library correctly in cmake?

I'm using yaml-cpp library recently. I follow the config file in "yaml-cpp-config.cmake.in" which content is

# - Config file for the yaml-cpp package
# It defines the following variables
#  YAML_CPP_INCLUDE_DIR - include directory
#  YAML_CPP_LIBRARIES    - libraries to link against

# Compute paths
get_filename_component(YAML_CPP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(YAML_CPP_INCLUDE_DIR "@CONFIG_INCLUDE_DIRS@")

# Our library dependencies (contains definitions for IMPORTED targets)
include("${YAML_CPP_CMAKE_DIR}/yaml-cpp-targets.cmake")
 
# These are IMPORTED targets created by yaml-cpp-targets.cmake
set(YAML_CPP_LIBRARIES "@EXPORT_TARGETS@")

According line 8 and line 14 (or the comment section), I edited my CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(yaml_test)
find_package(yaml-cpp)
include_directories(${YAML_CPP_INCLUDE_DIRS})

add_executable(yaml_test src/test.cpp)
target_link_libraries(yaml_test ${YAML_CPP_LIBRARIES})

and test.cpp:

#include <yaml-cpp/yaml.h>

int main()
{ 
  YAML::Node node = YAML::LoadFile("test.yaml");

  return 0;
}

and I got

CMakeFiles/yaml_test.dir/src/test.cpp.o: In function `main':
test.cpp:(.text+0xf9): undefined reference to `YAML::LoadFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status
CMakeFiles/yaml_test.dir/build.make:94: recipe for target 'yaml_test' failed
make[2]: *** [yaml_test] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/yaml_test.dir/all' failed
make[1]: *** [CMakeFiles/yaml_test.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

I found a solution from undefined reference to YAML::LoadFile

changed my CMakeLists.txt to

cmake_minimum_required(VERSION 3.5)
project(yaml_test)
find_package(yaml-cpp)
include_directories(${YAMLCPP_INCLUDE_DIRS})

add_executable(yaml_test src/test.cpp)
target_link_libraries(yaml_test ${YAMLCPP_LIBRARIES})

And I can build my code succesfully.

My question is how can I tell the right include_directories and target_link_libraries straight from yaml-cpp package's CMakeLists.txt or config file?

Upvotes: 3

Views: 3737

Answers (2)

Mohamed Ishad
Mohamed Ishad

Reputation: 155

Instead of installing yaml-cpp locally and then including and linking it, you can do it directly with cmake as follows.

include(FetchContent)

FetchContent_Declare(yaml-cpp
  GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
  GIT_TAG yaml-cpp-0.7.0)  #tag of a release

FetchContent_GetProperties(yaml-cpp)

if(NOT yaml-cpp_POPULATED)
  message(STATUS "Fetching yaml-cpp...")
  FetchContent_Populate(yaml-cpp)
  add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR})
endif()

target_link_libraries(<YOUR_LIBRARY/EXECUTABLE> PUBLIC yaml-cpp::yaml-cpp) # The library or executable that require yaml-cpp library

Answer is from: https://github.com/jbeder/yaml-cpp/pull/1143/files

PS:
Even though this not answer following question

My question is how can I tell the right include_directories and target_link_libraries straight from yaml-cpp package's CMakeLists.txt or config file?

This answers the main question of linking yaml-cpp with a project.

Upvotes: 0

Tsyvarev
Tsyvarev

Reputation: 65938

My question is how can I tell the right "include_directories" and "target_link_libraries" straight from yaml-cpp package's CMakeLists.txt or config file?

Just make sure you look into the config file, which is actually used by CMake. E.g. yaml-cpp-config.cmake.in is just a template for future yaml-cpp-config.cmake, but your system could have other config files for the same package.

CMake stores the exact path to the config file in the <PackageName>_CONFIG variable so you may print value of this variable if unsure:

...
find_package(yaml-cpp)
message(STATUS "Used config file: ${yaml-cpp_CONFIG}")

Important note

When read a config file, aside from the documentation at the top it is useful for check the set line which assigns a value to the documented variable like *_LIBRARY or *_LIBRARIES. If that value is empty, then the "config" file is probably broken and documented variables most likely cannot be used. But you may resort to the using of IMPORTED targets, see below.

Note, that most "config" files provide IMPORTED target(s) for use by other code.

This mechanism is preferred over using variables *_INCLUDE_DIR and *_LIBRARIES. If cannot find the documentation about which exact IMPORTED target to use, then see into the value of *_LIBRARIES variable in the config file: The variable may contain a list of IMPORTED targets, which you could try to use in your code via target_link_libraries.

For more details look into find_package documentation.

Upvotes: 2

Related Questions