Я создаю библиотеку 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
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