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

Support exported targets #40

Open
nicolamos opened this issue Feb 6, 2020 · 4 comments
Open

Support exported targets #40

nicolamos opened this issue Feb 6, 2020 · 4 comments

Comments

@nicolamos
Copy link

I have a C++ project using the CMake build system. I tried to link to libfort with
add_subdirectory(…) + target_link_libraries(mylib libfort) but cmake complains as it does not export targets. Indeed, there is no install(export ) for targets with CMake configuration files.
It would be possible to support also exported targets for use in an external project?
Thanks in advance for any help!

@seleznevae
Copy link
Owner

seleznevae commented Feb 9, 2020

Hi! I am currently working on exporting targets and creating appropriate files for library installation. I am not a cmake expert. So I think it will take a few days to figure out how to create proper cmake files.

But I wanted to note that library target is called fort (not libfort).
If I am not mistaken at the moment in case you copied sources in directory third-party you can add it to you project like this:

add_subdirectory(third-party/libfort EXCLUDE_FROM_ALL)
target_link_libraries(mylib fort)

or

add_subdirectory(third-party/libfort/lib)
target_link_libraries(mylib fort)

@nicolamos
Copy link
Author

nicolamos commented Feb 10, 2020

Hi! Thank you for the prompt response. By digging a bit on what happens during the configuration process, I figure out that upon creation of the export targets in my project, cmake complains that libfort lacks one.

The first strategy you suggested works for me, as long as I don’t export targets by myself.
The second approach works fine as long as no installation is performed, since it lacks version information provided by the full cmake project.

I am not a cmake expert either, so I may be missing something…

Since it took several days for me to figure out the proper way to support exported targets, let me suggest you how you can do it. Actually, in the end it is pretty straightforward. Your CMakeLists.txt file should contain the following lines after target creation (via add_library or add_executable):

include(CMakePackageConfigHelpers)

configure_package_config_file(
    ${LIB_NAME}-config.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}-config.cmake
    INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
    PATH_VARS CMAKE_INSTALL_INCLUDEDIR
)

write_basic_package_version_file(
    ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}-config-version.cmake
    COMPATIBILITY SameMajorVersion
)

install(
    FILES
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}-config.cmake
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}-config-version.cmake
    DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)

install(
    TARGETS ${LIB_NAME}
    EXPORT ${LIB_NAME}-targets
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

install(
     EXPORT ${LIB_NAME}-targets
     FILE ${LIB_NAME}-targets.cmake
     NAMESPACE ${PROJECT_NAME}::
     DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)

with the standard definitions CMAKE_INSTALL_LIBDIR=lib, CMAKE_INSTALL_BINDIR=bin, CMAKE_INSTALL_INCLUDEDIR=include.
CMAKECONFIG_INSTALL_DIR is usually defined as ${CMAKE_INSTALL_LIBDIR}/cmake/${LIB_NAME}, relative to the installation prefix.

Adding a NAMESPACE prevents name clashes, and also allows for a clean way to support multi-targets projects. The target can then be linked to as ${PROJECT_NAME}::${LIB_NAME}, in your case it would be: libfort::fort.

The *-targets.cmake files are automatically generated, you just need to write a *-config.cmake.in file. This file can be nothing more than

@PACKAGE_INIT@

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

check_required_components("@LIB_NAME@")

This is, to my current understanding, what should be done. This should just work. :) Hope it helps!

Best,
Nicola

@seleznevae
Copy link
Owner

seleznevae commented Feb 20, 2020

Hi! Sorry for keep you waiting.
Merged changes to develop (thanks for posting examples above, they helped me a lot).
Exported target is called libfort::fort.
So I think in case libfort is installed you can use in cmake:

find_package(libfort)
target_link_libraries(mylib libfort::fort)

Also added some simple checks to CI to check how library is installed and used by other libraries.

If something is still incorrect or doesn't work as expected feel free to write comments.

As I understand what I've done and tested is not particular you case because you don't install libfort but use add_subdirectory, I haven't tested such variant myself yet, I'll try to write such test for CI in a few days and correct cmake files if needed.

@nicolamos
Copy link
Author

Hi! I am glad that it helped you.

You are right, I mixed some things, but I actually need both methods... ;)
The library is first searched with find_package and if not found, cmake falls back to compilation from source with add_subdirectory.

As soon I have time to test myself, I will do!

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

2 participants