CMake add fmt library
Asked Answered
Z

1

8

I have a CMake project, with following structure:

cmake_minimum_required(VERSION 3.11)
project(ReadGraph)

# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
  RESULT_VARIABLE result
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
  message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
  RESULT_VARIABLE result
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
  message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()

# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
                 ${CMAKE_CURRENT_BINARY_DIR}/googletest-build
                 EXCLUDE_FROM_ALL)

SET(CMAKE_CXX_FLAGS "-std=c++20 -pthread -O3")
include_directories(include)

enable_testing()
file(GLOB TESTS "test/*.cpp" "test/*/*.cpp" "src/*.cpp" "src/*/*.cpp")
add_executable(Tests ${TESTS})
target_link_libraries(Tests gtest_main)

And this CMakeLists.txt.in file:

cmake_minimum_required(VERSION 3.11)

project(googletest-download NONE)

include(ExternalProject)
ExternalProject_Add(googletest
  GIT_REPOSITORY    https://github.com/google/googletest.git
  GIT_TAG           master
  SOURCE_DIR        "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
  BINARY_DIR        "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
  CONFIGURE_COMMAND ""
  BUILD_COMMAND     ""
  INSTALL_COMMAND   ""
  TEST_COMMAND      ""
)

Most of this I copy-pasted from GoogleTest instructions.

Usage of Gtests works perfectly for me.

I figured that I want to use FMT Library in my project.

I tried some approaches (such as direct copy of approach from gtest) to include FMT into my project, but failed.

I want CMake to download this library and embed it into my project, so I can use FMT as follow:

#include <fmt/core.h>

Currently I am receiving following error massage:

fatal error: fmt/core.h: No such file or directory
   10 | #include <fmt/core.h>
      |          ^~~~~~~~~~~~
compilation terminated.
Zara answered 8/3, 2021 at 14:1 Comment(2)
Can you use CMake 3.11 or newer? That would make everything much easier.Fug
It made no difference from my point of view, but I upgraded it as you wished.Zara
F
22

CMake 3.11 introduced the FetchContent module for exactly this purpose: To download 3rdparty dependencies at configuration time and to build them as part of the project itself. So in order to use both GTest and FMT you can use

# While FetchContent only requires CMake 3.11, selecting C++20 through
# CMAKE_CXX_STANDARD requires 3.12 and the convenience function
# `FetchContent_MakeAvailable` was introduced in CMake 3.14
cmake_minimum_required(VERSION 3.14) 
project(ReadGraph)

include(FetchContent)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

FetchContent_Declare(googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG main
)
FetchContent_MakeAvailable(googletest)

FetchContent_Declare(fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
  GIT_TAG master
)
FetchContent_MakeAvailable(fmt)

find_package(Threads REQUIRED) # for pthread

include_directories(include)

enable_testing()
file(GLOB TESTS "test/*.cpp" "test/*/*.cpp" "src/*.cpp" "src/*/*.cpp")
add_executable(Tests ${TESTS})
target_link_libraries(Tests 
  PRIVATE 
    gtest_main 
    fmt::fmt 
    Threads::Threads
)

I've also taken the liberty to use the Threads CMake module for threading support and to set the C++ standard through CMake, that way this project works on both Windows and Linux as is (unless of course you use Linux-specific headers in your implementation).

Fug answered 8/3, 2021 at 14:45 Comment(3)
Thank you a lot. This works! Moreover it simplified a CMake a lot, so it is so much nicer to work with.Zara
When should I link libraries with namespace::library_name? Could you briefly explains how you know the google_test library is called gtest_main?Balbinder
@YongKinChong: You need to use the names the dependency uses internally. For example, googletest mentions that you should use gtest_main in their README.md file at github.com/google/googletest/blob/main/googletest/README.md. If a library doesn't mention it explicitly you need to look it up in their CMakeLists.txt files. Ideally, each library provides a namespaced alias for their internal target, just like fmt does, because that way typos are spotted at configuration time instead of the linker complaining it can't find a library once everything has been built.Fug

© 2022 - 2024 — McMap. All rights reserved.