Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generating CMAKE EXPORT #247

Closed
jcarpent opened this issue Oct 11, 2019 · 12 comments
Closed

Generating CMAKE EXPORT #247

jcarpent opened this issue Oct 11, 2019 · 12 comments

Comments

@jcarpent
Copy link
Contributor

Dear @gergondet,

I have a minor question concerning the use of PROJECT_USE_CMAKE_EXPORT.
Should we use systematically add_project_dependency to list the dependencies of a project and then use the export?

Second, can we imagine to automatically generate the CMAKE EXPORT files of a dependency directly from the pkg-config file of it, in order to make a project totally independent from pkg-config when linking against it in a new project?

Thanks in advance for your insights!

Justin

@jcarpent
Copy link
Contributor Author

@wxmerkt This might be of your interest.

@gergondet
Copy link
Member

Hi Justin,

I'll try to clarify some things.

PROJECT_USE_CMAKE_EXPORT is merely telling the jrl-cmakemodules that we are using exports in the project in order to automate the call of setup_project_package_finalize() because it's doing an install(EXPORT ...) that will fail if nothing is exported

There's currently two supported ways to work with dependent projects but they are somewhat exclusives:

  1. The "old" way using pkg-config and add_required_dependency/add_optional_dependency plus pkg_config_use_dependency. You know about this one so I won't tell much more.

  2. The modern CMake way (see this article for an overview of what is meant by modern here) which use CMake packages.

The way to make it work with the jrl-cmakemodules is described in the doc.

Let's say you have a project ProjectA and a library FeaturesA inside, the minimal CMake:

# jrl-cmakemodules includes
project(${PROJECT_NAME} CXX)
add_library(FeaturesA ${MY_SOURCES})
install(TARGETS featuresA EXPORT ${TARGETS_EXPORT_NAME} DESTINATION lib)

Then within ProjectB, you simply consume the package:

find_package(ProjectA REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main ProjectA::FeaturesA)

When you are building another library (ProjectC) that depends on ProjectA you'll want to use add_project_dependency(ProjectA REQUIRED). This ensure that the user only need to find ProjectC (this is similar to add_required_dependency in pkg-config approach)

Nowadays, in our "end-user" projects we don't need to have the jrl-cmakemodules submodule, we can simply find_package(mc_rtc REQUIRED) and use the libraries from there. Furthermore, it's possible to export extra macros, so the simplest project you can build is:

cmake_minimum_required(VERSION 3.1)
find_package(mc_rtc REQUIRED)
# add_controller macro is exported by mc_rtc CMake package
add_controller(MyController MyController.cpp MyController.h)

You also gain the benefit that all build flags/dependencies are exported cleanly (respecting PUBLIC/PRIVATE keywords) and without any repetition required on your side (e.g. you don't need to think of exporting the library or flags as you do for the .pc)

The major downsides of the approach is that it's a CMake-only approach. So you loose the ability to integrate with other build-systems and you loose the ability to try out a very simple program on the command line, i.e.:

g++ -o sandbox sandbox.cpp `pkg-config --cflags --libs ProjectA`

It should be possible to generate a usable .pc file from the CMake target information but I haven't had the time nor the motivation to look into it.

Note: it also works poorly with CMake 2.8.12 (targets-based approach are viable but there is a lot of nice features for it from 3.1). I'm still building Ubuntu 14.04 packages so that's a pity but I've just added a more recent CMake version to my ppa to work around the issue.

I hope this is clear enough, let me know if you have more questions

@jcarpent
Copy link
Contributor Author

Thanks a lot @gergondet for this nice explanation.
A last remaining question concerns the generation of a FindPinocchioDependencies.cmake file which will translate all the *.pc used by add_required_dependency to explicitly linked the project to the known dependencies. Do you have in mind or think about such exportation toolbox?

@gergondet
Copy link
Member

A last remaining question concerns the generation of a FindPinocchioDependencies.cmake file which will translate all the *.pc used by add_required_dependency to explicitly linked the project to the known dependencies. Do you have in mind or think about such exportation toolbox?

I'm not sure I fully understand the question, do you want to have find_package(Pinocchio) also search for pkg-config dependencies?

If so, I have an example here: https://github.com/jrl-umi3218/mc_rbdyn_urdf/blob/master/CMakeLists.txt#L29 and the companion CMakeModule here: https://github.com/jrl-umi3218/mc_rbdyn_urdf/blob/master/CMakeModules/Findmc_rbdyn_urdf_TinyXML2.cmake

In that case we try to find a tinyxml2 CMake package (exists with recent versions of TinyXML2) otherwise we fall back to a regular search and we install. The module will be installed along the config file for mc_rbdyn_urdf and we make sure to include by appending to the PACKAGE_EXTRA_MACROS variable.

Similar example with nanomsg and pkg-config here and the export of multiple extra includes:

install(FILES ${MODULE_FILES} DESTINATION "${CONFIG_INSTALL_DIR}")
foreach(F ${MODULE_FILES})
  set(PACKAGE_EXTRA_MACROS "${PACKAGE_EXTRA_MACROS}
include(\"\${CMAKE_CURRENT_LIST_DIR}/${F}\")")
endforeach()
set(PACKAGE_EXTRA_MACROS ${PACKAGE_EXTRA_MACROS} PARENT_SCOPE)

@jmirabel
Copy link
Collaborator

@jcarpent Reopen if needed. @gergondet Thanks for the clarifications.

@wxmerkt
Copy link
Contributor

wxmerkt commented Oct 25, 2019

Hi @gergondet,
Thank you very much for the clear and detailed description and reference to the documentation. I have added the export and it correctly creates the export to the library for linking. It does not seem to populate the ${PROJECT_NAME}_INCLUDE_DIRS variable though. What steps do I need to do for the config file to include this information?

Thank you very much,
Wolfgang

@gergondet
Copy link
Member

Hi @wxmerkt,

The intended usage is not to rely on specific variables, rather you would:

find_package(eigenpy REQUIRED)

target_link_libraries(MyLibrary eigenpy::eigenpy)

Your eigenpy target should make sure that it exposes everything to correctly link with the library, this includes compile options, compile definitions, include directories and so on.

If you absolutely need to add that extra variable, you can use:

set(PACKAGE_EXTRA_MACROS "${PACKAGE_EXTRA_MACROS}
set(${PROJECT_NAME}_INCLUDE_DIRS ${${PROJECT_NAME}_INCLUDE_DIRS})")

@jcarpent
Copy link
Contributor Author

@wxmerkt I think we can automize the process for each current project relying on the jrl cmake module. Are you going into this direction?

@wxmerkt
Copy link
Contributor

wxmerkt commented Oct 28, 2019

@jcarpent I was aiming to see whether I can implement it directly following the tutorial but missed exporting the includes and compile options/definitions. I don't plan on following this up right now due to time constraints, however.

@olivier-stasse
Copy link
Member

I really like the article. It seems so much cleaner than all the tweakling we had to go through. In our group I do not think we have anymore commitments with 14.04 LTS. Thus I would be pushing in relying more on this new design pattern and remove the dependency to pc file. I am not sure I fully grasp all the implications but it seems to me that it would be very helpfull with plenty of new tools and usages.

@nim65s What do you think ?

@jcarpent
Copy link
Contributor Author

@gergondet I forgot to thank you a lot for this very nice introduction.

@traversaro
Copy link
Contributor

traversaro commented Dec 20, 2019

FYI @jcarpent @gergondet there is an ongoing discussion at the CMake level about supporting a CMake independent way of exporting packages, I guess you could be interested in that given this discussion: https://gitlab.kitware.com/cmake/cmake/issues/20106 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants