Как использовать find_package для пакета, добавленного из директории верхнего уровня add_subdirectory? - PullRequest
1 голос
/ 26 апреля 2019

Это может быть проблемой xy, так что вот моя ситуация.

Фон


У меня есть следующая структура проекта:

-project
    -examples
        -example_that_uses_mylib_1
            * CMakeLists.txt
            * main.cpp
        -example_that_uses_mylib_2
            * CMakeLists.txt
            * main.cpp
    -external
        -notmylib_a
            * CMakeLists.txt
            * ... (other stuff)
        -notmylib_b
            * CMakeLists.txt
            * ... (other stuff)
    -src
        -mylib_stuff
            * file1.cpp
            * file1.h
        *CMakeLists.txt
    CMakeLists.txt

Я пытаюсь создать файл cmake, который выполняет следующее:

  • позволяет mylib зависеть от целей в сторонних библиотеках, найденных в external, без использования add_subdirectory, учитывая, что они на самом деле не являются подкаталогами, и это плохая практика.

  • позволяет example_that_uses_mylib исполняемым файлам, которые зависят от цели mylib, без добавления ее в качестве подкаталога.

Я не был уверен, как это сделать, пока не увидел этот проект , чей cmake верхнего уровня делает это:

add_subdirectory(lib/foo)
add_subdirectory(src/bar)
add_subdirectory(src/baz)

и bar иbaz CMakeLists.txt сделать это:

#Bar
find_package(foo 0.1.2 CONFIG REQUIRED)

#Baz
find_package(bar CONFIG REQUIRED)

Что заставило меня думать, что я могу сделать то же самое с моими библиотеками.Я не мог

Первоначально CMakeLists.txt с одним верхним уровнем создавал все цели, я хотел отойти от этого и разделить здание на add_subdirectories, начиная с mylib.

Проблема


Первоначально мой верхний уровень CMakeLists.txt выглядел примерно так (который раньше работал):

add_subdirectory(external/notmylib_a)
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

, когда я решил разделить вещипоэтому изначально я сделал это (что также работает):

#CMakeLists.txt
add_subdirectory(external/notmylib_a)


#src/CMakeLists.txt
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

Затем, чтобы следовать другому проекту, я решил сделать это:

#CMakeLists.txt
add_subdirectory(external/notmylib_a)


#src/CMakeLists.txt
find_package(notmylib_a CONFIG REQUIRED) #NEW LINE!!
add_library(mylib STATIC src/mylib_stuff/file1.cpp)
target_include_directories(mylib PUBLIC src/)
target_link_libraries(mylib PRIVATE notmylib_a::notmylib_a)

, и я получил ошибку в CMAKE

CMake Error at src/CMakeLists.txt:25 (find_package):
  Could not find a package configuration file provided by "notmylib_a"
  with any of the following names:

    notmylib_aConfig.cmake
    notmylib_a-config.cmake

  Add the installation prefix of "notmylib_a" to CMAKE_PREFIX_PATH or set
  "notmylib_a_DIR" to a directory containing one of the above files.  If
  "notmylib_a" provides a separate development package or SDK, be sure it
  has been installed.

Как другой проект смог использовать find_package таким образом?

Ответы [ 2 ]

1 голос
/ 26 апреля 2019

Как другой проект смог использовать find_package таким образом?

Файл конфигурации для другого foo проекта содержит следующие строки :

if(NOT TARGET foo::foo)
    include("${foo_CMAKE_DIR}/foo-targets.cmake")
endif()

То есть, когда foo включен с подходом add_subdirectory и создает foo::foo target, find_package(foo) на самом деле игнорирует его файл конфигурации.

Это отмечено в CMakeLists.txt foo :

# We also add an alias definition so that we shadown
# the export namespace when using add_subdirectory() instead.
add_library(foo::foo ALIAS foo)

Другими словами, с данным пакетом foo, включенным в подход add_subdirectory, возможно использование find_package(foo), но необязательно : можно напрямую использовать цель foo или foo::foo без каких-либо find_package().

0 голосов
/ 26 апреля 2019

Пример проекта, на который вы ссылаетесь, способен выполнить:

#Bar
find_package(foo 0.1.2 CONFIG REQUIRED)

#Baz
find_package(bar CONFIG REQUIRED)

, поскольку оба подпроекта lib/foo и src/bar имеют CMakeLists.txt файлы которые содержат код CMake, который генерирует файл конфигурации пакета CMake который будет искать по find_package, когда указан режим CONFIG, обнаружение которого будет успешным для команды find_package.

В lib/foo/CMakeLists.txt, например, такой код включает:

include(CMakePackageConfigHelpers)
...
set(PROJECT_CONFIG_FILE         "${PROJECT_BINARY_DIR}/foo-config.cmake")
...
configure_package_config_file(cmake/foo-config.cmake.in
        ${PROJECT_CONFIG_FILE}
        INSTALL_DESTINATION ${INSTALL_CONFIG_DIR})

В результате, когда cmake запускается для генерации файлов сборки проекта, Файл конфигурации пакета находится среди сгенерированных файлов, например:

$ git clone https://github.com/sunsided/cmake.git
...
$ cd cmake/
$ mkdir build
$ cd build
$ cmake ..
...
$ find -name '*-config.cmake'
./lib/foo/foo-config.cmake
./src/bar/bar-config.cmake

Эти два *-config.cmake файла соответствуют конфигурации пакета файлы для lib/foo и src/bar. Документация для find_package CONFIG режима описывает (сложный) алгоритм поиска, с помощью которого find_package обнаружит их. Для подпроекта src/bar

find_package(foo 0.1.2 CONFIG REQUIRED)

может найти lib/foo/foo-config.cmake, потому что при запуске файлы сборки для его зависимости lib/foo уже были сгенерированы. Аналогично для подпроекта src/baz

find_package(bar CONFIG REQUIRED)

успешно, потому что файлы сборки для его зависимости src/bar уже были генерируется.

Ошибка CMake, полученная от вашей попытки использовать find_package таким же образом:

CMake Error at src/CMakeLists.txt:25 (find_package):
  Could not find a package configuration file provided by "notmylib_a"
  with any of the following names:

    notmylib_aConfig.cmake
    notmylib_a-config.cmake
    ...

теперь имеет очевидное значение. Чтобы это исправить, нужно заполнить недостающие CMake-код в external/notmylib_a/CMakeLists.txt для генерации notmylib_a-config.cmake.

...