how come cmake does not give an error when not specifying FILE name?
I understand that when FILE name not specified, cmake gives it the project's name...by this logic should be mandatory to specify path...
no error:
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/my_math/addition.h
${CMAKE_CURRENT_SOURCE_DIR}/include/my_math/division.h
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/my_math)
install(TARGETS my_math EXPORT my_export DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
install(EXPORT my_export DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
INTERFACE_INCLUDE_DIRECTORIES error:
install(TARGETS my_math EXPORT my_export DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
install(EXPORT my_export
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math
FILE my_math-config.cmake)
complete error message:
CMake Error in my_math/CMakeLists.txt:
Target "my_math" INTERFACE_INCLUDE_DIRECTORIES property contains path:
"/home/alon/cmake/sandbox/Install/my_math/include"
which is prefixed in the source directory.
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
Related
I'm new to CMake and have trouble understanding how targets are exposed in the install interface. I have a CMakeLists.txt where I define two targets (PROJECT_NAME is "realtime"):
...
add_library(${PROJECT_NAME} realtime_client.cpp)
...
configure_file(version/realtime_version.cpp.in realtime_version.cpp #ONLY)
add_library(realtime_version STATIC ${CMAKE_CURRENT_BINARY_DIR}/realtime_version.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE realtime_version)
...
You can see that the realtime_version target is privately linked to the realtime target. For the install interface I just want the realtime target to be exposed to the outside world whereas the version target should vanish. So I would typically do this:
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME} EXPORT "${PROJECT_NAME}_Exports"
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT ${PROJECT_NAME}_Runtime
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT ${PROJECT_NAME}_Runtime
NAMELINK_COMPONENT ${PROJECT_NAME}_Development
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT ${PROJECT_NAME}_Development
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
set(REALTIME_TARGET_EXPORT_NAME "${PROJECT_NAME}_Exports")
install(EXPORT ${REALTIME_TARGET_EXPORT_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/realtime-${PROJECT_VERSION}
NAMESPACE supabase::
FILE ${PROJECT_NAME}_Development.cmake
COMPONENT ${PROJECT_NAME}_Development
)
But then CMake complains that the realtime_version target has no install rules:
[cmake] CMake Error: install(EXPORT "realtime_Exports" ...) includes target "realtime" which requires target "realtime_version" that is not in any export set.
What I really want is for this library to just be compiled into the binary of the realtime target. I thought this would happen automatically, but it seems I'm mistaken. I might have missed a few essential things. So how can I hide the realtime_version target from export_sets and instead just compile it into the binary?
Take the following example as a start:
...
add_library(Foo ...)
install(TARGETS Foo EXPORT FooTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
...
)
install(EXPORT FooTargets
FILE lib/cmake/Foo
...
)
Running this with
$ mkdir build; cd build
$ cmake -DCMAKE_BUILD_TYPE=Release .. (or in Debug)
$ cmake --build .
$ cmake --install . --prefix my/custom/prefix
This will create the files:
my/custom/prefix/lib/cmake/Foo/FooTargets.cmake
my/custom/prefix/lib/cmake/Foo/FooTargets-release.cmake (Or debug, respectively)
my/custom/prefix/lib/libFoo.a
And from what I managed to understand from the FooTargets.cmake file, it globs for all FooTargets-*.cmake files and includes() them all.
In turn, the FooTargets-release.cmake file is the one that references the libFoo.a file.
In the docs about the install command, it says that you can add the CONFIGURATIONS option to the install TARGETS command, so that if we change the above:
install(TARGETS Foo EXPORT FooTargets
CONFIGURATIONS Debug
LIBRARY DESTINATION lib/Debug
ARCHIVE DESTINATION lib/Debug
This will install the libFoo.a file in my/custom/path/lib/Debug/libFoo.a. Now let's say I want the Release library to be installed in lib/Release and the Debug library be installed in lib/Debug, and that when the downstream project will consume my package, it will have the right library depending on its configuration - i.e. - debug build will link against the Debug library, same for release.
What I thought I can do is:
install(TARGETS Foo EXPORT FooTargets
CONFIGURATIONS Debug
LIBRARY DESTINATION lib/Debug
ARCHIVE DESTINATION lib/Debug
)
install(TARGETS Foo EXPORT FooTargets
CONFIGURATIONS Release
LIBRARY DESTINATION lib/Release
ARCHIVE DESTINATION lib/Release
)
install(EXPORT FooTargets
DESTINATION lib/cmake/Foo
...
)
And what will happen is that when building in Debug, the FooTargets-debug.cmake will be generated, pointing to the lib/Debug/libFoo.a, and when building in Release, the FooTargets-release.cmake will be generated, pointing to the lib/Release/libFoo.a. The FooTargets.cmake will then check what configuration is the consuming project is building with, and include the right configuration.
When I try doing the above, I get:
-- Configuring done
CMake Error: install(EXPORT "FooTargets" ...) includes target "Foo" more than once in the export set.
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
How is this should be done??
EDIT
I found out, in a not-very-straightforward way, that when I build the consuming project as such:
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
and like this:
$ cmake -DCMAKE_BUILD_TYPE=Release ..
I am linking against only the relevant library. Basically how this works is that the FooTargets.cmake file is included by the FooConfig.cmake file, which is called by find_package. The FooTargets.cmake file is the one that defines the imported target:
add_library(Foo IMPORTED)
This file then calls all the FooTargets-*.cmake, which adds the relevant library to some list called _IMPORT_CHECK_FILES_FOR_FOO.
What this file also does, is:
set_property(TARGET Foo::Foo APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
Apparently there is some property IMPORTED_CONFIGURATIONS that holds the imported configurations.
I suppose that somewhere down the road, find_package takes this list and filters it according to the CMAKE_BUILD_TYPE variable, and this way links only the relevant library.
What I still don't understand, is how to make it so that upon Release builds (of Foo), the FooTargets-release.cmake will be created, pointing to lib/Release/Foo.a, and the same for debug builds.
It seems that CMake went half-way with this, unless I'm seriously missing something.
It seems per-CONFIGURATIONS installs are not easily fit to EXPORT semantic.
However, in simple cases per-configuration's specific can be achieved by using generator expressions in DESTINATION:
install(TARGETS Foo EXPORT FooTargets
LIBRARY DESTINATION lib/$<CONFIG>
ARCHIVE DESTINATION lib/$<CONFIG>
)
install(EXPORT FooTargets
DESTINATION lib/cmake/Foo
...
)
The code above will install libraries into lib/Debug for Debug configuration, and into lib/Release for Release configuration.
I have static library Foo, static library Bar that depends on Foo and executable Baz that depends on Bar.
Relevant sections from Foo CMakeLists.txt:
# Specifying files to copy during "make install" command.
install(TARGETS Foo EXPORT FooConfig
INCLUDES DESTINATION include
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# Specifying config file that will be used to find a library using find_package().
install(EXPORT FooConfig
FILE FooConfig.cmake
NAMESPACE Foo::
DESTINATION lib/cmake/Foo)
export(TARGETS Foo
NAMESPACE Foo::
FILE FooConfig.cmake)
Relevant sections from Bar CMakeLists.txt:
# Specifying libraries that are required for build.
find_package(Foo REQUIRED)
# Specifying libraries to link to for the users of the library.
target_link_libraries(Bar PUBLIC Foo::Foo)
# Specifying files to copy during "make install" command.
install(TARGETS Bar EXPORT BarConfig
INCLUDES DESTINATION include
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# Specifying config file that will be used to find a library using find_package().
install(EXPORT BarConfig
FILE BarConfig.cmake
NAMESPACE Bar::
DESTINATION lib/cmake/Bar)
export(TARGETS Bar
NAMESPACE Bar::
FILE BarConfig.cmake)
And finally Baz CmakeLists.txt:
find_package(Bar REQUIRED)
target_link_libraries(Baz PRIVATE Bar::Bar)
Now when building Baz I get:
CMake Error at CMakeLists.txt:19 (add_executable):
Target "Baz" links to target "Foo::Foo" but the
target was not found. Perhaps a find_package() call is missing for an
IMPORTED target, or an ALIAS target is missing?
So build finds Bar and correctly determines that it depends on Foo but can't find Foo. I have another test project that directly depends on Foo and it builds fine. How to fix this?
Unfortunately, BarConfig.cmake generated like this does not handle finding dependencies, I had to modify Bar CMakeLists.txt to this:
# Specifying files to copy during "make install" command.
install(TARGETS Bar EXPORT BarTargets
INCLUDES DESTINATION include
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
install(FILES CMake/BarConfig.cmake DESTINATION lib/cmake/Bar)
# Specifying config file that will be used to find a library using find_package().
install(EXPORT BarTargets
FILE BarTargets.cmake
NAMESPACE Bar::
DESTINATION lib/cmake/Bar)
export(TARGETS Bar
NAMESPACE Bar::
FILE BarTargets.cmake)
Then I created a file CMake/BarConfig.cmake with this:
include("${CMAKE_CURRENT_LIST_DIR}/BarTargets.cmake")
find_package(Foo REQUIRED)
Now this BarConfig.cmake gets installed globally and calls find_package that finds Foo.
I have created cmake target, say A, and want to install it and create a Config file, so that the installed package could be relocatable. My code is:
install(EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION ??? )
Here, I am having a problem with the proper destination. I want the Config file to be installed where ${CMAKE_INSTALL_PREFIX} points to. But when I put ${CMAKE_INSTALL_PREFIX} at ???, my resulting ATargets.cmake file contains the line:
set(_IMPORT_PREFIX "C:/Libraries/...")
which is the actual value of ${CMAKE_INSTALL_PREFIX}. This _IMPORT_PREFIX is later prepended to the parameters of set_target_properties() command inside the auto-generated ATargets.cmake, resulting in hard coded paths, valid only on the installation system.
I tried to use some generator expressions like <$IMPORT_PREFIX> in place of ???, but this gave me an error at cmake generation. I also tried to omit DESTINATION which in my opinion should place the file in the location relative to ${CMAKE_INSTALL_PREFIX}, but cmake complained about it too.
Can you please help me with this issue?
This is an old question so you have probably solved it already (or given up).
I think the critical thing is that the export DESTINATION matches the one given to INSTALL_DESTINATION to configure_package_config_file().
what we are using is:
install(TARGETS
foobar
EXPORT foobarLibTargets
LIBRARY DESTINATION lib)
set(ConfigFileInstallDir lib/cmake/foobar)
set(INCLUDE_INSTALL_DIR include)
set(LIBRARY_INSTALL_DIR lib)
configure_package_config_file(src/main/cmake/foobarConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfig.cmake"
INSTALL_DESTINATION "${ConfigFileInstallDir}"
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfigVersion.cmake"
VERSION "${VERSION}"
COMPATIBILITY ExactVersion)
export(EXPORT foobarLibTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake")
install(EXPORT foobarLibTargets
FILE foobarLibTargets.cmake
DESTINATION "${ConfigFileInstallDir}")
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfigVersion.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake"
DESTINATION "${ConfigFileInstallDir}")
${ConfigFileInstallDir} is replaced automagically by _IMPORT_PREFIX
so that the generated foobarLibTargets.cmake contains something like:
set_property(TARGET foobar APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/foobar.so.2.0.0"
IMPORTED_SONAME_RELEASE "libfoobar.so.2"
)
There can be troubles getting this to work. See my questions:
correctly set the location of imported cmake targets for an installed package &
Strange issue with variables in a config-file cmake package.
See you in the ward for those suffering from cmake related nervous disorders in the near future...
When building an opensource project with CMake (in my case, it was the lemon graph library), I got this error when I tried to build shared libaries via -DBUILD_SHARED_LIBS=1:
TARGETS given no LIBRARY DESTINATION for shared library target
Where does this error come from and how do I fix it?
In my CMakeLists.txt, my INSTALL command had no LIBRARY parameter.
Changing from this:
INSTALL(
TARGETS lemon
ARCHIVE DESTINATION lib
COMPONENT library
)
to this:
INSTALL(
TARGETS lemon
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib # <-- Add this line
COMPONENT library
)
fixed my problem.
I got this... Another reason this happens is when you create a shared library
add_library(${NAME} SHARED sources )
then when Cmake reaches the install command on Windows platform, it complains of these error, solution is to use RUNTIME instead of LIBRARY, like
if(WIN32)
install(TARGETS ${NAME}
RUNTIME DESTINATION path)
else()
install(TARGETS ${NAME}
LIBRARY DESTINATION path)
endif()
After DESTINATION, it should have bin, lib, include.
install lib or bin
install(TARGETS snappy
EXPORT SnappyTargets
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # DESTINATION error
RUNTIME DESTINATION bin ${CMAKE_INSTALL_BINDIR} # should add bin or other dir
LIBRARY DESTINATION lib ${CMAKE_INSTALL_LIBDIR}
# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR # DESTINATION error
ARCHIVE DESTINATION lib ${CMAKE_INSTALL_LIBDIR} # should add lib
)
For example, install .h file:
install(
FILES
"${PROJECT_SOURCE_DIR}/test_hard1.h"
"${PROJECT_BINARY_DIR}/config.h"
# DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # error install FILES given no DESTINATION!
# add include after DESTINATION, then it works
DESTINATION include ${CMAKE_INSTALL_INCLUDEDIR}
)
see https://cmake.org/cmake/help/v3.0/command/install.html for more detail:
install(TARGETS myExe mySharedLib myStaticLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(TARGETS mySharedLib DESTINATION /some/full/path)
I just faced a similar problem. As #Fernando said in his answer, you can go with that solution. Another and similar solution is to just include(GNUInstallDirs)
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
EXPORT "${PROJECT_NAME}Config"
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
I had a similar, but not identical error message:
CMake Error at xxx/CMakeLists.txt:123 (install):
install Library TARGETS given no DESTINATION!
The fix in this case was to simply update CMake; from version 3.13.3 to 3.25.1 or really any newer version.
Note: I had originally posted my own question at CMake Error: install Library TARGETS given no DESTINATION but it was closed as a duplicate (although the error message was different), so I posted my own answer here.
I do not know if this would fix the TARGETS given no LIBRARY DESTINATION for shared library target error.
The other answers all talk about modifying the CMake configuration files (i.e. CMakeLists.txt), so this answer is new - and easier.
Our fix was just to update, and leave the configuration alone. As the error was thrown from another open source project, this was by far the better fix, for us.
Since CMake 3.14 the option DESTINATION is no longer required for executables, shared/static libraries and some other artifacts: CMake provides reasonable defaults for their installation directories. Alternatively, one could include module GNUInstallDirs, and set corresponding CMAKE_INSTALL_<dir> variable.
For regular executables, static libraries and shared libraries, the DESTINATION argument is not required. For these target types, when DESTINATION is omitted, a default destination will be taken from the appropriate variable from GNUInstallDirs, or set to a built-in default value if that variable is not defined. The same is true for the public and private headers associated with the installed targets through the PUBLIC_HEADER and PRIVATE_HEADER target properties.
https://cmake.org/cmake/help/v3.14/command/install.html#targets