Creating relocatable export files

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Creating relocatable export files

Roger Leigh
Hi,

I'm wanting to create -config scripts for my libraries so that dependent
projects can find them with find_package and use them transparently.  I
have a number of header-only and shared/static libs, and I'd like to
retain their relationships, plus any additional libraries they are
linked with.

I was previously using hand-crafted templates, e.g. with this type of
generated structure:

---------------------------------------------------------------------------
set(OME_COMMON_FOUND TRUE)

set(OME_COMMON_VERSION "5.2.0-pre0-7-gfc53ca3")
set(OME_COMMON_VERSION_MAJOR "5")
set(OME_COMMON_VERSION_MINOR "2")
set(OME_COMMON_VERSION_PATCH "0")
set(OME_COMMON_VERSION_EXTRA "-pre0-7-gfc53ca3")

find_path(OME_COMMON_INCLUDE_DIR ome/common/module.h HINTS
"/tmp/split/include")
find_library(OME_COMMON_LIBRARY NAMES ome-common libome-common HINTS
"/tmp/split/lib")
---------------------------------------------------------------------------

They unfortuately did not handle interface targets or public library
dependencies required by use in the headers.  I've switched to using
install(EXPORT):

https://github.com/rleigh-dundee/ome-common-cpp/blob/develop/lib/ome/common/CMakeLists.txt#L123
---------------------------------------------------------------------------
target_link_libraries(ome-common ome-compat
                       ${Boost_LOG_SETUP_LIBRARY_RELEASE}
                       ${Boost_LOG_LIBRARY_RELEASE}
                       ${Boost_FILESYSTEM_LIBRARY_RELEASE}
                       ${Boost_SYSTEM_LIBRARY_RELEASE}
                       ${LibDl_LIBRARIES}
                       ${XercesC_LIBRARIES})

set_target_properties(ome-common PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(ome-common PROPERTIES VERSION ${OME_VERSION_SHORT})

install(TARGETS ome-common
         EXPORT ome-common-config
         RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
         LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
         ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
install(EXPORT ome-common-config
         DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/ome-common)
---------------------------------------------------------------------------

This does a much better job of the dependencies.  It's preserving the
dependencies for the internal targets, plus the external libraries.
However, it's lacking:

- any setting of the include path via FOO_INCLUDE_DIR, unless it's just
not done in an obvious manner
- it's hardcoded the absolute paths of the various boost and xerces
libs; I'd like it to be relocatable so it can work in a superbuild and
continue to work after moving elsewhere
- it doesn't appear to recursively find needed import targets, e.g. I
need to find_package(ome-compat) before find_package(ome-common); it
would be nice if this was transparent so the user doesn't need to do this

I'd be interested to know if anyone else has run into these issues, and
if so what your solutions were?  I'm quite new to this part of cmake, so
it may well just be I'm not doing things exactly as expected.

Would it be easier to construct the template myself and then call
find_package for the external libs to avoid hardcoding the paths?  Is it
safe to recursively call find_package inside find_package?


Thanks all,
Roger
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Creating relocatable export files

Nicholas Braden
Instead of using FOO_INCLUDE_DIR, I believe you should use
target_include_directories() with the INTERFACE or PUBLIC options -
this will export the include directories properly and they will be
used when someone target_link_library()s your exported target.
https://cmake.org/cmake/help/latest/command/target_include_directories.html?highlight=INTERFACE

There seems to be a section in the documentation on making sure your
packages are relocatable:
https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-relocatable-packages

See also:
https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html

As for recursively finding packages, I honestly don't know on this
front. I would imagine that everything might work if everything was
using exported/imported targets, but I'm not sure. The problem is that
you have to consider what happens if you relocate your relocatable
package to a system that doesn't have the dependencies installed. I
don't think exported/imported targets or relocatable packages can
solve that problem easily, but I am not very knowledgeable in this
area myself.

On Sat, Nov 14, 2015 at 5:53 AM, Roger Leigh <[hidden email]> wrote:

> Hi,
>
> I'm wanting to create -config scripts for my libraries so that dependent
> projects can find them with find_package and use them transparently.  I have
> a number of header-only and shared/static libs, and I'd like to retain their
> relationships, plus any additional libraries they are linked with.
>
> I was previously using hand-crafted templates, e.g. with this type of
> generated structure:
>
> ---------------------------------------------------------------------------
> set(OME_COMMON_FOUND TRUE)
>
> set(OME_COMMON_VERSION "5.2.0-pre0-7-gfc53ca3")
> set(OME_COMMON_VERSION_MAJOR "5")
> set(OME_COMMON_VERSION_MINOR "2")
> set(OME_COMMON_VERSION_PATCH "0")
> set(OME_COMMON_VERSION_EXTRA "-pre0-7-gfc53ca3")
>
> find_path(OME_COMMON_INCLUDE_DIR ome/common/module.h HINTS
> "/tmp/split/include")
> find_library(OME_COMMON_LIBRARY NAMES ome-common libome-common HINTS
> "/tmp/split/lib")
> ---------------------------------------------------------------------------
>
> They unfortuately did not handle interface targets or public library
> dependencies required by use in the headers.  I've switched to using
> install(EXPORT):
>
> https://github.com/rleigh-dundee/ome-common-cpp/blob/develop/lib/ome/common/CMakeLists.txt#L123
> ---------------------------------------------------------------------------
> target_link_libraries(ome-common ome-compat
>                       ${Boost_LOG_SETUP_LIBRARY_RELEASE}
>                       ${Boost_LOG_LIBRARY_RELEASE}
>                       ${Boost_FILESYSTEM_LIBRARY_RELEASE}
>                       ${Boost_SYSTEM_LIBRARY_RELEASE}
>                       ${LibDl_LIBRARIES}
>                       ${XercesC_LIBRARIES})
>
> set_target_properties(ome-common PROPERTIES LINKER_LANGUAGE CXX)
> set_target_properties(ome-common PROPERTIES VERSION ${OME_VERSION_SHORT})
>
> install(TARGETS ome-common
>         EXPORT ome-common-config
>         RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
>         LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
>         ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
> install(EXPORT ome-common-config
>         DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/ome-common)
> ---------------------------------------------------------------------------
>
> This does a much better job of the dependencies.  It's preserving the
> dependencies for the internal targets, plus the external libraries. However,
> it's lacking:
>
> - any setting of the include path via FOO_INCLUDE_DIR, unless it's just not
> done in an obvious manner
> - it's hardcoded the absolute paths of the various boost and xerces libs;
> I'd like it to be relocatable so it can work in a superbuild and continue to
> work after moving elsewhere
> - it doesn't appear to recursively find needed import targets, e.g. I need
> to find_package(ome-compat) before find_package(ome-common); it would be
> nice if this was transparent so the user doesn't need to do this
>
> I'd be interested to know if anyone else has run into these issues, and if
> so what your solutions were?  I'm quite new to this part of cmake, so it may
> well just be I'm not doing things exactly as expected.
>
> Would it be easier to construct the template myself and then call
> find_package for the external libs to avoid hardcoding the paths?  Is it
> safe to recursively call find_package inside find_package?
>
>
> Thanks all,
> Roger
> --
>
> Powered by www.kitware.com
>
> Please keep messages on-topic and check the CMake FAQ at:
> http://www.cmake.org/Wiki/CMake_FAQ
>
> Kitware offers various services to support the CMake community. For more
> information on each offering, please visit:
>
> CMake Support: http://cmake.org/cmake/help/support.html
> CMake Consulting: http://cmake.org/cmake/help/consulting.html
> CMake Training Courses: http://cmake.org/cmake/help/training.html
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/cmake
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Creating relocatable export files

Tamás Kenéz
You need to manually write your config module which takes care of the dependencies. Of course you will still use the generated exports, too.

For now let's say `ome-common` has one dependency: `omedep` and its config-module, `omedep-config.cmake` creates the imported lib target `omedep::omedep`. The in `ome-common`'s CMakeLists.txt:

    target_link_libraries(ome-common PUBLIC omedep::omedep)
    install(TARGETS ome-common
        EXPORT ome-common-targets ....)
    install(EXPORT ome-common-targets
        DESTINATION cmake/ome-common)
    install(FILES ome-common-config.cmake DESTINATION cmake/ome-common)

 The `ome-common-config.cmake` should look like this:

    include(CMakeFindDependencyMacro)
    find_dependency(omedep)
    include(${CMAKE_CURRENT_LIST_DIR}/ome-common-targets.cmake)

Note: for CMake versions < 3.0 you need to use `find_package` instead of `find_dependency`.

Okay, so that's the solution if `ome-common`'s dependency creates an imported lib target.

If `omedep` has an oldschool config-module which provides only variables like OMEDEP_LIBRARIES containing absolute paths, then these paths will be hardcoded in `ome-common-targets.cmake`. In this case the recommended method is to convert these paths to relative paths in a postprocess step after installation.
See this: https://gist.github.com/tamaskenez/7ca4cba352525985ea70 as an example for such a script.

Of course this can only be used if `omedep` is a dependency which is installed into the same install tree as `ome-common`.
If you have a dependency in a separate install-tree which does not create imported lib targets then you need to do it yourself both in `ome-common`'s CMakeLists.txt and config-modules. This is not a trivial operation but always can be done with more or less additional logic. For a simple case where `omedep` consists of a single library file:

`ome-common`'s CMakeLists.txt:

    find_package(omedep REQUIRED)
    add_library(ome-common::omedep STATIC IMPORTED) # STATIC or SHARED or UNKNOWN
    set_target_properties(ome-common::omedep PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES ${OMEDEP_INCLUDE_DIRS}
        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
        IMPORTED_LOCATION ${OMEDEP_LIBRARIES} # a single library
    )
    target_link_libraries(ome-common PUBLIC ome-common::omedep)
    ...

which should be repeated in `ome-common-config.cmake`:

    include(CMakeFindDependencyMacro)
    find_dependency(omedep)
    set_target_properties(ome-common::omedep PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES ${OMEDEP_INCLUDE_DIRS}
        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
        IMPORTED_LOCATION ${OMEDEP_LIBRARIES} # a single library
    )
    include(${CMAKE_CURRENT_LIST_DIR}/ome-targets.cmake)

Things get more complicated when OMEDEP_LIBRARIES has per-config variants or further dependencies. You can check the generated `ome-common-targets.cmake` and `ome-common-targets-Debug/Relase.cmake` files for an example on how to set up such an imported lib target.



On Sat, Nov 14, 2015 at 7:19 PM, Nicholas Braden <[hidden email]> wrote:
Instead of using FOO_INCLUDE_DIR, I believe you should use
target_include_directories() with the INTERFACE or PUBLIC options -
this will export the include directories properly and they will be
used when someone target_link_library()s your exported target.
https://cmake.org/cmake/help/latest/command/target_include_directories.html?highlight=INTERFACE

There seems to be a section in the documentation on making sure your
packages are relocatable:
https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-relocatable-packages

See also:
https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html

As for recursively finding packages, I honestly don't know on this
front. I would imagine that everything might work if everything was
using exported/imported targets, but I'm not sure. The problem is that
you have to consider what happens if you relocate your relocatable
package to a system that doesn't have the dependencies installed. I
don't think exported/imported targets or relocatable packages can
solve that problem easily, but I am not very knowledgeable in this
area myself.

On Sat, Nov 14, 2015 at 5:53 AM, Roger Leigh <[hidden email]> wrote:
> Hi,
>
> I'm wanting to create -config scripts for my libraries so that dependent
> projects can find them with find_package and use them transparently.  I have
> a number of header-only and shared/static libs, and I'd like to retain their
> relationships, plus any additional libraries they are linked with.
>
> I was previously using hand-crafted templates, e.g. with this type of
> generated structure:
>
> ---------------------------------------------------------------------------
> set(OME_COMMON_FOUND TRUE)
>
> set(OME_COMMON_VERSION "5.2.0-pre0-7-gfc53ca3")
> set(OME_COMMON_VERSION_MAJOR "5")
> set(OME_COMMON_VERSION_MINOR "2")
> set(OME_COMMON_VERSION_PATCH "0")
> set(OME_COMMON_VERSION_EXTRA "-pre0-7-gfc53ca3")
>
> find_path(OME_COMMON_INCLUDE_DIR ome/common/module.h HINTS
> "/tmp/split/include")
> find_library(OME_COMMON_LIBRARY NAMES ome-common libome-common HINTS
> "/tmp/split/lib")
> ---------------------------------------------------------------------------
>
> They unfortuately did not handle interface targets or public library
> dependencies required by use in the headers.  I've switched to using
> install(EXPORT):
>
> https://github.com/rleigh-dundee/ome-common-cpp/blob/develop/lib/ome/common/CMakeLists.txt#L123
> ---------------------------------------------------------------------------
> target_link_libraries(ome-common ome-compat
>                       ${Boost_LOG_SETUP_LIBRARY_RELEASE}
>                       ${Boost_LOG_LIBRARY_RELEASE}
>                       ${Boost_FILESYSTEM_LIBRARY_RELEASE}
>                       ${Boost_SYSTEM_LIBRARY_RELEASE}
>                       ${LibDl_LIBRARIES}
>                       ${XercesC_LIBRARIES})
>
> set_target_properties(ome-common PROPERTIES LINKER_LANGUAGE CXX)
> set_target_properties(ome-common PROPERTIES VERSION ${OME_VERSION_SHORT})
>
> install(TARGETS ome-common
>         EXPORT ome-common-config
>         RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
>         LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
>         ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
> install(EXPORT ome-common-config
>         DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/ome-common)
> ---------------------------------------------------------------------------
>
> This does a much better job of the dependencies.  It's preserving the
> dependencies for the internal targets, plus the external libraries. However,
> it's lacking:
>
> - any setting of the include path via FOO_INCLUDE_DIR, unless it's just not
> done in an obvious manner
> - it's hardcoded the absolute paths of the various boost and xerces libs;
> I'd like it to be relocatable so it can work in a superbuild and continue to
> work after moving elsewhere
> - it doesn't appear to recursively find needed import targets, e.g. I need
> to find_package(ome-compat) before find_package(ome-common); it would be
> nice if this was transparent so the user doesn't need to do this
>
> I'd be interested to know if anyone else has run into these issues, and if
> so what your solutions were?  I'm quite new to this part of cmake, so it may
> well just be I'm not doing things exactly as expected.
>
> Would it be easier to construct the template myself and then call
> find_package for the external libs to avoid hardcoding the paths?  Is it
> safe to recursively call find_package inside find_package?
>
>
> Thanks all,
> Roger
> --
>
> Powered by www.kitware.com
>
> Please keep messages on-topic and check the CMake FAQ at:
> http://www.cmake.org/Wiki/CMake_FAQ
>
> Kitware offers various services to support the CMake community. For more
> information on each offering, please visit:
>
> CMake Support: http://cmake.org/cmake/help/support.html
> CMake Consulting: http://cmake.org/cmake/help/consulting.html
> CMake Training Courses: http://cmake.org/cmake/help/training.html
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/cmake
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake


--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Creating relocatable export files

Alexander Neundorf-3
In reply to this post by Nicholas Braden
On Saturday, November 14, 2015 12:19:11 Nicholas Braden wrote:

> Instead of using FOO_INCLUDE_DIR, I believe you should use
> target_include_directories() with the INTERFACE or PUBLIC options -
> this will export the include directories properly and they will be
> used when someone target_link_library()s your exported target.
> https://cmake.org/cmake/help/latest/command/target_include_directories.html?
> highlight=INTERFACE
>
> There seems to be a section in the documentation on making sure your
> packages are relocatable:
> https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-re
> locatable-packages
>
> See also:
> https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html

this is from before the fancy target-include-directories-propagation
functionality was added, it shouldn't be necessary anymore.

Alex

--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake