project_options icon indicating copy to clipboard operation
project_options copied to clipboard

target_find_dependencies and pkg-config

Open ddassie-texa opened this issue 2 years ago • 10 comments

I'm trying to use target_find_dependencies to add the dependencies for a STATIC library that depends on some libraries that can be found via pkg-config, I'm able to pass the PkgConfig package to target_find_dependencies but there doesn't seem to be an easy way to add the pkg_check_modules calls to the CMake package config, is there any way I can solve this situation?

My old Config.cmake.in file used to look like this:

@PACKAGE_INIT@

include(CMakeFindDependencyMacro)

find_dependency(Threads)
find_dependency(PkgConfig)

if(NOT TARGET PkgConfig::gio)
    pkg_check_modules(gio REQUIRED IMPORTED_TARGET gio-2.0)
endif()

if(NOT TARGET PkgConfig::dbus)
    pkg_check_modules(dbus REQUIRED IMPORTED_TARGET dbus-1)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")

check_required_components(@TARGET_NAME@)

ddassie-texa avatar Mar 13 '24 15:03 ddassie-texa

I’m not quite sure what your question is. Are you trying to target_find_dependencies(<target> PUBLIC gio) in which gio is a library that should be found by pkg_check_modules?

If that's the case, there is an official way for cmake to custom find_package, which might be helpful. You can see an actual example here, which is the CMake dependency provider for the Conan C and C++ package manager.

FeignClaims avatar Apr 28 '24 10:04 FeignClaims

Sure, so is there a way to inject a custom dependency provider into the project_options target_find_dependencies call? Or does the custom provider have to be implemented on the users of the package instead of the provider? And in that case, won't it break conan?

ddassie-texa avatar Apr 29 '24 06:04 ddassie-texa

The situation is that PkgConfig dosen't provide find_package provider, so you have to. I think this won't break conan as both cmake-conan and vcpkg use this approach and project_options works well while enabling both run_conan() and run_vcpkg().

What target_find_dependencies actually do is to

  • call find_package for the specified packages;
  • register them as a part of installation.

When running cmake --install, the corresponding cmake config file will insert a find_package(<package> [args]) for all the packages specifed in target_find_dependencies. That's how the function works.

To install pkg_check_modules dependency, you can

  • either pkg_check_modules by manual, and insert the code into cmake config file yourself at the same time.
  • or write a find_package provider which allows find_package to handle pkg_check_modules, and install the find_package provider file.

FeignClaims avatar Apr 29 '24 14:04 FeignClaims

Is this fixed after #257?

aminya avatar Apr 29 '24 18:04 aminya

Is this fixed after #257?

@aminya Possibly not. Instead of allowing custom find_package args like #257, this issue is about extending target_find_dependencies to be able to find dependencies that are imported by functions other than find_package, and install such a dependency when the target is required to install.

Without modifying the target_find_dependencies, this could be done by:

  • either pkg_check_modules by manual, and inserting the code into cmake config file yourself at the same time.
  • or writing a find_package provider which allows find_package to handle pkg_check_modules, and installing the find_package provider file.

Another option could be extending target_find_dependencies to have a custom mode:

target_find_dependencies(target
  PUBLIC
    # Syntax option 1
    CUSTOM "pkg_check_modules(gio REQUIRED IMPORTED_TARGET gio-2.0)"
    # Or syntax option 2?
    CUSTOM pkg_check_modules gio REQUIRED IMPORTED_TARGET gio-2.0
)

Please let me know if this is acceptable. If it is, which is the best syntax?

FeignClaims avatar Apr 30 '24 06:04 FeignClaims

I think the most versatile solution would be to add a way to provide a CMake script as an extension point (maybe allow multiple files?), eg: target_find_dependencies(<target> CUSTOM MyInjectedDep.cmake), then it can be installed as part of the package and included after the other find_dependency() calls.

ddassie-texa avatar Apr 30 '24 07:04 ddassie-texa

add a way to provide a CMake script as an extension point (maybe allow multiple files?), eg: target_find_dependencies(<target> CUSTOM MyInjectedDep.cmake)

After setting cmake_language(SET_DEPENDENCY_PROVIDER...), all find_package will try to use the provider, so this seems like a dependency for the whole project instead of the <target>, which violets the purpose of using target_find_dependencies (that is, bind the dependency to the target).

If setting the MyInjectedDep.cmake is the preferable way than CUSTOM pkg_check_modules gio REQUIRED IMPORTED_TARGET gio-2.0, I would prefer add a function like set_dependency_provider(<provider.cmake>) to both call cmake_language(SET_DEPENDENCY_PROVIDER...) and install it. But it is almost just a wrapper for a cmake_language(SET_DEPENDENCY_PROVIDER...) command and a install(FILES...) command, which is the solution describe before:

writing a find_package provider which allows find_package to handle pkg_check_modules, and installing the find_package provider file.

Another difference between setting dependency provider and just allowing CUSTOM any_function args is that you have to adapt the call to find_package style. For example, for pkg_check_modules(gio REQUIRED IMPORTED_TARGET gio-2.0), you have to adapt it to be find_package(gio) or something else, which is not implementable for some functions.

FeignClaims avatar Apr 30 '24 07:04 FeignClaims

I'm also unsure about what will happen if a user has a custom Findgio.cmake module and a dependency provider is added, my idea with the MyInjectedDep.cmake was just so you could more easily write complex logic to find dependencies if needed, without dealing with a long string.

ddassie-texa avatar Apr 30 '24 07:04 ddassie-texa

You could have MyInjectedDep.cmake without modifying target_find_dependencies. Just use include(MyInjectedDep.cmake) and install(FILES MyInjectedDep.cmake).

My question here is that target_find_dependencies is to set dependencies for a single target, so maybe a function like set_dependency_provider(<provider.cmake>) is more suitable than allowing target_find_dependencies to set (possibly global) a file dependency.

FeignClaims avatar Apr 30 '24 07:04 FeignClaims

Is this fixed after #257?

@aminya Possibly not. Instead of allowing custom find_package args like #257, this issue is about extending target_find_dependencies to be able to find dependencies that are imported by functions other than find_package, and install such a dependency when the target is required to install.

Without modifying the target_find_dependencies, this could be done by:

* either pkg_check_modules by manual, and inserting the code into cmake config file yourself at the same time.

* or writing a find_package provider which allows find_package to handle pkg_check_modules, and installing the find_package provider file.

Another option could be extending target_find_dependencies to have a custom mode:

target_find_dependencies(target
  PUBLIC
    # Syntax option 1
    CUSTOM "pkg_check_modules(gio REQUIRED IMPORTED_TARGET gio-2.0)"
    # Or syntax option 2?
    CUSTOM pkg_check_modules gio REQUIRED IMPORTED_TARGET gio-2.0
)

Please let me know if this is acceptable. If it is, which is the best syntax?

I guess the syntax on option 2 would be the best in this case than.

ddassie-texa avatar Apr 30 '24 09:04 ddassie-texa