Targets conflict when using CMake FetchContent - cmake

On a CMake project, I am using FetchContent to get two dependencies. Both of them define the same target (in this case doc), resulting in an error at configuration step:
CMake Error at thirdparty/penf/doc/CMakeLists.txt:7 (add_custom_target):
add_custom_target cannot create target "doc" because another target with
the same name already exists. The existing target is a custom target
created in source directory
"/home/me/project/thirdparty/flogging/doc". See
documentation for policy CMP0002 for more details.
How can I avoid this targets conflict?

Related

How do I remove duplicate cmake targets created by sub-cmake targets?

I have a cmake project that depends on several other cmake projects.
The cmake project that I am writing depends on 2 cmake projects that both create uninstall targets.
These duplicate targets cause errors:
add_custom_target cannot create target "uninstall" because another target
with the same name already exists. The existing target is a custom target
created in source directory
I do not need the uninstall target from either sub-cmake project. How do I exclude all targets with the name uninstall so that I don't get these errors? What other options are there available to solve this error? I am looking for a solution that is OS agnostic.
I sugguest you read the following documentation for Kitware : https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake .
The process is quite well explained.

CMake importing both shared and static library versions, but I only want one

I would like to use the Antlr framework in a project. I'm using CMake to build the project.
I would like to use the SHARED library version of Antlr, not the STATIC one. Its CMake file contains targets for both.
Antlr's github site explicity tells me to use the following code:
find_package(antlr4-runtime REQUIRED)
# add runtime include directories on this project.
include_directories( ${ANTLR4_INCLUDE_DIR} )
# add runtime to project dependencies
add_dependencies( Parsertest antlr4_shared )
# add runtime to project link libraries
target_link_libraries( Parsertest PRIVATE
antlr4_shared)
(another target, antlr4_static, exists, but shouldn´t be used.)
I copied it exactly like this and am getting the following error:
CMake Error at /usr/lib64/cmake/antlr4-runtime/antlr4-targets.cmake:82 (message):
The imported target "antlr4_static" references the file
"/usr/lib/libantlr4-runtime.a"
but this file does not exist.
I dont have the static library installed in my system as I have no intention of using it. Still, how do I make CMake stop looking for the wrong target in the first place? I use it nowhere in my CMakeLists.txt file and am puzzled by this behavior.

Python library and CMake target with the same name

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.
Problem description
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)
Detailed example
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)
Too limited work around
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)

Explicitly tell to CMake target_link_libraries() to read dependency as target and not as a file from system path?

I got multiple warnings:
CMake Warning at libsysev/src/CMakeLists.txt:17 (add_library):
Cannot generate a safe runtime search path for target sysev because files
in some directories may conflict with libraries in implicit directories:
runtime library [libzlog.so] in /usr/lib/arm-linux-gnueabihf may be hidden by files in:
/home/user/project/BUILD/libzlog/src
Some of these libraries may not be found correctly.
Target defined as following:
add_library(sysev SHARED main.cpp)
target_link_libraries(sysev PUBLIC zlog)
zlog provided in source code and also installed to the system.
Root CMakeLists.txt looks like:
project(xxx)
add_subdirectory(zlog)
add_subdirectory(sysev)
I want to disambiguate zlog. CMake must know this is a target and not a file from system path.

CMake all_object_files target

I want to create a CMake target to build all object files.
To do this, I first modified all targets to build an object file lib and link against it:
add_library(exe_object_files OBJECT ${sources})
add_executable(exe $<TARGET_OBJECTS:exe_object_files>)
Since I have multiple executables, I added a target for all object files and added the targets for each executable as dependency:
add_custom_target(all_exe_object_files)
add_dependencies(all_exe_object_files exe_object_files)
This adds a all_exe_object_files target I can make, but making the target does nothing.
Then I tried adding the object files as sources:
get_target_property(all_exe_object_files_sources all_exe_object_files SOURCES)
if(NOT all_exe_object_files_sources)
set(all_exe_object_files_sources)
endif()
list(APPEND all_exe_object_files_sources $<TARGET_OBJECTS:exe_object_files>)
set_target_properties(all_exe_object_files PROPERTIES SOURCES "${all_exe_object_files_sources}")
This did not help.
I guess the reason is that add_library(... OBJECT ...) behaves similar to add_custom_command and the files are only build if a target uses them (and my custom target probably does not count as using the generated files).
What am I doing wrong and how can I create a target to build all object files?