Библиотека Python и цель CMake с тем же именем

Я создаю библиотеку mylib, которая предназначена только для заголовков C++ и имеет API Python с использованием pybind11. Я хочу использовать mylib как цель CMake, содержащую инструкции по компиляции, и как имя Python API. Однако это приводит к конфликту имен.

Описание проблемы

Рассмотрим следующую файловую структуру:

CMakeLists.txt
include/mylib.hpp
python_api.cpp

На самом деле есть также тесты и примеры, каждый со своим CMakeLists.txt, но для целей этого примера важно только одно:

В (основном) CMakeLists.txt я определяю целевую библиотеку CMake, которая имеет путь включения к заголовку (заголовкам), но также «связывает» цели зависимостей. Так что пользователь (или тесты, примеры или сборка Python API) должен только «связать» цель и быть готовым к работе. (Наконец, я также устанавливаю цель в mylibTargets.cmake, когда устанавливаю заголовки, чтобы у конечного пользователя была поддержка CMake).

Теперь проблема: у моего пакета Python должно быть такое же имя, mylib. Однако, если я вызываю pybind11_add_module с mylib, CMake жалуется, что

CMake Error at .../share/cmake/pybind11/pybind11Tools.cmake:166 (add_library):
  add_library cannot create target "mylib" because another target with the
  same name already exists.  The existing target is an interface library
  created in source directory "..".
  See documentation for policy CMP0002 for more details.

Имеет право жаловаться. В то же время я не могу использовать другое имя ни для цели CMake (поскольку я хочу установить и использовать ее, используя единственное логическое имя, mylib), ни для цели pybind11 (поскольку она должна кодировать mylib).

Итак: как мне это решить?

(единственное решение, которое я нашел, состояло в том, чтобы переименовать одну из целей, но, как описано, я не хочу этого делать)

Подробный пример

Рассмотрим упрощенный, одиночный, CMakeLists.txt:

cmake_minimum_required(VERSION 3.1..3.19)

# configure target

project(mylib)

find_package(xtensor REQUIRED)

add_library(${PROJECT_NAME} INTERFACE)

target_include_directories(${PROJECT_NAME} INTERFACE
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)

target_link_libraries(${PROJECT_NAME} INTERFACE xtensor)

# installation of headers and of CMake target

include(CMakePackageConfigHelpers)
include(GNUInstallDirs)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include)

install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets)

install(
    EXPORT ${PROJECT_NAME}-targets
    FILE "${PROJECT_NAME}Targets.cmake"
    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")

# Build Python module

find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(${PROJECT_NAME} python_api.cpp) # <- target name conflict
target_link_libraries(example PUBLIC pybind11::module)

Слишком ограниченная работа

Я мог бы полностью разделить сборку (и последующую установку) API Python на независимый CMakeLists.txt. Однако я хочу использовать целевую библиотеку mylib, в которой уже есть все необходимое, для создания Python API. Поскольку я хочу сделать это без принудительной установки библиотеки, я не знаю, как это сделать в «одиночном» CMakeLists.txt


person Tom de Geus    schedule 22.04.2021    source источник
comment
pybind11_add_module — это просто оболочка вокруг add_library. То есть, если вы хотите, чтобы полученный файл назывался mylib.so, но не можете позволить себе использовать mylib в качестве имени цели, используйте любое другое имя для цели и настройте OUTPUT_NAME для этой цели: pybind11_add_module(mylib_python ...), set_target_properties(mylib_python PROPERTIES OUTPUT_NAME mylib).   -  person Tsyvarev    schedule 22.04.2021
comment
@Tsyvarev Спасибо, это все, что мне было нужно!   -  person Tom de Geus    schedule 22.04.2021
comment
@Tsyvarev Хотели бы вы преобразовать свой комментарий в ответ для дальнейшего использования?   -  person Tom de Geus    schedule 23.04.2021


Ответы (1)


pybind11_add_module — это просто оболочка вокруг add_library, это явно написано в документацию для этой функции. Итак, большинство трюков, которые работают для обычных библиотек, работают и для модулей Python.

То есть, если вы хотите, чтобы полученный файл назывался mylib.so, но не можете позволить себе использовать mylib в качестве целевого имени, вы можете использовать любое другое имя для целевого, но скорректируйте OUTPUT_NAME для этой цели. Например:

# Python library target has suffix '_python'
pybind11_add_module(mylib_python ...)
# But name of the library file doesn't have this suffix
set_target_properties(mylib_python PROPERTIES OUTPUT_NAME mylib)
person Tsyvarev    schedule 23.04.2021
comment
Еще раз спасибо! - person Tom de Geus; 23.04.2021