diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fc120fb9..a2f4d2f80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -530,3 +530,5 @@ elseif(SFML_OS_ANDROID) install(FILES src/SFML/Android.mk DESTINATION .) endif() + +sfml_export_targets() diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index 62f439e82..0221b4d14 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -287,5 +287,49 @@ function(sfml_find_package) target_link_libraries(${target} INTERFACE "$") endforeach() endif() + install(TARGETS ${target} EXPORT SFMLConfigExport) +endfunction() + +# Generate a SFMLConfig.cmake file (and associated files) from the targets registered against +# the EXPORT name "SFMLConfigExport" (EXPORT parameter of install(TARGETS)) +function(sfml_export_targets) + # CMAKE_CURRENT_LIST_DIR or CMAKE_CURRENT_SOURCE_DIR not usable for files that are to be included like this one + set(CURRENT_DIR "${PROJECT_SOURCE_DIR}/cmake") + + include(CMakePackageConfigHelpers) + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigVersion.cmake" + VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} + COMPATIBILITY SameMajorVersion) + + if (BUILD_SHARED_LIBS) + set(config_name "Shared") + else() + set(config_name "Static") + endif() + set(targets_config_filename "SFML${config_name}Targets.cmake") + + export(EXPORT SFMLConfigExport + FILE "${CMAKE_CURRENT_BINARY_DIR}/${targets_config_filename}") + + if (SFML_BUILD_FRAMEWORKS) + set(config_package_location "SFML.framework/Resources/CMake") + else() + set(config_package_location lib/cmake/SFML) + endif() + configure_package_config_file("${CURRENT_DIR}/SFMLConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfig.cmake" + INSTALL_DESTINATION "${config_package_location}") + configure_package_config_file("${CURRENT_DIR}/SFMLConfigDependencies.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigDependencies.cmake" + INSTALL_DESTINATION "${config_package_location}") + + + install(EXPORT SFMLConfigExport + FILE ${targets_config_filename} + DESTINATION ${config_package_location}) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigDependencies.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigVersion.cmake" + DESTINATION ${config_package_location} + COMPONENT devel) endfunction() diff --git a/cmake/SFMLConfig.cmake.in b/cmake/SFMLConfig.cmake.in new file mode 100644 index 000000000..ce819534a --- /dev/null +++ b/cmake/SFMLConfig.cmake.in @@ -0,0 +1,148 @@ +# This script provides the SFML libraries as imported targets +# ------------------------------------ +# +# Usage +# ----- +# +# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main). +# If none is given, no imported target will be created and you won't be able to link to SFML libraries. +# example: +# find_package(SFML COMPONENTS graphics window system) # find the graphics, window and system modules +# +# You can enforce a specific version, either MAJOR.MINOR or only MAJOR. +# If nothing is specified, the version won't be checked (i.e. any version will be accepted). +# example: +# find_package(SFML COMPONENTS ...) # no specific version required +# find_package(SFML 2 COMPONENTS ...) # any 2.x version +# find_package(SFML 2.4 COMPONENTS ...) # version 2.4 or greater +# +# By default, the dynamic libraries of SFML will be found. To find the static ones instead, +# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...). +# You don't need to deal with SFML's dependencies when linking your targets against SFML libraries, +# they will all be configured automatically, even if you use SFML static libraries. +# example: +# set(SFML_STATIC_LIBRARIES TRUE) +# find_package(SFML 2 COMPONENTS network system) +# +# On macOS by default CMake will search for frameworks. If you want to use static libraries and have installed +# both SFML frameworks and SFML static libraries, your must set CMAKE_FIND_FRAMEWORK to "NEVER" or "LAST" +# in addition to setting SFML_STATIC_LIBRARIES to TRUE. Otherwise CMake will check the frameworks bundle config and +# fail after finding out that it does not provide static libraries. Please refer to CMake documentation for more details. +# +# Additionally, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which +# are available for both release and debug modes. +# +# If SFML is not installed in a standard path, you can use the SFML_DIR CMake variable +# to tell CMake where SFML's config file is located (PREFIX/lib/cmake/SFML for a library-based installation, +# and PREFIX/SFML.framework/Resources/CMake on macOS for a framework-based installation). +# +# Output +# ------ +# +# This script defines the following variables: +# - For each specified module XXX (system, window, graphics, network, audio, main): +# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found +# - SFML_FOUND: true if all the required modules are found +# +# And the following targets: +# - For each specified module XXX (system, window, graphics, network, audio, main): +# - sfml-XXX +# The SFML targets are the same for both Debug and Release build configurations and will automatically provide +# correct settings based on your currently active build configuration. The SFML targets name also do not change +# when using dynamic or static SFML libraries. +# +# When linking against a SFML target, you do not need to specify indirect dependencies. For example, linking +# against sfml-graphics will also automatically link against sfml-window and sfml-system. +# +# example: +# find_package(SFML 2 COMPONENTS graphics audio REQUIRED) +# add_executable(myapp ...) +# target_link_libraries(myapp sfml-graphics sfml-audio) + +if (NOT SFML_FIND_COMPONENTS) + message(FATAL_ERROR "find_package(SFML) called with no component") +endif() + +set(FIND_SFML_PATHS + "${CMAKE_CURRENT_LIST_DIR}/../.." + ${SFML_ROOT} + $ENV{SFML_ROOT} + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw + /opt/local + /opt/csw + /opt) + +find_path(SFML_DOC_DIR SFML.tag + PATH_SUFFIXES SFML/doc share/SFML/doc + PATHS ${FIND_SFML_PATHS}) + + +# Update requested components (eg. request window component if graphics component was requested) +set(FIND_SFML_SYSTEM_DEPENDENCIES "") +set(FIND_SFML_MAIN_DEPENDENCIES "") +set(FIND_SFML_AUDIO_DEPENDENCIES system) +set(FIND_SFML_NETWORK_DEPENDENCIES system) +set(FIND_SFML_WINDOW_DEPENDENCIES system) +set(FIND_SFML_GRAPHICS_DEPENDENCIES window system) +set(FIND_SFML_ADDITIONAL_COMPONENTS "") +foreach(component ${SFML_FIND_COMPONENTS}) + string(TOUPPER "${component}" UPPER_COMPONENT) + list(APPEND FIND_SFML_ADDITIONAL_COMPONENTS ${FIND_SFML_${UPPER_COMPONENT}_DEPENDENCIES}) +endforeach() +list(APPEND SFML_FIND_COMPONENTS ${FIND_SFML_ADDITIONAL_COMPONENTS}) +list(REMOVE_DUPLICATES SFML_FIND_COMPONENTS) + +# Choose which target definitions must be imported +if (SFML_STATIC_LIBRARIES) + set(SFML_IS_FRAMEWORK_INSTALL "@SFML_BUILD_FRAMEWORKS@") + if (SFML_IS_FRAMEWORK_INSTALL) + message(WARNING "Static frameworks are not supported by SFML. Clear SFML_DIR cache entry, \ +and either change SFML_STATIC_LIBRARIES or CMAKE_FIND_FRAMEWORK before calling find_package(SFML)") + endif() + set(config_name "Static") +else() + set(config_name "Shared") +endif() +set(targets_config_file "${CMAKE_CURRENT_LIST_DIR}/SFML${config_name}Targets.cmake") + +# Generate imported targets for SFML and its dependencies +if (EXISTS "${targets_config_file}") + # Set SFML_FOUND to TRUE by default, may be overwritten by one of the includes below + set(SFML_FOUND TRUE) + include("${targets_config_file}") + include("${CMAKE_CURRENT_LIST_DIR}/SFMLConfigDependencies.cmake") + + if (SFML_FOUND) + foreach (component ${SFML_FIND_COMPONENTS}) + string(TOUPPER "${component}" UPPER_COMPONENT) + if (TARGET sfml-${component}) + set(SFML_${UPPER_COMPONENT}_FOUND TRUE) + else() + set(FIND_SFML_ERROR "Found SFML but requested component '${component}' is missing in the config defined in ${SFML_DIR}.") + set(SFML_${UPPER_COMPONENT}_FOUND FALSE) + set(SFML_FOUND FALSE) + endif() + endforeach() + endif() +else() + set(FIND_SFML_ERROR "Requested SFML configuration (${config_name}) was not found") + set(SFML_FOUND FALSE) +endif() + +if (NOT SFML_FOUND) + if(SFML_FIND_REQUIRED) + # fatal error + message(FATAL_ERROR "${FIND_SFML_ERROR}") + elseif(NOT SFML_FIND_QUIETLY) + # error but continue + message(STATUS "${FIND_SFML_ERROR}") + endif() +endif() + +if (SFML_FOUND AND NOT SFML_FIND_QUIETLY) + message(STATUS "Found SFML @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ in ${CMAKE_CURRENT_LIST_DIR}") +endif() diff --git a/cmake/SFMLConfigDependencies.cmake.in b/cmake/SFMLConfigDependencies.cmake.in new file mode 100644 index 000000000..2f85b388a --- /dev/null +++ b/cmake/SFMLConfigDependencies.cmake.in @@ -0,0 +1,80 @@ + +if (CMAKE_VERSION VERSION_LESS 3.5.2) + include(CMakeParseArguments) +endif() + +# in case of static linking, we must also define the list of all the dependencies of SFML libraries +if(SFML_STATIC_LIBRARIES) + # detect the OS + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(FIND_SFML_OS_WINDOWS 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(FIND_SFML_OS_LINUX 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(FIND_SFML_OS_FREEBSD 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(FIND_SFML_OS_MACOSX 1) + endif() + + # start with an empty list + set(FIND_SFML_DEPENDENCIES_NOTFOUND) + + # macro that searches for a 3rd-party library + function(sfml_bind_dependency) + cmake_parse_arguments(THIS "" "TARGET;FRIENDLY_NAME" "SEARCH_NAMES" ${ARGN}) + if (THIS_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments when calling sfml_bind_dependency: ${THIS_UNPARSED_ARGUMENTS}") + endif() + + # No lookup in environment variables (PATH on Windows), as they may contain wrong library versions + find_library(${THIS_FRIENDLY_NAME}_LIB NAMES ${THIS_SEARCH_NAMES} + PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH) + mark_as_advanced(${THIS_FRIENDLY_NAME}_LIB) + if(${THIS_FRIENDLY_NAME}_LIB) + set_property(TARGET ${THIS_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${${THIS_FRIENDLY_NAME}_LIB}") + else() + set(FIND_SFML_DEPENDENCIES_NOTFOUND "${FIND_SFML_DEPENDENCIES_NOTFOUND} ${THIS_FRIENDLY_NAME}" PARENT_SCOPE) + endif() + endfunction() + + # sfml-window + list(FIND SFML_FIND_COMPONENTS "window" FIND_SFML_WINDOW_COMPONENT_INDEX) + if(FIND_SFML_WINDOW_COMPONENT_INDEX GREATER -1) + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) + sfml_bind_dependency(TARGET X11 FRIENDLY_NAME "X11" SEARCH_NAMES "X11") + sfml_bind_dependency(TARGET X11 FRIENDLY_NAME "Xrandr" SEARCH_NAMES "Xrandr") + endif() + + if(FIND_SFML_OS_LINUX) + sfml_bind_dependency(TARGET UDev FRIENDLY_NAME "UDev" SEARCH_NAMES "udev" "libudev") + endif() + + if (FIND_SFML_OS_WINDOWS) + set_property(TARGET OpenGL APPEND PROPERTY INTERFACE_LINK_LIBRARIES "OpenGL32") + else() + sfml_bind_dependency(TARGET OpenGL FRIENDLY_NAME "OpenGL" SEARCH_NAMES "OpenGL" "GL") + endif() + endif() + + # sfml-graphics + list(FIND SFML_FIND_COMPONENTS "graphics" FIND_SFML_GRAPHICS_COMPONENT_INDEX) + if(FIND_SFML_GRAPHICS_COMPONENT_INDEX GREATER -1) + sfml_bind_dependency(TARGET Freetype FRIENDLY_NAME "FreeType" SEARCH_NAMES "freetype") + endif() + + # sfml-audio + list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT_INDEX) + if(FIND_SFML_AUDIO_COMPONENT_INDEX GREATER -1) + sfml_bind_dependency(TARGET OpenAL FRIENDLY_NAME "OpenAL" SEARCH_NAMES "OpenAL" "openal" "openal32") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Ogg" SEARCH_NAMES "ogg") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Vorbis" SEARCH_NAMES "vorbis") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisFile" SEARCH_NAMES "vorbisfile") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisEnc" SEARCH_NAMES "vorbisenc") + sfml_bind_dependency(TARGET FLAC FRIENDLY_NAME "FLAC" SEARCH_NAMES "FLAC") + endif() + + if (FIND_SFML_DEPENDENCIES_NOTFOUND) + set(FIND_SFML_ERROR "SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})") + set(SFML_FOUND FALSE) + endif() +endif()