feature request: list all (namespaced / imported / aliased) targets added by FetchContent

problem:
when adding a new library (with FetchContent_Declare & MakeAvailable) I have no idea what targets are available. I can google / stackoverflow and hope someone has documented, but it’s not a good experience. I can also spelunk in the lib-config.cmake file. Or I can guess and hope the targets are sensibly named. cmake docs recommend “Check the documentation for the package or Find module to see what imported targets it defines, if any.” which doesn’t seem good enough to me!

solution:
there should be a way to list the (namespaced) targets added by a FetchContent_Declare & MakeAvailable.

(bad) workarounds:

  1. use a recursive subdirectory function, and print all BUILDSYSTEM_TARGETS. problems: this only prints e.g. boost_algorithm, etc not Boost::Algorithm (namespaced targets are the preferred way to include “If the dependency provides namespaced targets of the form SomePrefix::ThingName, the project should link to those rather than to any non-namespaced targets.”)
graph=$(mktemp)
cmake --graphviz=$graph builddir
rg --only-matching --no-line-number "\w*::\w*" $graph | sort -u

this will print out all namespaced targets, but it is clearly not a good solution. however it does indicate that cmake internally has this information, but just doesn’t expose it neatly.

1 Like

an extension to this feature request would implement something like cmake add-dependency https://github.com/jeremy-rifkin/libassert, which would be a nicer experience than current, and comparable to cargo add among others.

I’m currently doing this with a (bad, flaky) bash script:

#!/bin/sh

set -eu

repo="$1/$2"
repo_org="$1"
repo_name="$2"

tag=$(
    curl --silent -m 10 --connect-timeout 5 "https://api.github.com/repos/$repo/releases/latest" |
    jq -r ".tag_name"
)

if (rg "FetchContent_MakeAvailable\($repo_name\)"); then
    echo "dependency $repo already found in CMakeLists.txt"
else
    template=$(mktemp)

    echo "FetchContent_Declare(
    $repo_name
    GIT_REPOSITORY https://github.com/$repo
    GIT_TAG $tag
    EXCLUDE_FROM_ALL
    SYSTEM
    OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable($repo_name)
" > $template

sed -i "/include(FetchContent)/r $template" CMakeLists.txt
fi

graph=$(mktemp)
cmake --graphviz=$graph build
rg --only-matching --no-line-number "\w*::\w*" $graph | sort -u

I would like to support this feature request.

Right now, I thought FetchContent targets should show up in one of available CMake properties like BUILDSYSTEM_TARGETS and IMPORTED_TARGETS. But instead they show something unexpected like:

add_executable(app main.cpp)
get_property(TRGB DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
get_property(TRGI DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY IMPORTED_TARGETS)
message(STATUS "${TRGB} - ${TRGI}")

# let's add spdlog
include(FetchContent)
FetchContent_Declare(
        spdlog
        GIT_REPOSITORY https://github.com/gabime/spdlog.git
        GIT_TAG        v1.16.0
)
FetchContent_MakeAvailable(spdlog)

get_property(TRGB DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
get_property(TRGI DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY IMPORTED_TARGETS)
message(STATUS "${TRGB} - ${TRGI}")

Make configuration runs and shows no spdlog target, but there is Git::Git

-- app - 
-- Build spdlog: 1.16.0
-- Build type: Release
-- app - Git::Git
...

Probably FetchContent_Declare creates Git::Git to clone the git repository?

BUILDSYSTEM_TARGETS and IMPORTED_TARGETS only show the targets added in the current directory scope. They do not include targets from subdirectories, and any targets created as part of a call to FetchContent_MakeAvailable() will be within subdirectories (unless dependency providers are involved, in which case it is completely up to the provider what it does to satisfy the dependencies).

Most likely, yes. As long as policy CMP0168 is NEW, FetchContent_MakeAvailable() would end up calling FindGit in the current directory scope so it could do the git clone before calling add_subdirectory().