libunifex icon indicating copy to clipboard operation
libunifex copied to clipboard

`std::coroutines` in INTERFACE_LINK_LIBRARIES breaks cmake packages that consume libunifex

Open bustercopley opened this issue 2 years ago • 4 comments

The CMake config file installed with unifex (e.g., /usr/local/cmake/lib/unifexConfig.cmake) contains the following:

set_target_properties(unifex::unifex PROPERTIES
  INTERFACE_COMPILE_FEATURES "cxx_std_17"
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
  INTERFACE_LINK_LIBRARIES "std::coroutines"
)

Having std::coroutines in INTERFACE_LINK_LIBRARIES means a package that declares a dependency on unifex also depends on std::coroutines. (This happens because std::coroutines is declared with the INTERFACE keyword, in libunifex/cmake/FindCoroutines.cmake.) But a definition for std::coroutines itself isn't published, so the consuming project will fail to configure, with

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

I asked a cmake expert, who said:

Enabling coroutines for older compilers is a project level concern that's done by setting flags in a toolchain/the command-line. Best course of action would be reporting the broken install interface and suggesting removing that find module altogether.

I hereby so report and suggest.

They also suggested a workaround for the consuming package to include() in its CMakeLists.txt,

In the meantime, you can use a find module to proxy the package discovery and remove the faulty bits:

# Findunifex.cmake

find_package(unifex NO_MODULE)

if(unifex_FOUND)
  get_target_property(link_libs unifex::unifex INTERFACE_LINK_LIBRARIES)
  list(REMOVE_ITEM link_libs std::coroutines)
  set_property(TARGET unifex::unifex PROPERTY INTERFACE_LINK_LIBRARIES "${link_libs}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(unifex CONFIG_MODE)

bustercopley avatar Feb 26 '22 15:02 bustercopley

Correction: the find module should not be included. It is for find_package, when operating in module mode. Instead, save the find module in the consuming project as cmake/find/Findunifex.cmake. Add the following to the consuming project's CMakeLists.txt (as usual):

find_package(unifex REQUIRED)
target_link_libraries(
  myproject_mytarget PRIVATE unifex::unifex
)

Then the person bulding the package can tell find_package to use the find module, if they decide they need to, by adding cmake/find to CMAKE_MODULE_PATH when configuring. For example,

cmake -S . -B build -DCMAKE_MODULE_PATH=./cmake/find

bustercopley avatar Feb 27 '22 12:02 bustercopley

It's possible to only depends on std::coroutines at build time.

diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -77,7 +77,7 @@ target_include_directories(unifex
 target_compile_features(unifex PUBLIC cxx_std_17)

 if(CXX_COROUTINES_HAVE_COROUTINES)
-  target_link_libraries(unifex PUBLIC std::coroutines)
+  target_link_libraries(unifex PUBLIC $<BUILD_INTERFACE:std::coroutines>)
 endif()

 configure_file(unifex.pc.in unifex.pc @ONLY)

cc-hng avatar Jun 14 '22 06:06 cc-hng

Thanks for flagging this bug with a suggested fix @bustercopley and @l2x-huang. We're planning on investing more time into maintaining this library, and we've filed a task to address this bug to our backlog.

AnujYamdagni avatar Jun 29 '22 20:06 AnujYamdagni