Cmake: Exporting subproject targets to main projec

2020-06-17 04:49发布

问题:

I currently have a project called LIBS with a structure like this:

├── Lib1
│   ├── CMakeLists.txt
│   ├── lib1-class.cpp
│   └── lib1-class.h
├── lib2
│   └── CMakeLists.txt
│   ├── lib2-class.cpp
│   ├── lib2-class.h
├── cmake
│   └── LIBSConfig.cmake.in
├── CMakeLists.txt                                                           

in the main cmake file, I have:

install(
        TARGETS
        lib1
        lib2
        DESTINATION
        ${PROJECT_DIRNAME_lib}
        EXPORT
        ${PROJECT_NAME}Exports
)

install(
        EXPORT
        ${PROJECT_NAME}Exports
        DESTINATION
        ${PROJECT_DIRNAME_lib}
)

as I want to export these in a package that is discoverable by find_package().

My problem is that I generate lib1 and lib2 in their respective directories and when installing them, Cmake tells me that

Error:install TARGETS given target "lib1" which does not exist in this directory.

As suggested here, My understanding is that I should use Export() and in lib1 and lib2, have something of the form:

export(TARGETS lib1 FILE lib1Exports.cmake)

and in the LIBS project, have something like this:

ADD_LIBRARY(lib1 UNKNOWN IMPORTED)
set_property(TARGET lib1 PROPERTY IMPORTED_LOCATION lib1)

However it does not like me using the same name for this library that is being added from the parent project. It tells me:

Error:add_library cannot create imported target "lib1" because another target with the same name already exists.

so the library is available and I can link to it, etc. if I were to create another target in the parent directory, but I can't install it.

I have found the exact same problem in a bug report here but I believe cmake handles things differently now and I am just not doing it correctly. So am I doing it wrong? I would like to avoid using external packages if possible.

Update: the accepted solution works only for cases where there is no dependency between lib1, lib2. In that case one should use the solution provided to this question.

回答1:

As noted in the bugreport you refer to install() command should be issued from the same directory where target is created. As you have libraries target created in different directories, you need to assign different export names for them, and, consequently, different export files.

But you are free to include both export files into the LIBSConfig.cmake script:

cmake/LIBSConfig.cmake:

get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(${SELF_DIR}/LIBS-lib1.cmake)
include(${SELF_DIR}/LIBS-lib2.cmake)

lib1/CMakeLists.txt:

add_library(lib1 ...)
install(TARGET lib1 EXPORT lib1-export ...)

lib2/CMakeLists.txt:

add_library(lib2 ...)
install(TARGET lib2 EXPORT lib2-export ...)

CMakeLists.txt:

add_subdirectory(lib1)
add_subdirectory(lib2)

install(EXPORT lib1-export FILENAME LIBS-lib1.cmake DESTINATION lib/LIBS)
install(EXPORT lib2-export FILENAME LIBS-lib2.cmake DESTINATION lib/LIBS)
install(FILES cmake/LIBSConfig.cmake DESTINATION lib/LIBS)

Note, that export command exports build tree. It is usually not suitable for find_package, which is normally used for find installed files.