Friday, September 2, 2022

[SOLVED] In cmake, how to add dependency for can-utils using FetchContent?

Issue

I am still learning cmake and am struggling with a dependency I am trying to set up.

I discovered FetchContent while setting up googletest, and that worked fine so I am trying to do the same thing for a new dependency I am trying to configure for can-utils.

In the CMakeLists.txt file in the source directory for the code that I want to use can-utils with, I added:

include(FetchContent)
FetchContent_Declare(
  can-utils
  GIT_REPOSITORY https://github.com/linux-can/can-utils.git
  GIT_TAG        e602e391a56e681b03506c2f0890eb128192ec3d
)
FetchContent_MakeAvailable(can-utils)

The project configures and builds,and I can see that cmake put the can-utils repo in to my build directory... However, unlike with googletest, where after doing the FetchContent I was able to #include <gtest/gtest.h>, I can't seem to #include "anything/resembling/can-utils"

I suspect that the difference is that googletest is set up with FetchContent in mind and can-utils is not. My question is: How would I know if I can use FetchContent for a given library?

Any guidance is very much appreciated!


Solution

FetchContent eventually calls add_subdirectory on the fetched content. The location of the downloaded contents is written to a variable named <lowercaseName>_SOURCE_DIR, which IIRC is by default under a binary dir.

Looking at can-utils/CMakeLists.txt, it does the following at what is currently line 22:

include_directories (.)
include_directories (./include)

include_directories is not attached to any target. See its docs:

The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file. The target property values are the ones used by the generators.

Since (IIRC,) the default value of ${can-utils_SOURCE_DIR} will be under some binary dir of your generated buildsystem, unless some crazy coincidence happens with an in-source build, your targets are probably not going to inherit those include_directories values.

As a bandaid-solution, you should be able to do something like:

# this must go after the call to FetchContent_MakeAvailable and before your targets are created and in a same-or-parent directory of the directories of the CMakeLists.txt files creating your targets.
include_directories("${can-utils_SOURCE_DIR}/..")

Which should then allow you do include the headers like:

#include <value_of_can-utils_SOURCE_DIR/lib.h>

And if you don't like whatever ${can-utils_SOURCE_DIR} is, I think you could do some symlinking to work around it.

A better bandaid-solution would be to use target_include_directories to add it per-target of can-utils like they preferably should have done.

If you want, you can raise an issue/PR to the maintainer of the project to switch from include_directories to use target_include_directories, which should be okay especially since they're using cmake_minimum_required(VERSION 3.3)

You could also ask/PR them to place their header files under a subdirectory named can-utils inside their repo so that you don't have do either deal with the value of ${can-utils_SOURCE_DIR} or do symlink workarounds.



Answered By - David Fong
Answer Checked By - Timothy Miller (WPSolving Admin)