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.
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?
Now I have a lib I made my self that I want to use in another CMake c++ project. It exists in my computer like this.
${MY_LIB_PATH}\include
${MY_LIB_PATH}\lib\x86\debug\lib-files
${MY_LIB_PATH}\lib\x86\release\lib-files
${MY_LIB_PATH}\lib\x64\debug\lib-files
${MY_LIB_PATH}\lib\x64\release\lib-files
What would a basic config file be like which makes CMake find_package know those? I expected it would be very simple because it just doesn't have much information to provide. But this page just make my head hurt.
Sorry, I decided to copy the source code around so I don't really know which answer should be accepted.
Don't write a config yourself; use CMake's export command. It's too broad to cover here in its entirety, but here's a modified example from one of my projects:
install(TARGETS
your_target
EXPORT YourPackageConfig
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
export(TARGETS
your_target
NAMESPACE YourPackage::
FILE "${CMAKE_CURRENT_BINARY_DIR}/YourPackageConfig.cmake"
)
install(EXPORT
YourPackageConfig
DESTINATION "${CMAKE_INSTALL_DATADIR}/YourPackage/cmake"
NAMESPACE YourPackage::
)
This will create the config file for you, so other projects can use it via find_package.
find_package(YourPackage REQUIRED)
target_link_libraries(foo YouprPackage::your_target)
This handles the IMPORTED targets automatically, and also lets you embed compiler flags, include paths, library dependencies, and even which files are part of your interface (basically, anything that falls under the INTERFACE properties).
Put a "${libname}-config.cmake" in library's root.
Then add an IMPORTED target in that file.
There is a example for libprotobuf.
add_library(libprotobuf STATIC IMPORTED GLOBAL)
set_target_properties(libprotobuf PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/prebuilt/android/${ANDROID_ABI}/libprotobuf.a"
IMPORTED_LINK_INTERFACE_LIBRARIES "${ZLIB_LIBRARIES};${CMAKE_THREAD_LIBS_INIT}"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/src")
Set Env or CMake variable "${libname}_DIR" to "${MY_LIB_PATH}"
Use it.
find_package(${libname})
#.......
target_link_libraries(main ${libname})
Maybe this older doc could be a tad more lightweight. And there is also this tutorial or this other one. The last one is perhaps the simplest.
Hope to not have added more pain :-)
Following the docs should give something roughly like the following (supposing your library is mylib):
MyLib/MyLibConfig.cmake.in
# - Config file for the MyLib package
# It defines the following variables
# MYLIB_INCLUDE_DIRS - include directories for MyLib
# MYLIB_LIBRARIES - libraries to link against
# MYLIB_EXECUTABLE - the bar executable
# Compute paths
get_filename_component(MYLIB_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(MYLIB_INCLUDE_DIRS "#CONF_INCLUDE_DIRS#")
# Our library dependencies (contains definitions for IMPORTED targets)
if(NOT TARGET mylib AND NOT MyLib_BINARY_DIR)
include("${MYLIB_CMAKE_DIR}/MyLibTargets.cmake")
endif()
# These are IMPORTED targets created by MyLibTargets.cmake
set(MYLIB_LIBRARIES mylib)
MyLib/MyLibConfigVersion.cmake.in
set(PACKAGE_VERSION "#MYLIB_VERSION#")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
main MyLib/CMakeLists.txt
...
set(MYLIB_MAJOR_VERSION 0)
set(MYLIB_MINOR_VERSION 1)
set(MYLIB_PATCH_VERSION 0)
set(MYLIB_VERSION
${MYLIB_MAJOR_VERSION}.${MYLIB_MINOR_VERSION}.${MYLIB_PATCH_VERSION})
...
add_library(mylib SHARED mylib.c ...)
...
install(TARGETS mylib
# IMPORTANT: Add the mylib library to the "export-set"
EXPORT MyLibTargets
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib
PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/mylib"
COMPONENT dev)
...
# The interesting stuff goes here
# ===============================
# Add all targets to the build-tree export set
export(TARGETS mylib
FILE "${PROJECT_BINARY_DIR}/MyLibTargets.cmake")
# Export the package for use from the build-tree
# (this registers the build-tree with a global CMake-registry)
export(PACKAGE MyLib)
# Create the MyLibConfig.cmake and MyLibConfigVersion files
file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}"
"${INSTALL_INCLUDE_DIR}")
# ... for the build tree
set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}")
configure_file(MyLibConfig.cmake.in
"${PROJECT_BINARY_DIR}/MyLibConfig.cmake" #ONLY)
# ... for the install tree
set(CONF_INCLUDE_DIRS "\${MYLIB_CMAKE_DIR}/${REL_INCLUDE_DIR}")
configure_file(MyLibConfig.cmake.in
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/MyLibConfig.cmake" #ONLY)
# ... for both
configure_file(MyLibConfigVersion.cmake.in
"${PROJECT_BINARY_DIR}/MyLibConfigVersion.cmake" #ONLY)
# Install the MyLibConfig.cmake and MyLibConfigVersion.cmake
install(FILES
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/MyLibConfig.cmake"
"${PROJECT_BINARY_DIR}/MyLibConfigVersion.cmake"
DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)
# Install the export set for use with the install-tree
install(EXPORT MyLibTargets DESTINATION
"${INSTALL_CMAKE_DIR}" COMPONENT dev)
I have a library foo which depends on bar. bar provides a nice barConfig.cmake upon installation.
cmake_minimum_required(VERSION 3.7)
project(foo VERSION 1.0)
find_package(bar)
add_library(foo SHARED foo.c)
target_link_libraries(foo PUBLIC bar)
install(TARGETS foo EXPORT fooTargets LIBRARY DESTINATION lib)
export(EXPORT fooTargets FILE fooTargets.cmake)
install(EXPORT fooTargets FILE fooTargets.cmake DESTINATION lib/cmake)
This works great. We simply apt install bar-dev then compile foo.
But since these packages are both developed by us and are related, my team would like to develop them in the same IDE session and compile them at the same time. I want to allow that, but I don't want to change the fact that these are already deployed as seperate packages and can be built independently.
if (DIRECTORY_EXISTS ../bar)
set(BAR_NO_INSTALL ON)
set(BAR_SKIP_TESTS ON)
add_subdirectory(../bar ${CMAKE_CURRENT_BINARY_DIR}/bar)
else()
find_package(bar)
endif()
If ../bar/ exists, then this results in:
CMake Error: install(EXPORT "fooTargets" ...) includes target "foo" which
requires target "bar" that is not in the export set.
How can I prevent the need to export bar in the foo package?
I'm trying to figure out why find_package(bar) works, but add_subdirectory(bar) doesn't. barConfig.cmake via barTargets.cmake defines bar like so:
add_library(bar SHARED IMPORTED)
set_property(TARGET bar APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
set_target_properties(bar PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "../bar/include"
IMPORTED_LOCATION_NOCONFIG "build/libbar.so.1.0.13574"
IMPORTED_SONAME_NOCONFIG "libbar.so.1"
)
My guess was the IMPORTED property that is used when bar is created in the autogenerated barConfig.cmake. I tried adding setting property (below), but saw no differences:
set_target_properties(bar PROPERTIES IMPORTED TRUE)
fooConfig.cmake does include the following which creates target bar (not bar::bar).
find_depdendency(bar)
I tried the following aliasing, hoping that an alias' inability to be exported would help me. But it still expects me to export bar.
add_library(barImported ALIAS bar)
target_link_libraries(foo PUBLIC barImported)
I tried linking only the build interface, hoping that bar would not need to be exported when installed. But that also had no effect.
target_link_libraries(foo PUBLIC $<BUILD_INTERFACE:bar>)
How can I prevent the need to export bar in the foo package?
You can't, at least not without hacks (see below).
I'm trying to figure out why find_package(bar) works, but add_subdirectory(bar) doesn't. barConfig.cmake via barTargets.cmake defines bar like so:
Because in one case, the target is imported (which can only be set on creation) and in the other case, the target is normal. Normal targets must be installed if normal targets that depend on them are installed.
The semantic issue with add_subdirectory is that CMake believes that any code you add this way is first-party. I have found that add_subdirectory and its relative FetchContent are more trouble than they're worth for installed dependencies. They're useful for build-or-test-only dependencies that do not need to be shipped.
One way to work around this is to use the COMPONENT / NAMELINK_COMPONENT features of the install() command. Then you would set the CPACK_COMPONENTS_ALL variable to include only the components from foo and not those from bar. When specifying components, you should avoid generic names like development or runtime, and instead prefix those names with the project name: foo_development, bar_runtime, etc.
Unfortunately, this does not affect the cmake --build . --target install command. You'll have to go through cmake --install . --component <comp> or CPack.
A hack is to add the bar dependency to foo as $<BUILD_INTERFACE:...> and then re-attach it to foo in fooConfig.cmake after include-ing your generated target export file and finding bar via find_dependency.
Here's the solution I came up with. This is for an arbitrary library foo (dynamic and static versions plus tests) which could also be a dependency in the same manner that I import bar:
cmake_minimum_required(VERSION 3.7)
include(GNUInstallDirs)
project(foo VERSION 1.0)
# Options set to
# ON explicitly for build machines,
# OFF by default for developers who build dependencies inline and only build for local use
option(FOO_EXPORT_TARGETS "Generate fooConfig.cmake for packaging." OFF)
option(FOO_BUILD_TESTS "Build and run tests. Default off for aircraft. Turn on in your IDE if developing foo" OFF)
# This is best implemented as a macro/function from an included cmake
set(BAR_ROOT "/noexist" CACHE PATH "Location of BAR for in-source building")
if (DIRECTORY_EXISTS "${BAR_ROOT}")
add_subdirectory(${BAR_ROOT})
else()
find_package(bar)
endif()
set(fooSources foo.c)
set(fooPublicHeaders include/foo.h)
add_library(fooObjects OBJECT ${fooSources})
target_include_directories(fooObjects
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE
$<TARGET_PROPERTY:bar,INTERFACE_INCLUDE_DIRECTORIES>
)
add_library(foo SHARED $<TARGET_OBJECTS:fooObjects>)
add_library(fooStatic STATIC $<TARGET_OBJECTS:fooObjects>)
target_link_libraries(foo PUBLIC fooObjects bar)
target_link_libraries(fooStatic PUBLIC fooObjects barStatic)
set_target_properties(fooObjects foo fooStatic
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
if (NOT FOO_EXPORT_TARGETS)
install(TARGETS foo LIBRARY DESTINATION lib)
else()
set_target_properties(foo fooStatic
PROPERTIES
VERSION ${foo_VERSION}
SOVERSION ${foo_VERSION_MAJOR}
PUBLIC_HEADER "${fooPublicHeaders}"
)
install(
TARGETS foo fooStatic fooObjects
EXPORT fooTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/foo
)
include(CMakePackageConfigHelpers)
set(configDir "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/foo-${foo_VERSION_MAJOR}")
configure_package_config_file(
"${CMAKE_CURRENT_LIST_DIR}/fooConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake"
INSTALL_DESTINATION ${configDir}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/fooConfigVersion.cmake"
VERSION ${foo_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/fooConfigVersion.cmake"
DESTINATION ${configDir}
)
export (EXPORT fooTargets FILE fooTargets.cmake)
install(EXPORT fooTargets FILE fooTargets.cmake DESTINATION ${configDir})
endif()
if (FOO_BUILD_TESTS)
add_executable(test_foo test.c)
target_link_libraries(test_foo foo)
enable_testing()
add_test(NAME test_foo COMMAND test_foo WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
With the following fooConfig.cmake.in:
include(CMakeFindDependencyMacro)
#PACKAGE_INIT#
find_dependency(bar)
if(NOT TARGET foo)
include("${CMAKE_CURRENT_LIST_DIR}/fooTargets.cmake")
endif()
The build machines create a debian package out of this. This is what the debian/rules files look like to ensure it is compiled without any in-source building, with packaging, and with tests:
#!/usr/bin/make -f
#export DH_VERBOSE = 1
%:
dh $#
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
-DFOO_BUILD_TESTS=ON \
-DFOO_EXPORT_TARGETS=ON \
-DBAR_ROOT=/noexist
When I use set(CMAKE_DEBUG_POSTFIX "d"), the build and install targets work as expected. But in the libfooTargets-debug.cmake file with the exported targets, there is a path to libfoo and not libfood.
I exported the targets like this:
install(TARGETS libfoo EXPORT libfoo-targets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
install(EXPORT libfoo-targets FILE libfooTargets.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
which creates and installs libfooTargets.cmake and libfooTargets-debug.cmake when building in debug mode, and libfooTargets.cmake and libfooTargets-release.cmake when building in release mode.
Both libfooTargets-release.cmake and libfooTargets-debug.cmake reference the name without a postfix as:
list(APPEND _IMPORT_CHECK_FILES_FOR_libfoo "${_IMPORT_PREFIX}/lib/libfoo.lib" )
and thus a program linking against the debug target still uses the release-build library and I would need to install release and debug versions into different folders to be able to link against the debug target.
How can I get the exported targets to work with a debug postfix?
I could of course try to change the library name depending on CMAKE_RELEASE_TYPE or a CONFIGURATION generator expression, but this will probably break the multi-configuration features in MSVC and other IDEs supporting different targets and seems not to work in the sense of how the exported targets feature is meant to simplify and unify the build.
I suspect that the install(EXPORT ...) command somehow drops the CMAKE_DEBUG_POSTFIX or does not implement it for generating the libfooTargets-{release,debug}.cmake files, but possibly I overlooked how to make this variable visible to the generator of the exported targets or something like this.
All target code
cmake_minimum_required(VERSION 3.11.1)
project(foo)
include(CMakePackageConfigHelpers)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_DEBUG_POSTFIX "d")
# ...
add_library(libfoo STATIC somesource.cpp someheader.h)
target_include_directories(libfoo PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
target_link_libraries(libfoo
somelibrary
)
target_include_directories (libfoo PUBLIC
somelibrary_header_dirs
)
install(TARGETS libfoo EXPORT libfoo-targets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
install(EXPORT libfoo-targets FILE libfooTargets.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
configure_package_config_file(libfooConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libfooConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libfooConfig.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h")
The platform is a Windows 10 with cmake 3.11.1 and MSVC 2015. Of course the most general solution is probably the best one.
According to the documentation of the install command, you need to reference the configuration that you are interested in:
[...] If a CONFIGURATIONS option is given then the file will only be installed when one of the named configurations is installed. Additionally, the generated import file will reference only the matching target configurations. [...]
So, you need to add the CONFIGURATIONS option in both install commands and duplicate the commands for each configuration you want to install and export.
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