With modern cmake, does transtive dependency needs `find_package`?

A

find_package(CURL REQUIRED)
target_link_libraries(A PUBLIC CURL::libcurl)

B

target_link_libraries(B PRIVATE A)

When configure for B

CMake Error at CMakeLists.txt:53 (add_executable):
  Target "B" links to target "CURL::libcurl" but the target was not
  found.  Perhaps a find_package() call is missing for an IMPORTED target, or
  an ALIAS target is missing?

Does B have to find_package(CURL REQUIRED)?

BTW, if not using modern cmake, i.e. using CURL_INCLUDE_DIRS and CURL_LIBRARIES, no such a problem.

It depends on where find_package(CURL ...) is called. The imported target created is not global, so only visible in the directory, and any sub-directories, where find_package(...) call occurred.

To solve your problem, a new call to find_package(CURL ...) can be done.

In traditional way, i.e. CURL_INCLUDE_DIRS and CURL_LIBRARIES, a new call to find_package(CURL ...) is not necesary, it is expected, isn’t it?

It depends on the module you are using. In your case, it works because CURL_INCLUDE_DIRS and CURL_LIBRARIES are defined as cache variables (so with a global visibility), but it is perfectly valid that result variables are defined as standard variables. In this case, you have the same problem as the imported target.

It’s about properties of INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES.

CURL::libcurl literally in INTERFACE_LINK_LIBRARIES needs extra find_package(CURL ...) for it to make sense.

CURL_INCLUDE_DIRS and CURL_LIBRARIES in INTERFACE_LINK_LIBRARIES have concrete paths and names, so no extra find_package(CURL ...) is needed.

No, it is not a problem with properties, but with artifact visibility : the imported target is not global so does not exist everywhere as clearly described in the error message!

OK, it’s about both.

For CURL_INCLUDE_DIRS and CURL_LIBRARIES, when the values are assigned to INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES,
CURL_INCLUDE_DIRS and CURL_LIBRARIES are not needs anymore.

But for CURL::libcurl as a target, it should be visible when referenced.

The imported target doesn’t need to be global (I haven’t needed to make any imported target global in my usage). It comes from A's usage requirements, so A's scope is used to look up the imported target.

Is there any way for the result of find_package(CURL REQUIRED) in A’s scope so that no need for find_package(CURL REQUIRED) in B’s CMakeLists?

I do basically the opposite and make every imported target global. I don’t have the need for directory-specific dependencies, -l flags already have global name semantics, and it’s just less confusing that way.

I’d set a CMAKE_ALL_IMPORTS_ARE_GLOBAL=1 flag if I could.

Have a look at IMPORTED_GLOBAL property.