I'm constructing a library "mylib" that is C++ header-only and has a Python API using pybind11. I want to use "mylib" both as CMake target, containing compile instructions, and as name of the Python API. However, this leads to a name conflict.
Consider the following file structure:
CMakeLists.txt
include/mylib.hpp
python_api.cpp
In reality there are also tests and examples, each with their own CMakeLists.txt, but for the purpose of this example the only thing that matters is:
In the (main) CMakeLists.txt I am defining a CMake target "mylib" that has the include path to the header(s), but also 'links' the targets of dependencies. So that the user (or tests, examples, or build of the Python API) only has to 'link' the target and be good to go. (Finally, I'm also installing the target in mylibTargets.cmake when I install the headers such that there is CMake support for the end user).
Now the problem: My Python package should have the same name, "mylib". However, if I call pybind11_add_module with "mylib", CMake complains that
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.
It has the right to complain. At the same time I cannot use a different name for either the CMake target (since I want to install and use it using the only logical name, "mylib") or the pybind11 target (since it has to encode "mylib").
So: how do I solve this?
(The only solution I found was to rename one of targets, but as described I don't want to do this)
Consider the simplified, single, 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)
I could entirely split building (and later install) the Python API to an independent CMakeLists.txt. However, I want to use the target "mylib", that I already equipped with everything it needs, to build the Python API. Since I want to do this without being forced to install the library forced, I don't know how to do this in a 'single' CMakeLists.txt
pybind11_add_module is just a wrapper around add_library, this is explicitely written in the documentation for that function. So, most of the "tricks", which works for the common libraries, works for python modules too.
That is, if you want resulted file to be named as mylib.so but cannot afford you to use mylib as a target name, then you could use any other name for the target but adjust OUTPUT_NAME property for that target. For example:
# 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With