From 2680388a65f8bfbe462968bcf0c8d721e0258dcb Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 26 Apr 2016 18:02:20 -0500 Subject: [PATCH] Squashed 'cmake/' changes from 1cc81cc..0875d12 0875d12 FindSDL2: standardize indentation within the file. 75ba012 FindSDL2: Use MinGWSearchPathExtras if it's available and suitable. 66d7885 MinGW: build a list of prefixes too. 83f169b FindSDL2: sdlmain must come before sdl2. 6d639f6 Update list of dependencies in FindWinHID 2c5bec7 Update WinHID drastically to use FindWindowsSDK, so it can easily build against much newer SDKs/DDKs/WDKs. 2273ac4 Add two new functions to FindWindowsSDK eded907 Fix quietness of finding windows SDK and add comment 3f5f7df Add a module to help find things on MinGW (specifically MSYS2). c90ca93 Backported bugfixed version of WriteCompilerDetectionHeader. 6a941e5 ColibriApi: Module written for VRPN. 1dd3d89 Another flag in ExtraCompilerWarnings, to get GCC to stop whining about boost::optional. 90d1a89 Formatting fix in finddirectshow 8b37b27 Updated the InterSense finder to look in default install locations. bd6a7ca Improvements to the WindowsSDK finder for newer win10 sdks and better handling of them. 58ed198 Add a minor tweak to the VRPN module 83a2091 Add a FindJsonCpp module I wrote for various OSVR projects. faf198f Major improvements to FindSDL2 for Mac support. Thanks to David, aka @d235j for lots of help. fe2273c Add GenerateCompatibilityVersionFile, for keeping your msvc from compiling against your android builds. 01d0c41 Major improvements to FindWindowsSDK and FindDirectShow 16a3a8c Add an upstream "FindGit" from CMake 3.2.0 6bc6a53 Fix up create dashboard scripts to use a shared Git location. git-subtree-dir: cmake git-subtree-split: 0875d124fd6f0a7b775227e1790f17dcf45a7ec6 --- CompatibilityVersionFile-BASIC.cmake.in | 19 + CompatibilityVersionFile-CXX_ABI.cmake.in | 29 + CompatibilityVersionFile-CXX_LAYOUT.cmake.in | 16 + CompatibilityVersionFile-C_ABI.cmake.in | 16 + CreateDashboardScripts.cmake | 21 +- EnableExtraCompilerWarnings.cmake | 9 + FindColibriApi.cmake | 120 +++ FindDirectShow.cmake | 81 +- FindInterSense.cmake | 34 +- FindJsonCpp.cmake | 372 ++++++++++ FindSDL2.cmake | 178 +++-- FindVRPN.cmake | 2 +- FindWinHID.cmake | 191 +++-- FindWindowsSDK.cmake | 627 ++++++++++++---- GenerateCompatibilityVersionFile.cmake | 83 +++ MinGWSearchPathExtras.cmake | 94 +++ cmake-3.2.0-modules/FindGit.cmake | 106 +++ .../WriteCompilerDetectionHeader.cmake | 692 ++++++++++++++++++ 18 files changed, 2406 insertions(+), 284 deletions(-) create mode 100644 CompatibilityVersionFile-BASIC.cmake.in create mode 100644 CompatibilityVersionFile-CXX_ABI.cmake.in create mode 100644 CompatibilityVersionFile-CXX_LAYOUT.cmake.in create mode 100644 CompatibilityVersionFile-C_ABI.cmake.in create mode 100644 FindColibriApi.cmake create mode 100644 FindJsonCpp.cmake create mode 100644 GenerateCompatibilityVersionFile.cmake create mode 100644 MinGWSearchPathExtras.cmake create mode 100644 cmake-3.2.0-modules/FindGit.cmake create mode 100644 cmake-3.3.0-modules/WriteCompilerDetectionHeader.cmake diff --git a/CompatibilityVersionFile-BASIC.cmake.in b/CompatibilityVersionFile-BASIC.cmake.in new file mode 100644 index 000000000..d2b97ba7a --- /dev/null +++ b/CompatibilityVersionFile-BASIC.cmake.in @@ -0,0 +1,19 @@ +# will always be the actual version one +# Wrapped in a macro because it's got a return before we want. +macro(_gcvf_version) + @GCVF_PREVIOUS_FILE@ +endmacro() +_gcvf_version() + + +if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "@CMAKE_SYSTEM_NAME@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_SYSTEM_NAME@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() + +if(ANDROID AND NOT ("${ANDROID_ABI}" STREQUAL "@ANDROID_ABI@")) + set(PACKAGE_VERSION "${PACKAGE_VERSION} (Android @ANDROID_ABI@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() \ No newline at end of file diff --git a/CompatibilityVersionFile-CXX_ABI.cmake.in b/CompatibilityVersionFile-CXX_ABI.cmake.in new file mode 100644 index 000000000..f09043d6a --- /dev/null +++ b/CompatibilityVersionFile-CXX_ABI.cmake.in @@ -0,0 +1,29 @@ +@GCVF_PREVIOUS_FILE@ + +if(MSVC) + if(NOT "${MSVC_VERSION}" STREQUAL "@MSVC_VERSION@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@GCVF_WIN_CXXLAYOUT@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() + endif() +endif() + +macro(_gcvf_compute_cxxabi _var _compilerid _compilerver) + set(${_var}) + if("${_compilerid}" STREQUAL "GNU" AND NOT ("${_compilerver}" STREQUAL "")) + if("${_compilerver}" VER_LESS 5.0) + # This is pre-gcc5, not compatible with post-gcc5 + set(${_var} "g++ < 5.0") + else() + set(${_var} "g++ >= 5.0") + endif() + endif() +endmacro() +_gcvr_compute_cxxabi(_installed_cxx "@CMAKE_CXX_COMPILER_ID@" "@CMAKE_CXX_COMPILER_VERSION@") +_gcvr_compute_cxxabi(_current_cxx "${CMAKE_CXX_COMPILER_ID}" "${CMAKE_CXX_COMPILER_VERSION}") + +# if(NOT "${_installed_cxx}" STREQUAL "${_current_cxx}") +# set(PACKAGE_VERSION "${PACKAGE_VERSION} (${_installed_cxx})") +# set(PACKAGE_VERSION_UNSUITABLE TRUE) +# return() +# endif() diff --git a/CompatibilityVersionFile-CXX_LAYOUT.cmake.in b/CompatibilityVersionFile-CXX_LAYOUT.cmake.in new file mode 100644 index 000000000..8f98a084c --- /dev/null +++ b/CompatibilityVersionFile-CXX_LAYOUT.cmake.in @@ -0,0 +1,16 @@ +@GCVF_PREVIOUS_FILE@ + +set(GCVF_WIN_CXXLAYOUT) +if(MSVC) + set(GCVF_WIN_CXXLAYOUT "MSVC") +elseif(MINGW) + set(GCVF_WIN_CXXLAYOUT "MinGW") +elseif(WIN32) + set(GCVF_WIN_CXXLAYOUT "other") +endif() + +if(NOT "@GCVF_WIN_CXXLAYOUT@" STREQUAL "${GCVF_WIN_CXXLAYOUT}") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@GCVF_WIN_CXXLAYOUT@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() diff --git a/CompatibilityVersionFile-C_ABI.cmake.in b/CompatibilityVersionFile-C_ABI.cmake.in new file mode 100644 index 000000000..656e90ffa --- /dev/null +++ b/CompatibilityVersionFile-C_ABI.cmake.in @@ -0,0 +1,16 @@ +@GCVF_PREVIOUS_FILE@ + +if(NOT ("${CMAKE_C_COMPILER_ABI}" STREQUAL "") AND NOT ("@CMAKE_C_COMPILER_ABI@" STREQUAL "")) + if(NOT "${CMAKE_C_COMPILER_ABI}" STREQUAL "@CMAKE_C_COMPILER_ABI@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_C_COMPILER_ABI@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() + endif() +endif() + +if(NOT "${CMAKE_C_COMPILER_TARGET}" STREQUAL "@CMAKE_C_COMPILER_TARGET@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_C_COMPILER_TARGET@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() +# todo anything for a C ABI beyond just "basic"? \ No newline at end of file diff --git a/CreateDashboardScripts.cmake b/CreateDashboardScripts.cmake index ec1664a55..22420b5b4 100644 --- a/CreateDashboardScripts.cmake +++ b/CreateDashboardScripts.cmake @@ -16,7 +16,8 @@ # Requires these CMake modules: # GetCompilerInfoString # -# Requires CMake 2.6 or newer (uses the 'function' command) +# Requires CMake 2.6 or newer (uses the 'function' command), +# as well as FindGit.cmake (included with 2.8.2, may be backported) # # Original Author: # 2009-2010 Ryan Pavlik @@ -118,13 +119,21 @@ if(NOT IN_DASHBOARD_SCRIPT) if(NOT "1.${CMAKE_VERSION}" VERSION_LESS "1.2.8.0") if(IS_DIRECTORY "${CMAKE_SOURCE_DIRECTORY}/.git") - find_program(DASHBOARDSCRIPT_GIT_EXECUTABLE NAMES git git.cmd) - if(DASHBOARDSCRIPT_GIT_EXECUTABLE) - + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + # If we have a valid git we found ourselves in older version of the module, + # let the regular FindGit module (since 2.8.2) know. + if(DASHBOARDSCRIPT_GIT_EXECUTABLE AND EXISTS "${DASHBOARDSCRIPT_GIT_EXECUTABLE}" AND NOT GIT_FOUND) + set(GIT_EXECUTABLE "${DASHBOARDSCRIPT_GIT_EXECUTABLE}" CACHE FILEPATH "Git executable" FORCE) + find_package(Git QUIET) + endif() + unset(DASHBOARDSCRIPT_GIT_EXECUTABLE) + unset(DASHBOARDSCRIPT_GIT_EXECUTABLE CACHE) + if(GIT_FOUND) set(UPDATE_TYPE "git") - set(UPDATE_COMMAND "${DASHBOARDSCRIPT_GIT_EXECUTABLE}") + set(UPDATE_COMMAND "${GIT_EXECUTABLE}") set(UPDATE_OPTIONS "") - mark_as_advanced(DASHBOARDSCRIPT_GIT_EXECUTABLE) endif() endif() endif() diff --git a/EnableExtraCompilerWarnings.cmake b/EnableExtraCompilerWarnings.cmake index 833172ae1..4c0e5c78d 100644 --- a/EnableExtraCompilerWarnings.cmake +++ b/EnableExtraCompilerWarnings.cmake @@ -50,6 +50,15 @@ macro(_enable_extra_compiler_warnings_flags) set(_flags "${_flags} -Wextra") endif() + if(SUPPORTS_WALL_FLAG) + # At least GCC includes -Wmaybe-uninitialized in -Wall, which + # unneccesarily whines about boost::optional (by it's nature + # it's a "maybe" warning - prone to noisy false-positives) + check_cxx_compiler_flag(-Wno-maybe-uninitialized SUPPORTS_WNO_MAYBE_UNINITIALIZED_FLAG) + if(SUPPORTS_WNO_MAYBE_UNINITIALIZED_FLAG) + set(_flags "${_flags} -Wno-maybe-uninitialized") + endif() + endif() endif() endmacro() diff --git a/FindColibriApi.cmake b/FindColibriApi.cmake new file mode 100644 index 000000000..0d7b4ff36 --- /dev/null +++ b/FindColibriApi.cmake @@ -0,0 +1,120 @@ +# - try to find Trivisio Colibri API library +# +# Cache Variables: +# COLIBRIAPI_LIBRARY +# COLIBRIAPI_INCLUDE_DIR +# +# Non-cache variables you might use in your CMakeLists.txt: +# COLIBRIAPI_FOUND +# COLIBRIAPI_SERVER_LIBRARIES - server libraries +# COLIBRIAPI_LIBRARIES - client libraries +# COLIBRIAPI_CLIENT_DEFINITIONS - definitions if you only use the client library +# COLIBRIAPI_DEFINITIONS - Client-only definition if all we found was the client library. +# COLIBRIAPI_INCLUDE_DIRS +# +# COLIBRIAPI_ROOT_DIR is searched preferentially for these files +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2009-2012 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(COLIBRIAPI_ROOT_DIR + "${COLIBRIAPI_ROOT_DIR}" + CACHE + PATH + "Root directory to search for Colibri API") + +if("${CMAKE_SIZEOF_VOID_P}" MATCHES "8") + set(_libsuffixes lib64 lib) + + # 64-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{ProgramW6432}" _progfiles) +else() + set(_libsuffixes lib) + set(_PF86 "ProgramFiles(x86)") + if(NOT "$ENV{${_PF86}}" STREQUAL "") + # 32-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{${_PF86}}" _progfiles) + else() + # 32-bit dir on win32, useless to us on win64 + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _progfiles) + endif() +endif() + +### +# Configure COLIBRIAPI +### + +find_path(COLIBRIAPI_INCLUDE_DIR + NAMES + colibri_api.h + PATH_SUFFIXES + include + HINTS + "${COLIBRIAPI_ROOT_DIR}" + PATHS + "${_progfiles}/ColibriAPI 1.1.20140925 (64-bit)" + "$ENV{HOME}" + "$ENV{HOME}/ColibriAPI-1.1.20140710-Linux-amd64" + C:/usr/local + /usr/local) + +find_library(COLIBRIAPI_LIBRARY + NAMES + colibri-api + PATH_SUFFIXES + ${_libsuffixes} + HINTS + "${COLIBRIAPI_ROOT_DIR}" + PATHS + "${_progfiles}/ColibriAPI 1.1.20140925 (64-bit)" + "$ENV{HOME}" + "$ENV{HOME}/ColibriAPI-1.1.20140710-Linux-amd64" + C:/usr/local + /usr/local) + +### +# Dependencies +### +set(_deps_libs) +set(_deps_includes) +set(_deps_check) + +find_package(quatlib) +list(APPEND _deps_libs ${QUATLIB_LIBRARIES}) +list(APPEND _deps_includes ${QUATLIB_INCLUDE_DIRS}) +list(APPEND _deps_check QUATLIB_FOUND) + +if(NOT WIN32) + find_package(Threads) + list(APPEND _deps_libs ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND _deps_check CMAKE_HAVE_THREADS_LIBRARY) +endif() + + +# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ColibriApi + DEFAULT_MSG + COLIBRIAPI_LIBRARY + COLIBRIAPI_INCLUDE_DIR + ${_deps_check}) + +if(COLIBRIAPI_FOUND) + set(COLIBRIAPI_INCLUDE_DIRS "${COLIBRIAPI_INCLUDE_DIR}" ${_deps_includes}) + set(COLIBRIAPI_LIBRARIES "${COLIBRIAPI_LIBRARY}" ${_deps_libs}) + + mark_as_advanced(COLIBRIAPI_ROOT_DIR) +endif() + +mark_as_advanced(COLIBRIAPI_LIBRARY COLIBRIAPI_INCLUDE_DIR) diff --git a/FindDirectShow.cmake b/FindDirectShow.cmake index 984056d7c..1756f7080 100644 --- a/FindDirectShow.cmake +++ b/FindDirectShow.cmake @@ -23,7 +23,7 @@ set(_ds_quiet) if(DirectShow_FIND_QUIETLY) - set(_ds_quiet QUIET) + set(_ds_quiet QUIET) endif() find_package(WindowsSDK ${_ds_quiet}) find_package(DirectX ${_ds_quiet}) @@ -71,6 +71,52 @@ find_path(DIRECTSHOW_WINDOWSSDK_INCLUDE_DIR PATH_SUFFIXES "Include") +### +# Begin code dedicated to finding a proper qedit.h file... +### + +# Checks to see if a directory has qedit.h and if that file contains ISampleGrabber. +function(_directshow_check_qedit _dir _var) + set(fn "${_dir}/qedit.h") + if(NOT EXISTS "${fn}") + set(${_var} FALSE PARENT_SCOPE) + return() + endif() + file(STRINGS "${fn}" samplegrabber REGEX ISampleGrabber) + if(NOT samplegrabber) + set(${_var} FALSE PARENT_SCOPE) + return() + endif() + set(${_var} TRUE PARENT_SCOPE) +endfunction() + +function(_directshow_check_current_qedit) + if(DIRECTSHOW_QEDIT_INCLUDE_DIR) + _directshow_check_qedit("${DIRECTSHOW_QEDIT_INCLUDE_DIR}" _ds_ok) + if(NOT _ds_ok) + message(STATUS "FindDirectShow: qedit.h in ${DIRECTSHOW_QEDIT_INCLUDE_DIR} lacks ISampleGrabber, unsetting DIRECTSHOW_QEDIT_INCLUDE_DIR") + set(DIRECTSHOW_QEDIT_INCLUDE_DIR "" CACHE PATH "" FORCE) + endif() + endif() +endfunction() + +# Check before deciding if we should make our list of possible locations. +_directshow_check_current_qedit() + +# Compose a list of possible directories that might hold a qedit.h file. +set(DIRECTSHOW_QEDIT_SEARCH) +if(WINDOWSSDK_FOUND AND NOT DIRECTSHOW_QEDIT_INCLUDE_DIR) + foreach(_sdk ${WINDOWSSDK_DIRS}) + windowssdk_build_lookup("${_sdk}" _build) + if(_build AND ("${_build}" VERSION_LESS 6.2)) + get_windowssdk_include_dirs("${_sdk}" _dirs) + if(_dirs) + list(APPEND DIRECTSHOW_QEDIT_SEARCH ${_dirs}) + endif() + endif() + endforeach() +endif() + # This one we can grab from another SDK version. find_path(DIRECTSHOW_QEDIT_INCLUDE_DIR NAMES @@ -78,17 +124,46 @@ find_path(DIRECTSHOW_QEDIT_INCLUDE_DIR HINTS "${DIRECTSHOW_WINDOWSSDK_ROOT}" PATHS - ${WINDOWSSDK_DIRS} + ${DIRECTSHOW_QEDIT_SEARCH} PATH_SUFFIXES "Include") +# Check if the directory is OK after the search. +_directshow_check_current_qedit() + +# If we didn't find a proper qedit, manually look through the possibilities. +if(NOT DIRECTSHOW_QEDIT_INCLUDE_DIR) + foreach(_dir "${DIRECTSHOW_WINDOWSSDK_ROOT}/Include" ${DIRECTSHOW_QEDIT_SEARCH}) + if(NOT DIRECTSHOW_QEDIT_INCLUDE_DIR) + _directshow_check_qedit("${_dir}" _ds_ok) + if(_ds_ok) + set(DIRECTSHOW_QEDIT_INCLUDE_DIR "${_dir}" CACHE PATH "" FORCE) + endif() + endif() + endforeach() +endif() + +### +# End qedit.h section. +### + +set(DIRECTSHOW_STRMIIDS_SEARCH) +if(WINDOWSSDK_FOUND AND NOT DIRECTSHOW_STRMIIDS_LIBRARY) + foreach(_sdk ${WINDOWSSDK_DIRS}) + get_windowssdk_library_dirs("${_sdk}" _dirs) + message(STATUS "- ${_dirs}") + if(_dirs) + list(APPEND DIRECTSHOW_STRMIIDS_SEARCH ${_dirs}) + endif() + endforeach() +endif() find_library(DIRECTSHOW_STRMIIDS_LIBRARY NAMES strmiids HINTS "${DIRECTSHOW_WINDOWSSDK_ROOT}" PATHS - ${_acceptable_winsdk} + ${DIRECTSHOW_STRMIIDS_SEARCH} PATH_SUFFIXES "Lib${DIRECTSHOW_LIB_SUBDIR}") diff --git a/FindInterSense.cmake b/FindInterSense.cmake index 6edfaa513..855c9a1d2 100644 --- a/FindInterSense.cmake +++ b/FindInterSense.cmake @@ -38,32 +38,42 @@ if(APPLE) set(_ARCH UniversalLib) else() if(CMAKE_SIZEOF_VOID_P MATCHES "8") - set(_ARCH x86_64) + set(_IS_ARCH x86_64) else() - set(_ARCH x86_32) + set(_IS_ARCH x86_32) endif() endif() +set(_IS_INSTALLDIRS) if(APPLE) - set(_SDKDIR MacOSX) + set(_IS_SDKDIR MacOSX) elseif(WIN32) - set(_SDKDIR Windows) + set(_IS_SDKDIR Windows) + # Default locations, as well as registry places it records install locations, + # if you installed from a (actual or downloaded) product "CD" + foreach(_IS_PROD "IS-900 Software" "InertiaCube Software") + get_filename_component(_IS_REGPATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\InterSense\\${_IS_PROD};Path]" ABSOLUTE) + if(_IS_REGPATH AND (NOT "${_IS_REGPATH}" STREQUAL "/registry")) + list(APPEND _IS_INSTALLDIRS "${_IS_REGPATH}/SDK") + endif() + list(APPEND _IS_INSTALLDIRS "C:/InterSense/${_IS_PROD}/SDK") + endforeach() else() # Assume Linux, since that's the only other platform supported by this library - set(_SDKDIR Linux) + set(_IS_SDKDIR Linux) endif() find_path(INTERSENSE_INCLUDE_DIR NAMES isense.h - PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK") + PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK" ${_IS_INSTALLDIRS}) find_path(INTERSENSE_ISENSEC_DIR NAMES isense.c - PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK" + PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK" ${_IS_INSTALLDIRS} PATH_SUFFIXES - Linux/Sample - MacOSX/Sample "Windows/Sample/Visual C++ 2005" - "Windows/Sample/Visual C++ 2005 (single tracker)") + "Windows/Sample/Visual C++ 2005 (single tracker)" + Linux/Sample + MacOSX/Sample) include(FindPackageHandleStandardArgs) @@ -81,8 +91,8 @@ if(WIN32) else() # Only MSVC on Windows theoretically needs import libraries, so... find_library(INTERSENSE_LIBRARY NAMES isense - PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK" - PATH_SUFFIXES "${_SDKDIR}/${_ARCH}") + PATHS "${INTERSENSE_ROOT_DIR}" "${INTERSENSE_ROOT_DIR}/SDK" ${_IS_INSTALLDIRS} + PATH_SUFFIXES "${_IS_SDKDIR}/${_IS_ARCH}") find_package_handle_standard_args(InterSense DEFAULT_MSG diff --git a/FindJsonCpp.cmake b/FindJsonCpp.cmake new file mode 100644 index 000000000..a62564757 --- /dev/null +++ b/FindJsonCpp.cmake @@ -0,0 +1,372 @@ +# - Find jsoncpp - Overarching find module +# This is a over-arching find module to find older jsoncpp versions and those sadly built +# without JSONCPP_WITH_CMAKE_PACKAGE=ON, as well as those built with the cmake config file. +# It also wraps the different versions of the module. +# +# On CMake 3.0 and newer: +# JsonCpp::JsonCpp - Imported target (possibly an interface/alias) to use: +# if anything is populated, this is. If both shared and static are found, then +# this will be the static version on DLL platforms and shared on non-DLL platforms. +# JsonCpp::JsonCppShared - Imported target (possibly an interface/alias) for a +# shared library version. +# JsonCpp::JsonCppStatic - Imported target (possibly an interface/alias) for a +# static library version. +# +# On all CMake versions: (Note that on CMake 2.8.10 and earlier, you may need to use JSONCPP_INCLUDE_DIRS) +# JSONCPP_LIBRARY - wraps JsonCpp::JsonCpp or equiv. +# JSONCPP_LIBRARY_IS_SHARED - if we know for sure JSONCPP_LIBRARY is shared, this is true-ish. We try to "un-set" it if we don't know one way or another. +# JSONCPP_LIBRARY_SHARED - wraps JsonCpp::JsonCppShared or equiv. +# JSONCPP_LIBRARY_STATIC - wraps JsonCpp::JsonCppStatic or equiv. +# JSONCPP_INCLUDE_DIRS - Include directories - should (generally?) not needed if you require CMake 2.8.11+ since it handles target include directories. +# +# JSONCPP_FOUND - True if JsonCpp was found. +# +# Original Author: +# 2016 Ryan Pavlik +# Incorporates work from the module contributed to VRPN under the same license: +# 2011 Philippe Crassous (ENSAM ParisTech / Institut Image) p.crassous _at_ free.fr +# +# Copyright Philippe Crassous 2011. +# Copyright Sensics, Inc. 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(__jsoncpp_have_namespaced_targets OFF) +set(__jsoncpp_have_interface_support OFF) +if(NOT ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 3.0)) + set(__jsoncpp_have_namespaced_targets ON) + set(__jsoncpp_have_interface_support ON) +elseif(("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" EQUAL 2.8) AND "${CMAKE_PATCH_VERSION}" GREATER 10) + set(__jsoncpp_have_interface_support ON) +endif() + +# sets __jsoncpp_have_jsoncpplib based on whether or not we have a real imported jsoncpp_lib target. +macro(_jsoncpp_check_for_real_jsoncpplib) + set(__jsoncpp_have_jsoncpplib FALSE) + if(TARGET jsoncpp_lib) + get_property(__jsoncpp_lib_type TARGET jsoncpp_lib PROPERTY TYPE) + #message(STATUS "__jsoncpp_lib_type ${__jsoncpp_lib_type}") + # We make interface libraries. If an actual config module made it, it would be an imported library. + if(NOT __jsoncpp_lib_type STREQUAL "INTERFACE_LIBRARY") + #message("have jsoncpp_lib and we didn't invent it ourselves") + set(__jsoncpp_have_jsoncpplib TRUE) + endif() + endif() +endmacro() + +include(FindPackageHandleStandardArgs) +# Ensure that if this is TRUE later, it's because we set it. +set(JSONCPP_FOUND FALSE) + +# See if we find a CMake config file - there is no harm in calling this more than once, +# and we need to call it at least once every CMake invocation to create the original +# imported targets, since those don't stick around like cache variables. +find_package(jsoncpp QUIET NO_MODULE) + +if(jsoncpp_FOUND) + # Build a string to help us figure out when to invalidate our cache variables. + # start with where we found jsoncpp + set(__jsoncpp_info_string "[${jsoncpp_DIR}]") + + # part of the string to indicate if we found a real jsoncpp_lib (and what kind) + _jsoncpp_check_for_real_jsoncpplib() + if(__jsoncpp_have_jsoncpplib) + list(APPEND __jsoncpp_info_string "[${__jsoncpp_lib_type}]") + else() + list(APPEND __jsoncpp_info_string "[]") + endif() + # part of the string to indicate if we found jsoncpp_lib_static + if(TARGET jsoncpp_lib_static) + list(APPEND __jsoncpp_info_string "[T]") + else() + list(APPEND __jsoncpp_info_string "[]") + endif() +endif() + + +# If we found something, and it's not the exact same as what we've found before... +# NOTE: The contents of this "if" block update only (internal) cache variables! +# (since this will only get run the first CMake pass that finds jsoncpp or that finds a different/updated install) +if(jsoncpp_FOUND AND NOT __jsoncpp_info_string STREQUAL "${JSONCPP_CACHED_JSONCPP_DIR_DETAILS}") + #message("Updating jsoncpp cache variables! ${__jsoncpp_info_string}") + set(JSONCPP_CACHED_JSONCPP_DIR_DETAILS "${__jsoncpp_info_string}" CACHE INTERNAL "" FORCE) + unset(JSONCPP_IMPORTED_LIBRARY_SHARED) + unset(JSONCPP_IMPORTED_LIBRARY_STATIC) + unset(JSONCPP_IMPORTED_LIBRARY) + unset(JSONCPP_IMPORTED_INCLUDE_DIRS) + unset(JSONCPP_IMPORTED_LIBRARY_IS_SHARED) + + # if(__jsoncpp_have_jsoncpplib) is equivalent to if(TARGET jsoncpp_lib) except it excludes our + # "invented" jsoncpp_lib interface targets, made for convenience purposes after this block. + + if(__jsoncpp_have_jsoncpplib AND TARGET jsoncpp_lib_static) + + # A veritable cache of riches - we have both shared and static! + set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) + if(WIN32 OR CYGWIN OR MINGW) + # DLL platforms: static library should be default + set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_STATIC} CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) + else() + # Other platforms - might require PIC to be linked into shared libraries, so safest to prefer shared. + set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_SHARED} CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE) + endif() + + elseif(TARGET jsoncpp_lib_static) + # Well, only one variant, but we know for sure that it's static. + set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib_static CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) + + elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "STATIC_LIBRARY") + # We were able to figure out the mystery library is static! + set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) + + elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "SHARED_LIBRARY") + # We were able to figure out the mystery library is shared! + set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE) + + elseif(__jsoncpp_have_jsoncpplib) + # One variant, and we have no idea if this is just an old version or if + # this is shared based on the target name alone. Hmm. + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) + endif() + + # Now, we need include directories. Can't just limit this to old CMakes, since + # new CMakes might be used to build projects designed to support older ones. + if(__jsoncpp_have_jsoncpplib) + get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + if(__jsoncpp_interface_include_dirs) + set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + endif() + endif() + if(TARGET jsoncpp_lib_static AND NOT JSONCPP_IMPORTED_INCLUDE_DIRS) + get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + if(__jsoncpp_interface_include_dirs) + set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + endif() + endif() +endif() + +# As a convenience... +if(TARGET jsoncpp_lib_static AND NOT TARGET jsoncpp_lib) + add_library(jsoncpp_lib INTERFACE) + target_link_libraries(jsoncpp_lib INTERFACE jsoncpp_lib_static) +endif() + +if(JSONCPP_IMPORTED_LIBRARY) + if(NOT JSONCPP_IMPORTED_INCLUDE_DIRS) + # OK, so we couldn't get it from the target... maybe we can figure it out from jsoncpp_DIR. + + # take off the jsoncpp component + get_filename_component(__jsoncpp_import_root "${jsoncpp_DIR}/.." ABSOLUTE) + set(__jsoncpp_hints "${__jsoncpp_import_root}") + # take off the cmake component + get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE) + list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}") + # take off the lib component + get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE) + list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}") + # take off one more component in case of multiarch lib + get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE) + list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}") + + # Now, search. + find_path(JsonCpp_INCLUDE_DIR + NAMES + json/json.h + PATH_SUFFIXES include jsoncpp include/jsoncpp + HINTS ${__jsoncpp_hints}) + if(JsonCpp_INCLUDE_DIR) + mark_as_advanced(JsonCpp_INCLUDE_DIR) + # Note - this does not set it in the cache, in case we find it better at some point in the future! + set(JSONCPP_IMPORTED_INCLUDE_DIRS ${JsonCpp_INCLUDE_DIR}) + endif() + endif() + + find_package_handle_standard_args(JsonCpp + DEFAULT_MSG + jsoncpp_DIR + JSONCPP_IMPORTED_LIBRARY + JSONCPP_IMPORTED_INCLUDE_DIRS) +endif() + +if(JSONCPP_FOUND) + # Create any missing namespaced targets from the config module. + if(__jsoncpp_have_namespaced_targets) + if(JSONCPP_IMPORTED_LIBRARY AND NOT TARGET JsonCpp::JsonCpp) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY}") + endif() + + if(JSONCPP_IMPORTED_LIBRARY_SHARED AND NOT TARGET JsonCpp::JsonCppShared) + add_library(JsonCpp::JsonCppShared INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCppShared PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY_SHARED}") + endif() + + if(JSONCPP_IMPORTED_LIBRARY_STATIC AND NOT TARGET JsonCpp::JsonCppStatic) + add_library(JsonCpp::JsonCppStatic INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCppStatic PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY_STATIC}") + endif() + + # Hide the stuff we didn't, and no longer, need. + if(NOT JsonCpp_LIBRARY) + unset(JsonCpp_LIBRARY CACHE) + endif() + if(NOT JsonCpp_INCLUDE_DIR) + unset(JsonCpp_INCLUDE_DIR CACHE) + endif() + endif() + + set(JSONCPP_LIBRARY ${JSONCPP_IMPORTED_LIBRARY}) + set(JSONCPP_INCLUDE_DIRS ${JSONCPP_IMPORTED_INCLUDE_DIRS}) + if(DEFINED JSONCPP_IMPORTED_LIBRARY_IS_SHARED) + set(JSONCPP_LIBRARY_IS_SHARED ${JSONCPP_IMPORTED_LIBRARY_IS_SHARED}) + else() + unset(JSONCPP_LIBRARY_IS_SHARED) + endif() + + if(JSONCPP_IMPORTED_LIBRARY_SHARED) + set(JSONCPP_LIBRARY_SHARED ${JSONCPP_IMPORTED_LIBRARY_SHARED}) + endif() + + if(JSONCPP_IMPORTED_LIBRARY_STATIC) + set(JSONCPP_LIBRARY_STATIC ${JSONCPP_IMPORTED_LIBRARY_STATIC}) + endif() +endif() + +# Still nothing after looking for the config file: must go "old-school" +if(NOT JSONCPP_FOUND) + # Invoke pkgconfig for hints + find_package(PkgConfig QUIET) + set(_JSONCPP_INCLUDE_HINTS) + set(_JSONCPP_LIB_HINTS) + if(PKG_CONFIG_FOUND) + pkg_search_module(_JSONCPP_PC QUIET jsoncpp) + if(_JSONCPP_PC_INCLUDE_DIRS) + set(_JSONCPP_INCLUDE_HINTS ${_JSONCPP_PC_INCLUDE_DIRS}) + endif() + if(_JSONCPP_PC_LIBRARY_DIRS) + set(_JSONCPP_LIB_HINTS ${_JSONCPP_PC_LIBRARY_DIRS}) + endif() + if(_JSONCPP_PC_LIBRARIES) + set(_JSONCPP_LIB_NAMES ${_JSONCPP_PC_LIBRARIES}) + endif() + endif() + + if(NOT _JSONCPP_LIB_NAMES) + # OK, if pkg-config wasn't able to give us a library name suggestion, then we may + # have to resort to some intense old logic. + set(_JSONCPP_LIB_NAMES jsoncpp) + set(_JSONCPP_PATHSUFFIXES) + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND _JSONCPP_PATHSUFFIXES + linux-gcc) # bit of a generalization but close... + endif() + if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND + _JSONCPP_LIB_NAMES + json_linux-gcc-${CMAKE_CXX_COMPILER_VERSION}_libmt + json_linux-gcc_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES + linux-gcc-${CMAKE_CXX_COMPILER_VERSION}) + + elseif(MSVC) + if(MSVC_VERSION EQUAL 1200) + list(APPEND _JSONCPP_LIB_NAMES json_vc6_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc6) + elseif(MSVC_VERSION EQUAL 1300) + list(APPEND _JSONCPP_LIB_NAMES json_vc7_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc7) + elseif(MSVC_VERSION EQUAL 1310) + list(APPEND _JSONCPP_LIB_NAMES json_vc71_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc71) + elseif(MSVC_VERSION EQUAL 1400) + list(APPEND _JSONCPP_LIB_NAMES json_vc8_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc80) + elseif(MSVC_VERSION EQUAL 1500) + list(APPEND _JSONCPP_LIB_NAMES json_vc9_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc90) + elseif(MSVC_VERSION EQUAL 1600) + list(APPEND _JSONCPP_LIB_NAMES json_vc10_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES msvc10 msvc100) + endif() + + elseif(MINGW) + list(APPEND _JSONCPP_LIB_NAMES + json_mingw_libmt) + list(APPEND _JSONCPP_PATHSUFFIXES mingw) + + else() + list(APPEND _JSONCPP_LIB_NAMES + json_suncc_libmt + json_vacpp_libmt) + endif() + endif() # end of old logic + + # Actually go looking. + find_path(JsonCpp_INCLUDE_DIR + NAMES + json/json.h + PATH_SUFFIXES jsoncpp + HINTS ${_JSONCPP_INCLUDE_HINTS}) + find_library(JsonCpp_LIBRARY + NAMES + ${_JSONCPP_LIB_NAMES} + PATHS libs + PATH_SUFFIXES ${_JSONCPP_PATHSUFFIXES} + HINTS ${_JSONCPP_LIB_HINTS}) + + find_package_handle_standard_args(JsonCpp + DEFAULT_MSG + JsonCpp_INCLUDE_DIR + JsonCpp_LIBRARY) + + if(JSONCPP_FOUND) + # We already know that the target doesn't exist, let's make it. + # TODO don't know why we get errors like: + # error: 'JsonCpp::JsonCpp-NOTFOUND', needed by 'bin/osvr_json_to_c', missing and no known rule to make it + # when we do the imported target commented out below. So, instead, we make an interface + # target with an alias. Hmm. + + #add_library(JsonCpp::JsonCpp UNKNOWN IMPORTED) + #set_target_properties(JsonCpp::JsonCpp PROPERTIES + # IMPORTED_LOCATION "${JsonCpp_LIBRARY}" + # INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIR}" + # IMPORTED_LINK_INTERFACE_LANGUAGES "CXX") + + set(JSONCPP_LIBRARY "${JsonCpp_LIBRARY}") + set(JSONCPP_INCLUDE_DIRS "${JsonCpp_INCLUDE_DIR}") + unset(JSONCPP_LIBRARY_IS_SHARED) + + if(__jsoncpp_have_interface_support AND NOT TARGET jsoncpp_interface) + add_library(jsoncpp_interface INTERFACE) + set_target_properties(jsoncpp_interface PROPERTIES + INTERFACE_LINK_LIBRARIES "${JsonCpp_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIR}") + endif() + if(__jsoncpp_have_namespaced_targets) + if(NOT TARGET JsonCpp::JsonCpp) + add_library(JsonCpp::JsonCpp ALIAS jsoncpp_interface) + endif() + endif() + endif() +endif() + +if(JSONCPP_FOUND) + mark_as_advanced(jsoncpp_DIR JsonCpp_INCLUDE_DIR JsonCpp_LIBRARY) +endif() diff --git a/FindSDL2.cmake b/FindSDL2.cmake index 68e395851..f69c68a13 100644 --- a/FindSDL2.cmake +++ b/FindSDL2.cmake @@ -16,18 +16,25 @@ # Set up architectures (for windows) and prefixes (for mingw builds) if(WIN32) + if(MINGW) + include(MinGWSearchPathExtras OPTIONAL) + if(MINGWSEARCH_TARGET_TRIPLE) + set(SDL2_PREFIX ${MINGWSEARCH_TARGET_TRIPLE}) + endif() + endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(SDL2_LIB_PATH_SUFFIX lib/x64) - if(NOT MSVC) + if(NOT MSVC AND NOT SDL2_PREFIX) set(SDL2_PREFIX x86_64-w64-mingw32) endif() else() set(SDL2_LIB_PATH_SUFFIX lib/x86) - if(NOT MSVC) + if(NOT MSVC AND NOT SDL2_PREFIX) set(SDL2_PREFIX i686-w64-mingw32) endif() endif() endif() + if(SDL2_PREFIX) set(SDL2_ORIGPREFIXPATH ${CMAKE_PREFIX_PATH}) if(SDL2_ROOT_DIR) @@ -38,6 +45,9 @@ if(SDL2_PREFIX) list(APPEND CMAKE_PREFIX_PATH "${_prefix}/${SDL2_PREFIX}") endforeach() endif() + if(MINGWSEARCH_PREFIXES) + list(APPEND CMAKE_PREFIX_PATH ${MINGWSEARCH_PREFIXES}) + endif() endif() # Invoke pkgconfig for hints @@ -56,24 +66,51 @@ endif() include(FindPackageHandleStandardArgs) -find_path(SDL2_INCLUDE_DIR +find_library(SDL2_LIBRARY NAMES - SDL_haptic.h # this file was introduced with SDL2 + SDL2 HINTS - ${SDL2_INCLUDE_HINTS} + ${SDL2_LIB_HINTS} PATHS ${SDL2_ROOT_DIR} ENV SDL2DIR - PATH_SUFFIXES include include/sdl2) -find_library(SDL2_LIBRARY + PATH_SUFFIXES lib SDL2 ${SDL2_LIB_PATH_SUFFIX}) + +set(_sdl2_framework FALSE) +# Some special-casing if we've found/been given a framework. +# Handles whether we're given the library inside the framework or the framework itself. +if(APPLE AND "${SDL2_LIBRARY}" MATCHES "(/[^/]+)*.framework(/.*)?$") + set(_sdl2_framework TRUE) + set(SDL2_FRAMEWORK "${SDL2_LIBRARY}") + # Move up in the directory tree as required to get the framework directory. + while("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework(/.*)$" AND NOT "${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$") + get_filename_component(SDL2_FRAMEWORK "${SDL2_FRAMEWORK}" DIRECTORY) + endwhile() + if("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$") + set(SDL2_FRAMEWORK_NAME ${CMAKE_MATCH_1}) + # If we found a framework, do a search for the header ahead of time that will be more likely to get the framework header. + find_path(SDL2_INCLUDE_DIR + NAMES + SDL_haptic.h # this file was introduced with SDL2 + HINTS + "${SDL2_FRAMEWORK}/Headers/") + else() + # For some reason we couldn't get the framework directory itself. + # Shouldn't happen, but might if something is weird. + unset(SDL2_FRAMEWORK) + endif() +endif() + +find_path(SDL2_INCLUDE_DIR NAMES - SDL2 + SDL_haptic.h # this file was introduced with SDL2 HINTS - ${SDL2_LIB_HINTS} + ${SDL2_INCLUDE_HINTS} PATHS ${SDL2_ROOT_DIR} ENV SDL2DIR - PATH_SUFFIXES lib ${SDL2_LIB_PATH_SUFFIX}) + PATH_SUFFIXES include include/sdl2 include/SDL2 SDL2) + if(WIN32 AND SDL2_LIBRARY) find_file(SDL2_RUNTIME_LIBRARY NAMES @@ -87,7 +124,8 @@ if(WIN32 AND SDL2_LIBRARY) PATH_SUFFIXES bin lib ${SDL2_LIB_PATH_SUFFIX}) endif() -if(WIN32 OR ANDROID OR IOS) + +if(WIN32 OR ANDROID OR IOS OR (APPLE AND NOT _sdl2_framework)) set(SDL2_EXTRA_REQUIRED SDL2_SDLMAIN_LIBRARY) find_library(SDL2_SDLMAIN_LIBRARY NAMES @@ -98,7 +136,6 @@ if(WIN32 OR ANDROID OR IOS) PATH_SUFFIXES lib ${SDL2_LIB_PATH_SUFFIX}) endif() - if(MINGW AND NOT SDL2PC_FOUND) find_library(SDL2_MINGW_LIBRARY mingw32) find_library(SDL2_MWINDOWS_LIBRARY mwindows) @@ -119,55 +156,87 @@ find_package_handle_standard_args(SDL2 ${SDL2_EXTRA_REQUIRED}) if(SDL2_FOUND) - if(WIN32 AND SDL2_RUNTIME_LIBRARY) - set(SDL2_DYNAMIC TRUE) - add_library(SDL2::SDL2 SHARED IMPORTED) - set_target_properties(SDL2::SDL2 - PROPERTIES - IMPORTED_IMPLIB "${SDL2_LIBRARY}" - IMPORTED_LOCATION "${SDL2_RUNTIME_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}" - ) - else() - add_library(SDL2::SDL2 STATIC IMPORTED) - set_target_properties(SDL2::SDL2 - PROPERTIES - IMPORTED_LOCATION "${SDL2_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}" - ) - endif() - add_library(SDL2::SDL2main INTERFACE IMPORTED) - set(SDL2MAIN_LIBRARIES SDL2::SDL2) - if(SDL2_SDLMAIN_LIBRARY) - add_library(SDL2::SDL2main_real STATIC IMPORTED) - set_target_properties(SDL2::SDL2main_real - PROPERTIES - IMPORTED_LOCATION "${SDL2_SDLMAIN_LIBRARY}") - list(APPEND SDL2MAIN_LIBRARIES SDL2::SDL2main_real) - endif() - if(MINGW) - # MinGW requires some additional libraries to appear earlier in the link line. - if(SDL2PC_LIBRARIES) - # Use pkgconfig-suggested extra libraries if available. - list(REMOVE_ITEM SDL2PC_LIBRARIES SDL2main SDL2) - set(SDL2MAIN_LIBRARIES ${SDL2PC_LIBRARIES} ${SDL2MAIN_LIBRARIES}) + if(NOT TARGET SDL2::SDL2) + # Create SDL2::SDL2 + if(WIN32 AND SDL2_RUNTIME_LIBRARY) + set(SDL2_DYNAMIC TRUE) + add_library(SDL2::SDL2 SHARED IMPORTED) + set_target_properties(SDL2::SDL2 + PROPERTIES + IMPORTED_IMPLIB "${SDL2_LIBRARY}" + IMPORTED_LOCATION "${SDL2_RUNTIME_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}" + ) else() - # fall back to extra libraries specified in pkg-config in - # an official binary distro of SDL2 for MinGW I downloaded - if(SDL2_MINGW_LIBRARY) - set(SDL2MAIN_LIBRARIES ${SDL2_MINGW_LIBRARY} ${SDL2MAIN_LIBRARIES}) + add_library(SDL2::SDL2 UNKNOWN IMPORTED) + if(SDL2_FRAMEWORK AND SDL2_FRAMEWORK_NAME) + # Handle the case that SDL2 is a framework and we were able to decompose it above. + set_target_properties(SDL2::SDL2 PROPERTIES + IMPORTED_LOCATION "${SDL2_FRAMEWORK}/${SDL2_FRAMEWORK_NAME}") + elseif(_sdl2_framework AND SDL2_LIBRARY MATCHES "(/[^/]+)*.framework$") + # Handle the case that SDL2 is a framework and SDL_LIBRARY is just the framework itself. + + # This takes the basename of the framework, without the extension, + # and sets it (as a child of the framework) as the imported location for the target. + # This is the library symlink inside of the framework. + set_target_properties(SDL2::SDL2 PROPERTIES + IMPORTED_LOCATION "${SDL2_LIBRARY}/${CMAKE_MATCH_1}") + else() + # Handle non-frameworks (including non-Mac), as well as the case that we're given the library inside of the framework + set_target_properties(SDL2::SDL2 PROPERTIES + IMPORTED_LOCATION "${SDL2_LIBRARY}") + endif() + set_target_properties(SDL2::SDL2 + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}" + ) + endif() + + if(APPLE) + # Need Cocoa here, is always a framework + find_library(SDL2_COCOA_LIBRARY Cocoa) + list(APPEND SDL2_EXTRA_REQUIRED SDL2_COCOA_LIBRARY) + if(SDL2_COCOA_LIBRARY) + set_target_properties(SDL2::SDL2 PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES ${SDL2_COCOA_LIBRARY}) endif() - if(SDL2_MWINDOWS_LIBRARY) - set(SDL2MAIN_LIBRARIES ${SDL2_MWINDOWS_LIBRARY} ${SDL2MAIN_LIBRARIES}) + endif() + + + # Compute what to do with SDL2main + set(SDL2MAIN_LIBRARIES SDL2::SDL2) + add_library(SDL2::SDL2main INTERFACE IMPORTED) + if(SDL2_SDLMAIN_LIBRARY) + add_library(SDL2::SDL2main_real STATIC IMPORTED) + set_target_properties(SDL2::SDL2main_real + PROPERTIES + IMPORTED_LOCATION "${SDL2_SDLMAIN_LIBRARY}") + set(SDL2MAIN_LIBRARIES SDL2::SDL2main_real ${SDL2MAIN_LIBRARIES}) + endif() + if(MINGW) + # MinGW requires some additional libraries to appear earlier in the link line. + if(SDL2PC_LIBRARIES) + # Use pkgconfig-suggested extra libraries if available. + list(REMOVE_ITEM SDL2PC_LIBRARIES SDL2main SDL2) + set(SDL2MAIN_LIBRARIES ${SDL2PC_LIBRARIES} ${SDL2MAIN_LIBRARIES}) + else() + # fall back to extra libraries specified in pkg-config in + # an official binary distro of SDL2 for MinGW I downloaded + if(SDL2_MINGW_LIBRARY) + set(SDL2MAIN_LIBRARIES ${SDL2_MINGW_LIBRARY} ${SDL2MAIN_LIBRARIES}) + endif() + if(SDL2_MWINDOWS_LIBRARY) + set(SDL2MAIN_LIBRARIES ${SDL2_MWINDOWS_LIBRARY} ${SDL2MAIN_LIBRARIES}) + endif() endif() + set_target_properties(SDL2::SDL2main + PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "main=SDL_main") endif() set_target_properties(SDL2::SDL2main PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "main=SDL_main") + INTERFACE_LINK_LIBRARIES "${SDL2MAIN_LIBRARIES}") endif() - set_target_properties(SDL2::SDL2main - PROPERTIES - INTERFACE_LINK_LIBRARIES "${SDL2MAIN_LIBRARIES}") mark_as_advanced(SDL2_ROOT_DIR) endif() @@ -175,5 +244,6 @@ mark_as_advanced(SDL2_LIBRARY SDL2_RUNTIME_LIBRARY SDL2_INCLUDE_DIR SDL2_SDLMAIN_LIBRARY + SDL2_COCOA_LIBRARY SDL2_MINGW_LIBRARY SDL2_MWINDOWS_LIBRARY) diff --git a/FindVRPN.cmake b/FindVRPN.cmake index 8efa3193d..641b62b70 100644 --- a/FindVRPN.cmake +++ b/FindVRPN.cmake @@ -116,7 +116,7 @@ if(NOT WIN32) endif() if(WIN32) - find_package(Libusb1 ${_vrpn_quiet}) + find_package(Libusb1 QUIET) if(LIBUSB1_FOUND) list(APPEND _deps_libs ${LIBUSB1_LIBRARIES}) list(APPEND _deps_includes ${LIBUSB1_INCLUDE_DIRS}) diff --git a/FindWinHID.cmake b/FindWinHID.cmake index 4445c0dac..7dd057214 100644 --- a/FindWinHID.cmake +++ b/FindWinHID.cmake @@ -14,6 +14,8 @@ # FindPackageHandleStandardArgs (known included with CMake >=2.6.2) # PrefixListGlob # CleanDirectoryList +# MinGWSearchPathExtras +# FindWindowsSDK # # Original Author: # 2009-2010 Ryan Pavlik @@ -31,28 +33,40 @@ if(NOT WIN32) WIN32) return() endif() + if(MSVC) if( (NOT WINHID_ROOT_DIR) AND (NOT ENV{DDKROOT} STREQUAL "") ) set(WINHID_ROOT_DIR "$ENV{DDKROOT}") endif() endif() + set(WINHID_ROOT_DIR "${WINHID_ROOT_DIR}" CACHE PATH "Directory to search") -if(CMAKE_SIZEOF_VOID_P MATCHES "8") - set(_arch amd64) # what the architecture used to be called - set(_arch8 x64) # what the WDK for Win8+ calls this architecture -else() - set(_arch i386) # what the architecture used to be called - set(_arch8 x86) # what the WDK for Win8+ calls this architecture -endif() - set(_deps_check) set(_need_crt_dir) if(MSVC) + + find_package(WindowsSDK) + set(WINSDK_LIBDIRS) + if(WINDOWSSDK_FOUND) + get_windowssdk_library_dirs_multiple(WINSDK_LIBDIRS ${WINDOWSSDK_PREFERRED_FIRST_DIRS}) + foreach(WINSDKDIR ${WINDOWSSDK_DIRS}) + get_windowssdk_library_dirs(${WINSDKDIR} WINSDK_CURRENT_LIBDIRS) + list(APPEND WINSDK_LIBDIRS ${WINSDK_CURRENT_LIBDIRS}) + endforeach() + endif() + + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + set(_arch amd64) # what the architecture used to be called + set(_arch8 x64) # what the WDK for Win8+ calls this architecture + else() + set(_arch i386) # what the architecture used to be called + set(_arch8 x86) # what the WDK for Win8+ calls this architecture + endif() include(PrefixListGlob) include(CleanDirectoryList) prefix_list_glob(_prefixed @@ -65,8 +79,9 @@ if(MSVC) NAMES hid libhid - HINTS + PATHS "${WINHID_ROOT_DIR}" + ${WINSDK_LIBDIRS} ${_prefixed} PATH_SUFFIXES "lib/w2k/${_arch}" # Win2k min requirement @@ -81,34 +96,65 @@ if(MSVC) ) # Might want to look close to the library first for the includes. if(WINHID_LIBRARY) + get_filename_component(WINHID_LIBRARY_DIR "${WINHID_LIBRARY}" PATH) + if(WINDOWSSDK_FOUND) + get_windowssdk_from_component("${WINHID_LIBRARY}" _USED_WINSDK) + set(WINHID_LIBRARY_FROM_WINDOWSSDK ON) + get_windowssdk_include_dirs(${_USED_WINSDK} WINHID_INCLUDE_HINTS) + endif() + endif() + + find_library(WINHID_SETUPAPI_LIBRARY + NAMES + setupapi + HINTS + "${WINHID_LIBRARY_DIR}" + PATHS + "${WINHID_ROOT_DIR}" + ${WINSDK_LIBDIRS} + ${_prefixed} + PATH_SUFFIXES + "lib/w2k/${_arch}" # Win2k min requirement + "lib/wxp/${_arch}" # WinXP min requirement + "lib/wnet/${_arch}" # Win Server 2003 min requirement + "lib/wlh/${_arch}" # Win Vista ("Long Horn") min requirement + "lib/wlh/um/${_arch8}" # Win Vista ("Long Horn") min requirement + "lib/win7/${_arch}" # Win 7 min requirement + "lib/win7/um/${_arch8}" # Win 7 min requirement + "lib/win8/${_arch}" # Win 8 min requirement + "lib/win8/um/${_arch8}" # Win 8 min requirement + ) + + if(WINHID_LIBRARY AND NOT WINHID_LIBRARY_FROM_WINDOWSSDK) + set(_basedir "${WINHID_LIBRARY_DIR}") set(_prevdir) - get_filename_component(_basedir "${WINHID_LIBRARY}" PATH) while(NOT IS_DIRECTORY "${_basedir}/lib" AND NOT (_basedir STREQUAL _prevdir)) set(_prevdir "${_basedir}") get_filename_component(_basedir "${_basedir}/.." ABSOLUTE) endwhile() - endif() - if(WINHID_LIBRARY AND EXISTS "${_basedir}/inc") - find_path(WINHID_CRT_INCLUDE_DIR # otherwise you get weird compile errors - NAMES - stdio.h - HINTS - "${_basedir}" - PATHS - "${WINHID_ROOT_DIR}" - PATH_SUFFIXES - inc/crt - NO_DEFAULT_PATH) - list(APPEND _deps_check WINHID_CRT_INCLUDE_DIR) - set(_need_crt_dir ON) - endif() + set(WINHID_INCLUDE_HINTS "${_basedir}") + if(EXISTS "${_basedir}/inc") + find_path(WINHID_CRT_INCLUDE_DIR # otherwise you get weird compile errors + NAMES + stdio.h + HINTS + "${_basedir}" + PATHS + "${WINHID_ROOT_DIR}" + PATH_SUFFIXES + inc/crt + NO_DEFAULT_PATH) + list(APPEND _deps_check WINHID_CRT_INCLUDE_DIR) + set(_need_crt_dir ON) + endif() + endif() find_path(WINHID_INCLUDE_DIR NAMES hidsdi.h HINTS - "${_basedir}" + ${WINHID_INCLUDE_HINTS} PATHS "${WINHID_ROOT_DIR}" PATH_SUFFIXES @@ -119,20 +165,58 @@ if(MSVC) inc/wnet include/shared) else() - find_library(WINHID_LIBRARY - NAMES - libhid - HINTS - "${WINHID_ROOT_DIR}" - /mingw - PATH_SUFFIXES - lib - lib/w32api) + # This is the non-MSVC path. + if(MINGW) + include(MinGWSearchPathExtras) + + find_library(WINHID_LIBRARY + NAMES + libhid + HINTS + "${WINHID_ROOT_DIR}" + ${MINGWSEARCH_LIBRARY_DIRS} + /mingw + PATH_SUFFIXES + lib + lib/w32api) + find_library(WINHID_SETUPAPI_LIBRARY + NAMES + libsetupapi + HINTS + "${WINHID_ROOT_DIR}" + ${MINGWSEARCH_LIBRARY_DIRS} + /mingw + PATH_SUFFIXES + lib + lib/w32api) + else() + find_library(WINHID_LIBRARY + NAMES + hid + libhid + HINTS + "${WINHID_ROOT_DIR}" + /mingw + PATH_SUFFIXES + lib + lib/w32api) + find_library(WINHID_SETUPAPI_LIBRARY + NAMES + setupapi + libsetupapi + HINTS + "${WINHID_ROOT_DIR}" + /mingw + PATH_SUFFIXES + lib + lib/w32api) + endif() find_path(WINHID_INCLUDE_DIR NAMES hidsdi.h PATHS "${WINHID_ROOT_DIR}" + ${MINGWSEARCH_INCLUDE_DIRS} /mingw PATH_SUFFIXES include/w32api/ddk @@ -144,34 +228,49 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(WinHID DEFAULT_MSG WINHID_LIBRARY + WINHID_SETUPAPI_LIBRARY WINHID_INCLUDE_DIR ${_deps_check}) if(WINHID_FOUND) if(MSVC) - set(_winreq "Unknown") - if(WINHID_LIBRARY MATCHES "lib/w2k") + set(_winreq) + if(WINHID_LIBRARY MATCHES "[Ll]ib/w2k") set(_winreq "Windows 2000") - elseif(WINHID_LIBRARY MATCHES "lib/wxp") + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/wxp") set(_winreq "Windows XP") - elseif(WINHID_LIBRARY MATCHES "lib/wnet") + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/wnet") set(_winreq "Windows Server 2003") - elseif(WINHID_LIBRARY MATCHES "lib/wlh") + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/wlh") set(_winreq "Windows Vista") - elseif(WINHID_LIBRARY MATCHES "lib/win7") + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/win7") set(_winreq "Windows 7") - elseif(WINHID_LIBRARY MATCHES "lib/win8") - set(_winreq "Windows 8 (Possibly?)") + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/win8") + set(_winreq "Windows 8") + set(_winreq_uncertain ON) + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/winv6.3") + set(_winreq "Windows 8.1") + set(_winreq_uncertain ON) + elseif(WINHID_LIBRARY MATCHES "[Ll]ib/10.0") + set(_winreq "Windows 10") + set(_winreq_uncertain ON) endif() if(NOT "${WINHID_MIN_WINDOWS_VER}" STREQUAL "${_winreq}") if(NOT WinHID_FIND_QUIETLY) - message(STATUS - "Linking against WINHID_LIBRARY will enforce this minimum version: ${_winreq}") + if(NOT _winreq) + message("Couldn't determine if the WINHID_LIBRARY would result in a minimum version compatibility requirement.") + elseif(_winreq_uncertain) + message(STATUS + "Found WINHID_LIBRARY in the Windows SDK for ${_winreq} , which may or may not affect minimum compatible Windows version.") + else() + message(STATUS + "Linking against WINHID_LIBRARY will enforce this minimum version: ${_winreq}") + endif() endif() set(WINHID_MIN_WINDOWS_VER "${_winreq}" CACHE INTERNAL "" FORCE) endif() endif() - set(WINHID_LIBRARIES "${WINHID_LIBRARY}") + set(WINHID_LIBRARIES "${WINHID_LIBRARY}" "${WINHID_SETUPAPI_LIBRARY}") if(_need_crt_dir) set(WINHID_INCLUDE_DIRS "${WINHID_CRT_INCLUDE_DIR}" diff --git a/FindWindowsSDK.cmake b/FindWindowsSDK.cmake index 19630a06c..c6a945d27 100644 --- a/FindWindowsSDK.cmake +++ b/FindWindowsSDK.cmake @@ -2,6 +2,10 @@ # # Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK # +# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case +# you just want the tool binaries to run, rather than the libraries and headers +# for compiling. +# # Variables: # WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio # WINDOWSSDK_LATEST_DIR @@ -17,15 +21,26 @@ # windowssdk_name_lookup( ) - Find the name corresponding with the SDK directory you pass in, or # NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. # +# windowssdk_build_lookup( ) - Find the build version number corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# # get_windowssdk_from_component( ) - Given a library or include dir, # find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized. # # get_windowssdk_library_dirs( ) - Find the architecture-appropriate # library directories corresponding to the SDK directory you pass in (or NOTFOUND if none) # +# get_windowssdk_library_dirs_multiple( ...) - Find the architecture-appropriate +# library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# # get_windowssdk_include_dirs( ) - Find the # include directories corresponding to the SDK directory you pass in (or NOTFOUND if none) # +# get_windowssdk_include_dirs_multiple( ...) - Find the +# include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# # Requires these CMake modules: # FindPackageHandleStandardArgs (known included with CMake >=2.6.2) # @@ -39,182 +54,412 @@ # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -set(_preferred_sdk_dirs) -set(_win_sdk_dirs) -set(_win_sdk_versanddirs) -if(MSVC_VERSION GREATER 1310) # Newer than VS .NET/VS Toolkit 2003 +set(_preferred_sdk_dirs) # pre-output +set(_win_sdk_dirs) # pre-output +set(_win_sdk_versanddirs) # pre-output +set(_win_sdk_buildsanddirs) # pre-output +set(_winsdk_vistaonly) # search parameters +set(_winsdk_kits) # search parameters + + +set(_WINDOWSSDK_ANNOUNCE OFF) +if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY)) + set(_WINDOWSSDK_ANNOUNCE ON) +endif() +macro(_winsdk_announce) + if(_WINSDK_ANNOUNCE) + message(STATUS ${ARGN}) + endif() +endmacro() + +set(_winsdk_win10vers + 10.0.10586.0 # TH2 aka Win10 1511 + 10.0.10240.0 # Win10 RTM + 10.0.10150.0 # just ucrt + 10.0.10056.0 +) + +if(WindowsSDK_FIND_COMPONENTS MATCHES "tools") + set(_WINDOWSSDK_IGNOREMSVC ON) + _winsdk_announce("Checking for tools from Windows/Platform SDKs...") +else() + set(_WINDOWSSDK_IGNOREMSVC OFF) + _winsdk_announce("Checking for Windows/Platform SDKs...") +endif() + +# Appends to the three main pre-output lists used only if the path exists +# and is not already in the list. +function(_winsdk_conditional_append _vername _build _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_dirs "${_path}") + set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_versanddirs + "${_vername}" + "${_path}") + set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_buildsanddirs + "${_build}" + "${_path}") + set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE) +endfunction() + +# Appends to the "preferred SDK" lists only if the path exists +function(_winsdk_conditional_append_preferred _info _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + + get_filename_component(_path "${_path}" ABSOLUTE) + + list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_preferred_sdk_dirs "${_path}") + set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + + # Just in case we somehow missed it: + _winsdk_conditional_append("${_info}" "" "${_path}") +endfunction() + +# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs". +# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows +# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits", +# use this macro first, since these registry keys usually have more information. +# +# Pass a "default" build number as an extra argument in case we can't find it. +function(_winsdk_check_microsoft_sdks_registry _winsdkver) + set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}") + get_filename_component(_sdkdir + "[${SDKKEY};InstallationFolder]" + ABSOLUTE) + + set(_sdkname "Windows SDK ${_winsdkver}") + + # Default build number passed as extra argument + set(_build ${ARGN}) + # See if the registry holds a Microsoft-mutilated, err, designated, product name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkproductname + "[${SDKKEY};ProductName]" + NAME) + if(NOT "${_sdkproductname}" MATCHES "registry") + # Got a product name + set(_sdkname "${_sdkname} (${_sdkproductname})") + endif() + + # try for a version to augment our name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkver + "[${SDKKEY};ProductVersion]" + NAME) + if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES) + # Got a version + if(NOT "${_sdkver}" MATCHES "\\.\\.") + # and it's not an invalid one with two dots in it: + # use to override the default build + set(_build ${_sdkver}) + if(NOT "${_sdkname}" MATCHES "${_sdkver}") + # Got a version that's not already in the name, let's use it to improve our name. + set(_sdkname "${_sdkname} (${_sdkver})") + endif() + endif() + endif() + _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes, the build number, and a key (technically a "value name") +# corresponding to a Windows SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Note that the key or "value name" tends to be something weird like KitsRoot81 - +# no easy way to predict, just have to observe them in the wild. +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]" + ABSOLUTE) + _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes and the build number +# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_win10_kits _winkit_build) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" + ABSOLUTE) + if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}")) + return() # not found + endif() + if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um") + _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}") + endif() +endfunction() + +# Given a name for indentification purposes, the build number, and the associated package GUID, +# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\ +# for that guid and the SDK it points to. +function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid) + foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) + get_filename_component(_sdkdir + "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" + ABSOLUTE) + _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}") + endforeach() +endfunction() + +### +# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs +### +set(_winsdk_vistaonly_ok OFF) +if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC) + # VC 10 and older has broad target support + if(MSVC_VERSION LESS 1700) + # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") + # This is the XP-compatible v110+ toolset + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90") + # This is the VS2010/VS2008 toolset + else() + # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset. + # These versions have no XP (and possibly Vista pre-SP1) support + set(_winsdk_vistaonly_ok ON) + if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED) + set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE) + message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!") + endif() + endif() +endif() +if(_WINDOWSSDK_IGNOREMSVC) + set(_winsdk_vistaonly_ok ON) +endif() + +### +# MSVC version checks - keeps messy conditionals in one place +# (messy because of _WINDOWSSDK_IGNOREMSVC) +### +set(_winsdk_msvc_greater_1200 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200))) + set(_winsdk_msvc_greater_1200 ON) +endif() +# Newer than VS .NET/VS Toolkit 2003 +set(_winsdk_msvc_greater_1310 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310))) + set(_winsdk_msvc_greater_1310 ON) +endif() + +# VS2005/2008 +set(_winsdk_msvc_less_1600 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600))) + set(_winsdk_msvc_less_1600 ON) +endif() + +# VS2013+ +set(_winsdk_msvc_not_less_1800 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800))) + set(_winsdk_msvc_not_less_1800 ON) +endif() + +### +# START body of find module +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + ### + # Look for "preferred" SDKs + ### # Environment variable for SDK dir if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) - message(STATUS "Got $ENV{WindowsSDKDir} - Windows/Platform SDK directories: ${_win_sdk_dirs}") - list(APPEND _preferred_sdk_dirs "$ENV{WindowsSDKDir}") + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") endif() - if(MSVC_VERSION LESS 1600) + if(_winsdk_msvc_less_1600) # Per-user current Windows SDK for VS2005/2008 get_filename_component(_sdkdir "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) - if(EXISTS "${_sdkdir}") - list(APPEND _preferred_sdk_dirs "${_sdkdir}") - endif() + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") # System-wide current Windows SDK for VS2005/2008 get_filename_component(_sdkdir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) - if(EXISTS "${_sdkdir}") - list(APPEND _preferred_sdk_dirs "${_sdkdir}") - endif() + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") endif() - if(MSVC_VERSION LESS 1700) - # VC 10 and older has broad target support - set(_winsdk_vistaonly) - else() - # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ - if("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") - # This is the XP-compatible v110 toolset - elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100") - # This is the VS2010 toolset - else() - if((NOT WINDOWSSDK_FOUND) AND (NOT WindowsSDK_FIND_QUIETLY)) - message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!") - endif() - # These versions have no XP (and possibly Vista pre-SP1) support - set(_winsdk_vistaonly) - if(NOT MSVC_VERSION LESS 1800) - list(APPEND _winsdk_vistaonly - # Windows Software Development Kit (SDK) for Windows 8.1 - # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 - v8.1) - endif() - list(APPEND _winsdk_vistaonly - # Included in Visual Studio 2012 - v8.0A - - # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 - # This is the first version to also include the DirectX SDK - # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx - v8.0 - - # Microsoft Windows SDK for Windows 7 and .NET Framework 4 - # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b - v7.1 - ) - endif() - endif() - foreach(_winsdkver - ${_winsdk_vistaonly} + ### + # Begin the massive list of SDK searching! + ### + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # These require at least Visual Studio 2013 (VC12) - # Included in Visual Studio 2013 - # Includes the v120_xp toolset - v8.1A + _winsdk_check_microsoft_sdks_registry(v10.0A) - # Included with VS 2012 Update 1 or later - # Introduces v110_xp toolset - v7.1A + # Windows Software Development Kit (SDK) for Windows 10 + # Several different versions living in the same directory - if nothing else we can assume RTM (10240) + _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0) + foreach(_win10build ${_winsdk_win10vers}) + _winsdk_check_win10_kits(${_win10build}) + endforeach() + endif() # vista-only and 2013+ + + # Included in Visual Studio 2013 + # Includes the v120_xp toolset + _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636) + + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # Windows Software Development Kit (SDK) for Windows 8.1 + # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 + _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0) + _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81) + endif() # vista-only and 2013+ + + if(_winsdk_vistaonly_ok) + # Included in Visual Studio 2012 + _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727) + + # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 + # This is the first version to also include the DirectX SDK + # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx + _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384) + _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot) + endif() # vista-only - # Included with VS 2010 - v7.0A + # Included with VS 2012 Update 1 or later + # Introduces v110_xp toolset + _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106) + if(_winsdk_vistaonly_ok) + # Microsoft Windows SDK for Windows 7 and .NET Framework 4 + # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b + _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514) + endif() # vista-only - # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 - # Works with VC9 - #http://www.microsoft.com/en-us/download/details.aspx?id=18950 - v7.0 + # Included with VS 2010 + _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385) - # Two versions call themselves "v6.1": - # Older: - # Windows Vista Update & .NET 3.0 SDK - # http://www.microsoft.com/en-us/download/details.aspx?id=14477 + # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 + # Works with VC9 + # http://www.microsoft.com/en-us/download/details.aspx?id=18950 + _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385) - # Newer: - # Windows Server 2008 & .NET 3.5 SDK - # may have broken VS9SP1? they recommend v7.0 instead, or a KB... - # http://www.microsoft.com/en-us/download/details.aspx?id=24826 - v6.1 + # Two versions call themselves "v6.1": + # Older: + # Windows Vista Update & .NET 3.0 SDK + # http://www.microsoft.com/en-us/download/details.aspx?id=14477 - # Included in VS 2008 - v6.0A + # Newer: + # Windows Server 2008 & .NET 3.5 SDK + # may have broken VS9SP1? they recommend v7.0 instead, or a KB... + # http://www.microsoft.com/en-us/download/details.aspx?id=24826 + _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10) + + # Included in VS 2008 + _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1) + + # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components + # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx + _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384) +endif() + +# Let's not forget the Platform SDKs, which sometimes are useful! +if(_winsdk_msvc_greater_1200) + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1") + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3") +endif() +### +# Finally, look for "preferred" SDKs +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 - # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components - # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx - v6.0) + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 get_filename_component(_sdkdir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver};InstallationFolder]" + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) - if(EXISTS "${_sdkdir}") - list(APPEND _win_sdk_dirs "${_sdkdir}") - list(APPEND - _win_sdk_versanddirs - "Windows SDK ${_winsdkver}" - "${_sdkdir}") - endif() - endforeach() -endif() -if(MSVC_VERSION GREATER 1200) - foreach(_platformsdkinfo - "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1_Microsoft Platform SDK for Windows Server 2003 R2" - "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3_Microsoft Platform SDK for Windows Server 2003 SP1") - string(SUBSTRING "${_platformsdkinfo}" 0 36 _platformsdkguid) - string(SUBSTRING "${_platformsdkinfo}" 37 -1 _platformsdkname) - foreach(HIVE HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) - get_filename_component(_sdkdir - "[${HIVE}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" - ABSOLUTE) - if(EXISTS "${_sdkdir}") - list(APPEND _win_sdk_dirs "${_sdkdir}") - list(APPEND _win_sdk_versanddirs "${_platformsdkname}" "${_sdkdir}") - endif() - endforeach() - endforeach() + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() endif() -set(_win_sdk_versanddirs - "${_win_sdk_versanddirs}" - CACHE - INTERNAL - "mapping between windows sdk version locations and names" - FORCE) function(windowssdk_name_lookup _dir _outvar) list(FIND _win_sdk_versanddirs "${_dir}" _diridx) - math(EXPR _nameidx "${_diridx} - 1") - if(${_nameidx} GREATER -1) - list(GET _win_sdk_versanddirs ${_nameidx} _sdkname) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_versanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +function(windowssdk_build_lookup _dir _outvar) + list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_buildsanddirs ${_idx} _ret) else() - set(_sdkname "NOTFOUND") + set(_ret "NOTFOUND") endif() - set(${_outvar} "${_sdkname}" PARENT_SCOPE) + set(${_outvar} "${_ret}" PARENT_SCOPE) endfunction() +# If we found something... if(_win_sdk_dirs) - # Remove duplicates - list(REMOVE_DUPLICATES _win_sdk_dirs) list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR) windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" WINDOWSSDK_LATEST_NAME) set(WINDOWSSDK_DIRS ${_win_sdk_dirs}) + + # Fallback, in case no preference found. + set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") + set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") + set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) + set(WINDOWSSDK_FOUND_PREFERENCE OFF) endif() -if(_preferred_sdk_dirs) - list(GET _preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) - windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" + +# If we found indications of a user preference... +if(_win_sdk_preferred_sdk_dirs) + list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) + windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}" WINDOWSSDK_PREFERRED_NAME) set(WINDOWSSDK_PREFERRED_FIRST_DIRS - ${_preferred_sdk_dirs} + ${_win_sdk_preferred_sdk_dirs} ${_win_sdk_dirs}) list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS) set(WINDOWSSDK_FOUND_PREFERENCE ON) - - # In case a preferred dir was found that isn't found otherwise - #set(WINDOWSSDK_DIRS ${WINDOWSSDK_DIRS} ${WINDOWSSDK_PREFERRED_FIRST_DIRS}) - #list(REMOVE_DUPLICATES WINDOWSSDK_DIRS) -else() - set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") - set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") - set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) - set(WINDOWSSDK_FOUND_PREFERENCE OFF) endif() include(FindPackageHandleStandardArgs) @@ -223,26 +468,16 @@ find_package_handle_standard_args(WindowsSDK WINDOWSSDK_DIRS) if(WINDOWSSDK_FOUND) - if(NOT _winsdk_remembered_dirs STREQUAL WINDOWSSDK_DIRS) - set(_winsdk_remembered_dirs - "${WINDOWSSDK_DIRS}" - CACHE - INTERNAL - "" - FORCE) - if(NOT WindowsSDK_FIND_QUIETLY) - foreach(_sdkdir ${WINDOWSSDK_DIRS}) - windowssdk_name_lookup("${_sdkdir}" _sdkname) - message(STATUS " - Found ${_sdkname} at ${_sdkdir}") - endforeach() - endif() - endif() - # Internal: Architecture-appropriate library directory names. if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM") - set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs - set(_winsdk_arch arm) # what the architecture used to be called - set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + # Only supported in Win10 SDK and up. + set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch arm) # what the architecture used to be called + set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture + endif() else() if(CMAKE_SIZEOF_VOID_P MATCHES "8") set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs @@ -273,20 +508,47 @@ if(WINDOWSSDK_FOUND) endfunction() function(get_windowssdk_library_dirs _winsdk_dir _var) set(_result) - foreach(_suffix + set(_suffixes "lib${_winsdk_archbare}" # SDKs like 7.1A + "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir "lib/w2k/${_winsdk_arch}" # Win2k min requirement "lib/wxp/${_winsdk_arch}" # WinXP min requirement "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement - "lib/wlh/${_winsdk_arch}" # Win Vista ("Long Horn") min requirement + "lib/wlh/${_winsdk_arch}" "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement - "lib/win7/${_winsdk_arch}" # Win 7 min requirement + "lib/win7/${_winsdk_arch}" "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement - "lib/win8/um/${_winsdk_arch8}" # Win 8 min requirement - "lib/win8/km/${_winsdk_arch8}" # Win 8 min requirement - "lib/winv6.3/km/${_winsdk_arch8}" # Win 8.1 min requirement - "lib/winv6.3/um/${_winsdk_arch8}" # Win 8.1 min requirement ) + foreach(_ver + wlh # Win Vista ("Long Horn") min requirement + win7 # Win 7 min requirement + win8 # Win 8 min requirement + winv6.3 # Win 8.1 min requirement + ) + + list(APPEND _suffixes + "lib/${_ver}/${_winsdk_arch}" + "lib/${_ver}/um/${_winsdk_arch8}" + "lib/${_ver}/km/${_winsdk_arch8}" + ) + endforeach() + + # Look for WDF libraries in Win10+ SDK + foreach(_mode umdf kmdf) + file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*") + if(_wdfdirs) + list(APPEND _suffixes ${_wdfdirs}) + endif() + endforeach() + + # Look in each Win10+ SDK version for the components + foreach(_win10ver ${_winsdk_win10vers}) + foreach(_component um km ucrt mmos) + list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) # Check to see if a library actually exists here. file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib") if(_libs) @@ -295,19 +557,28 @@ if(WINDOWSSDK_FOUND) endforeach() if(NOT _result) set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) endif() set(${_var} ${_result} PARENT_SCOPE) endfunction() function(get_windowssdk_include_dirs _winsdk_dir _var) set(_result) - foreach(_suffix - "Include" - "Include/shared" - "Include/um" - "Include/winrt" - "Include/km" - "Include/wdf" - ) + + set(_subdirs shared um winrt km wdf mmos ucrt) + set(_suffixes Include) + + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_dir}") + endforeach() + + foreach(_ver ${_winsdk_win10vers}) + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_ver}/${_dir}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) # Check to see if a header file actually exists here. file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h") if(_headers) @@ -316,6 +587,38 @@ if(WINDOWSSDK_FOUND) endforeach() if(NOT _result) set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) + endif() + set(${_var} ${_result} PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs_multiple _var) + set(_result) + foreach(_sdkdir ${ARGN}) + get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs) + if(_current_sdk_libdirs) + list(APPEND _result ${_current_sdk_libdirs}) + endif() + endforeach() + if(NOT _result) + set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) + endif() + set(${_var} ${_result} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs_multiple _var) + set(_result) + foreach(_sdkdir ${ARGN}) + get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs) + if(_current_sdk_libdirs) + list(APPEND _result ${_current_sdk_incdirs}) + endif() + endforeach() + if(NOT _result) + set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) endif() set(${_var} ${_result} PARENT_SCOPE) endfunction() diff --git a/GenerateCompatibilityVersionFile.cmake b/GenerateCompatibilityVersionFile.cmake new file mode 100644 index 000000000..7ac28ed5f --- /dev/null +++ b/GenerateCompatibilityVersionFile.cmake @@ -0,0 +1,83 @@ +#.rst: +# .. command:: generate_compatibility_version_file +# +# Create a version file for a project:: +# +# generate_compatibility_version_file( +# [VERSION ] +# COMPATIBILITY +# [C_ABI] +# [CXX_LAYOUT] +# [CXX_ABI]) + +#============================================================================= +# Copyright 2015 Sensics, Inc. +# Copyright 2012 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +include(CMakeParseArguments) +include(CMakePackageConfigHelpers) + +set(GCVF_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "" FORCE) + +function(generate_compatibility_version_file _filename) + + set(options C_ABI CXX_LAYOUT CXX_ABI) + set(oneValueArgs VERSION COMPATIBILITY ) + set(multiValueArgs ) + cmake_parse_arguments(GCVF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(GCVF_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to generate_compatibility_version_file(): ${GCVF_UNPARSED_ARGUMENTS}") + endif() + set(versionTemplateFile "${CMAKE_ROOT}/Modules/BasicConfigVersion-${GCVF_COMPATIBILITY}.cmake.in") + if(NOT EXISTS "${versionTemplateFile}") + message(FATAL_ERROR "Bad COMPATIBILITY value used for generate_compatibility_version_file(): \"${GCVF_COMPATIBILITY}\"") + endif() + + if(GCVF_CXX_ABI) + set(GCVF_CXX_LAYOUT TRUE) + endif() + if(GCVF_CXX_LAYOUT) + set(GCVF_C_ABI TRUE) + endif() + + if("${GCVF_VERSION}" STREQUAL "") + if("${PROJECT_VERSION}" STREQUAL "") + message(FATAL_ERROR "No VERSION specified for generate_compatibility_version_file()") + else() + set(GCVF_VERSION ${PROJECT_VERSION}) + endif() + endif() + + set(GCVF_WIN_CXXLAYOUT) + if(MSVC) + set(GCVF_WIN_CXXLAYOUT "MSVC") + elseif(MINGW) + set(GCVF_WIN_CXXLAYOUT "MinGW") + elseif(WIN32) + set(GCVF_WIN_CXXLAYOUT "other") + endif() + + set(PREV_FILE "${_filename}.cmakeversion") + write_basic_package_version_file("${PREV_FILE}" VERSION ${GCVF_VERSION} COMPATIBILITY ${GCVF_COMPATIBILITY}) + set(GCVF_BASIC TRUE) + foreach(level BASIC C_ABI CXX_LAYOUT CXX_ABI) + if(GCVF_${level}) + file(READ "${PREV_FILE}" GCVF_PREVIOUS_FILE) + set(PREV_FILE "${_filename}.${level}") + configure_file("${GCVF_DIR}/CompatibilityVersionFile-${level}.cmake.in" "${PREV_FILE}" @ONLY) + endif() + endforeach() + configure_file("${PREV_FILE}" "${_filename}" COPYONLY) +endfunction() \ No newline at end of file diff --git a/MinGWSearchPathExtras.cmake b/MinGWSearchPathExtras.cmake new file mode 100644 index 000000000..cd9fe69bb --- /dev/null +++ b/MinGWSearchPathExtras.cmake @@ -0,0 +1,94 @@ +# - Additional help finding search paths on MinGW distributions, including MSYS2. +# +# Much of this is really more in the purview of CMake or the packages of CMake for +# those distributions, but if I can centralize/simplify the pain here, it's worth doing. +# +# Variables: (all are internal cache variables) +# MINGWSEARCH_INCLUDE_DIRS - use under PATHS in your find_path() commands +# MINGWSEARCH_LIBRARY_DIRS - use under PATHS in your find_library() commands +# MINGWSEARCH_PREFIXES - suitable for temporary use in CMAKE_FIND_ROOT_PATH or CMAKE_PREFIX_PATH. +# MINGWSEARCH_TARGET_TRIPLE - something like x86_64-w64-mingw32 or i686-w64-mingw32, use as you see fit. +# +# Original Author: +# 2016 Ryan Pavlik +# +# Copyright Sensics, Inc. 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(MINGW AND NOT MINGWSEARCH_COMPLETED) + ### + # Helper function + ### + function(_mingwsearch_conditional_add _var _path) + #message(STATUS "conditional add to ${_var}: ${_path}") + if(("${_path}" MATCHES "registry") OR (NOT IS_DIRECTORY "${_path}")) + # Path invalid - do not add + return() + endif() + list(FIND ${_var} "${_path}" _idx) + if(_idx GREATER -1) + # Path already in list - do not add + return() + endif() + # Not yet in the list, so we'll add it + list(APPEND ${_var} "${_path}") + set(${_var} ${${_var}} PARENT_SCOPE) + endfunction() + + # Clear the working variables. + set(MINGWSEARCH_INCLUDE_DIRS_WORK) + set(MINGWSEARCH_LIBRARY_DIRS_WORK) + set(MINGWSEARCH_PREFIXES_WORK) + set(_mingw_target_triple) + + # Try to find the string like x86_64-w64-mingw32 by parsing the implicit link directories... + # TODO this is a hack that either should be resolved in CMake or in MSYS2's package of CMake. + foreach(_link_dir ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) + _mingwsearch_conditional_add(MINGWSEARCH_LIBRARY_DIRS_WORK "${_link_dir}") + if("${_link_dir}" MATCHES "/([^/]*-mingw32)/lib") + set(_mingw_target_triple ${CMAKE_MATCH_1}) + get_filename_component(_mingw_internal_basedir "${_link_dir}" PATH) + # Try adding the parallel include dir + if(IS_DIRECTORY "${_mingw_internal_basedir}/include") + _mingwsearch_conditional_add(MINGWSEARCH_INCLUDE_DIRS_WORK "${_mingw_internal_basedir}/include") + _mingwsearch_conditional_add(MINGWSEARCH_PREFIXES_WORK "${_mingw_internal_basedir}") + endif() + if(NOT CMAKE_CROSSCOMPILING) + # Try going up a level, since the directory with the target is usually a sibling to the main prefix. + get_filename_component(_mingw_main_basedir_candidate "${_mingw_internal_basedir}/.." ABSOLUTE) + if(IS_DIRECTORY "${_mingw_main_basedir_candidate}/include" AND NOT ("${_mingw_main_basedir_candidate}" STREQUAL "${_mingw_internal_basedir}")) + # If we could go up a level, add that include dir too. + _mingwsearch_conditional_add(MINGWSEARCH_INCLUDE_DIRS_WORK "${_mingw_main_basedir_candidate}/include") + _mingwsearch_conditional_add(MINGWSEARCH_PREFIXES_WORK "${_mingw_main_basedir_candidate}") + endif() + endif() + endif() + endforeach() + + ### + # Output results. + ### + if(MINGWSEARCH_INCLUDE_DIRS_WORK) + set(MINGWSEARCH_INCLUDE_DIRS "${MINGWSEARCH_INCLUDE_DIRS_WORK}" CACHE INTERNAL "" FORCE) + #message(STATUS "MINGWSEARCH_INCLUDE_DIRS ${MINGWSEARCH_INCLUDE_DIRS}") + endif() + + if(MINGWSEARCH_LIBRARY_DIRS_WORK) + set(MINGWSEARCH_LIBRARY_DIRS "${MINGWSEARCH_LIBRARY_DIRS_WORK}" CACHE INTERNAL "" FORCE) + #message(STATUS "MINGWSEARCH_LIBRARY_DIRS ${MINGWSEARCH_LIBRARY_DIRS}") + endif() + + if(MINGWSEARCH_PREFIXES_WORK) + set(MINGWSEARCH_PREFIXES "${MINGWSEARCH_PREFIXES_WORK}" CACHE INTERNAL "" FORCE) + #message(STATUS "MINGWSEARCH_PREFIXES ${MINGWSEARCH_PREFIXES}") + endif() + + if(_mingw_target_triple) + set(MINGWSEARCH_TARGET_TRIPLE ${_mingw_target_triple} CACHE INTERNAL "" FORCE) + #message(STATUS "MINGWSEARCH_TARGET_TRIPLE ${MINGWSEARCH_TARGET_TRIPLE}") + endif() + + set(MINGWSEARCH_COMPLETED TRUE CACHE INTERNAL "" FORCE) +endif() diff --git a/cmake-3.2.0-modules/FindGit.cmake b/cmake-3.2.0-modules/FindGit.cmake new file mode 100644 index 000000000..5714b651a --- /dev/null +++ b/cmake-3.2.0-modules/FindGit.cmake @@ -0,0 +1,106 @@ +#.rst: +# FindGit +# ------- +# +# +# +# The module defines the following variables: +# +# :: +# +# GIT_EXECUTABLE - path to git command line client +# GIT_FOUND - true if the command line client was found +# GIT_VERSION_STRING - the version of git found (since CMake 2.8.8) +# +# Example usage: +# +# :: +# +# find_package(Git) +# if(GIT_FOUND) +# message("git found: ${GIT_EXECUTABLE}") +# endif() + +#============================================================================= +# Copyright 2010 Kitware, Inc. +# Copyright 2012 Rolf Eike Beer +# +# Distributed under the OSI-approved BSD License (the "License"); +# see below. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +# Look for 'git' or 'eg' (easy git) +# +set(git_names git eg) + +# Prefer .cmd variants on Windows unless running in a Makefile +# in the MSYS shell. +# +if(WIN32) + if(NOT CMAKE_GENERATOR MATCHES "MSYS") + set(git_names git.cmd git eg.cmd eg) + # GitHub search path for Windows + set(github_path "$ENV{LOCALAPPDATA}/Github/PortableGit*/bin") + file(GLOB github_path "${github_path}") + endif() +endif() + +find_program(GIT_EXECUTABLE + NAMES ${git_names} + PATHS ${github_path} + PATH_SUFFIXES Git/cmd Git/bin + DOC "git command line client" + ) +mark_as_advanced(GIT_EXECUTABLE) + +if(GIT_EXECUTABLE) + execute_process(COMMAND ${GIT_EXECUTABLE} --version + OUTPUT_VARIABLE git_version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (git_version MATCHES "^git version [0-9]") + string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}") + endif() + unset(git_version) +endif() + +# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if +# all listed variables are TRUE + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(Git + REQUIRED_VARS GIT_EXECUTABLE + VERSION_VAR GIT_VERSION_STRING) diff --git a/cmake-3.3.0-modules/WriteCompilerDetectionHeader.cmake b/cmake-3.3.0-modules/WriteCompilerDetectionHeader.cmake new file mode 100644 index 000000000..b40d824b1 --- /dev/null +++ b/cmake-3.3.0-modules/WriteCompilerDetectionHeader.cmake @@ -0,0 +1,692 @@ +#.rst: +# WriteCompilerDetectionHeader +# ---------------------------- +# +# This module provides the function write_compiler_detection_header(). +# +# The ``WRITE_COMPILER_DETECTION_HEADER`` function can be used to generate +# a file suitable for preprocessor inclusion which contains macros to be +# used in source code:: +# +# write_compiler_detection_header( +# FILE +# PREFIX +# [OUTPUT_FILES_VAR OUTPUT_DIR ] +# COMPILERS [...] +# FEATURES [...] +# [VERSION ] +# [PROLOG ] +# [EPILOG ] +# ) +# +# The ``write_compiler_detection_header`` function generates the +# file ```` with macros which all have the prefix ````. +# +# By default, all content is written directly to the ````. The +# ``OUTPUT_FILES_VAR`` may be specified to cause the compiler-specific +# content to be written to separate files. The separate files are then +# available in the ```` and may be consumed by the caller +# for installation for example. The ``OUTPUT_DIR`` specifies a relative +# path from the main ```` to the compiler-specific files. For example: +# +# .. code-block:: cmake +# +# write_compiler_detection_header( +# FILE climbingstats_compiler_detection.h +# PREFIX ClimbingStats +# OUTPUT_FILES_VAR support_files +# OUTPUT_DIR compilers +# COMPILERS GNU Clang MSVC +# FEATURES cxx_variadic_templates +# ) +# install(FILES +# ${CMAKE_CURRENT_BINARY_DIR}/climbingstats_compiler_detection.h +# DESTINATION include +# ) +# install(FILES +# ${support_files} +# DESTINATION include/compilers +# ) +# +# +# ``VERSION`` may be used to specify the API version to be generated. +# Future versions of CMake may introduce alternative APIs. A given +# API is selected by any ```` value greater than or equal +# to the version of CMake that introduced the given API and less +# than the version of CMake that introduced its succeeding API. +# The value of the :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` +# variable is used if no explicit version is specified. +# (As of CMake version |release| there is only one API version.) +# +# ``PROLOG`` may be specified as text content to write at the start of the +# header. ``EPILOG`` may be specified as text content to write at the end +# of the header +# +# At least one ```` and one ```` must be listed. Compilers +# which are known to CMake, but not specified are detected and a preprocessor +# ``#error`` is generated for them. A preprocessor macro matching +# ``_COMPILER_IS_`` is generated for each compiler +# known to CMake to contain the value ``0`` or ``1``. +# +# Possible compiler identifiers are documented with the +# :variable:`CMAKE__COMPILER_ID` variable. +# Available features in this version of CMake are listed in the +# :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and +# :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties. +# +# See the :manual:`cmake-compile-features(7)` manual for information on +# compile features. +# +# Feature Test Macros +# =================== +# +# For each compiler, a preprocessor macro is generated matching +# ``_COMPILER_IS_`` which has the content either ``0`` +# or ``1``, depending on the compiler in use. Preprocessor macros for +# compiler version components are generated matching +# ``_COMPILER_VERSION_MAJOR`` ``_COMPILER_VERSION_MINOR`` +# and ``_COMPILER_VERSION_PATCH`` containing decimal values +# for the corresponding compiler version components, if defined. +# +# A preprocessor test is generated based on the compiler version +# denoting whether each feature is enabled. A preprocessor macro +# matching ``_COMPILER_``, where ```` is the +# upper-case ```` name, is generated to contain the value +# ``0`` or ``1`` depending on whether the compiler in use supports the +# feature: +# +# .. code-block:: cmake +# +# write_compiler_detection_header( +# FILE climbingstats_compiler_detection.h +# PREFIX ClimbingStats +# COMPILERS GNU Clang AppleClang MSVC +# FEATURES cxx_variadic_templates +# ) +# +# .. code-block:: c++ +# +# #if ClimbingStats_COMPILER_CXX_VARIADIC_TEMPLATES +# template +# void someInterface(T t...) { /* ... */ } +# #else +# // Compatibility versions +# template +# void someInterface(T1 t1) { /* ... */ } +# template +# void someInterface(T1 t1, T2 t2) { /* ... */ } +# template +# void someInterface(T1 t1, T2 t2, T3 t3) { /* ... */ } +# #endif +# +# Symbol Macros +# ============= +# +# Some additional symbol-defines are created for particular features for +# use as symbols which may be conditionally defined empty: +# +# .. code-block:: c++ +# +# class MyClass ClimbingStats_FINAL +# { +# ClimbingStats_CONSTEXPR int someInterface() { return 42; } +# }; +# +# The ``ClimbingStats_FINAL`` macro will expand to ``final`` if the +# compiler (and its flags) support the ``cxx_final`` feature, and the +# ``ClimbingStats_CONSTEXPR`` macro will expand to ``constexpr`` +# if ``cxx_constexpr`` is supported. +# +# The following features generate corresponding symbol defines: +# +# ========================== =================================== ================= +# Feature Define Symbol +# ========================== =================================== ================= +# ``c_restrict`` ``_RESTRICT`` ``restrict`` +# ``cxx_constexpr`` ``_CONSTEXPR`` ``constexpr`` +# ``cxx_deleted_functions`` ``_DELETED_FUNCTION`` ``= delete`` +# ``cxx_extern_templates`` ``_EXTERN_TEMPLATE`` ``extern`` +# ``cxx_final`` ``_FINAL`` ``final`` +# ``cxx_noexcept`` ``_NOEXCEPT`` ``noexcept`` +# ``cxx_noexcept`` ``_NOEXCEPT_EXPR(X)`` ``noexcept(X)`` +# ``cxx_override`` ``_OVERRIDE`` ``override`` +# ========================== =================================== ================= +# +# Compatibility Implementation Macros +# =================================== +# +# Some features are suitable for wrapping in a macro with a backward +# compatibility implementation if the compiler does not support the feature. +# +# When the ``cxx_static_assert`` feature is not provided by the compiler, +# a compatibility implementation is available via the +# ``_STATIC_ASSERT(COND)`` and +# ``_STATIC_ASSERT_MSG(COND, MSG)`` function-like macros. The macros +# expand to ``static_assert`` where that compiler feature is available, and +# to a compatibility implementation otherwise. In the first form, the +# condition is stringified in the message field of ``static_assert``. In +# the second form, the message ``MSG`` is passed to the message field of +# ``static_assert``, or ignored if using the backward compatibility +# implementation. +# +# The ``cxx_attribute_deprecated`` feature provides a macro definition +# ``_DEPRECATED``, which expands to either the standard +# ``[[deprecated]]`` attribute or a compiler-specific decorator such +# as ``__attribute__((__deprecated__))`` used by GNU compilers. +# +# The ``cxx_alignas`` feature provides a macro definition +# ``_ALIGNAS`` which expands to either the standard ``alignas`` +# decorator or a compiler-specific decorator such as +# ``__attribute__ ((__aligned__))`` used by GNU compilers. +# +# The ``cxx_alignof`` feature provides a macro definition +# ``_ALIGNOF`` which expands to either the standard ``alignof`` +# decorator or a compiler-specific decorator such as ``__alignof__`` +# used by GNU compilers. +# +# ============================= ================================ ===================== +# Feature Define Symbol +# ============================= ================================ ===================== +# ``cxx_alignas`` ``_ALIGNAS`` ``alignas`` +# ``cxx_alignof`` ``_ALIGNOF`` ``alignof`` +# ``cxx_nullptr`` ``_NULLPTR`` ``nullptr`` +# ``cxx_static_assert`` ``_STATIC_ASSERT`` ``static_assert`` +# ``cxx_static_assert`` ``_STATIC_ASSERT_MSG`` ``static_assert`` +# ``cxx_attribute_deprecated`` ``_DEPRECATED`` ``[[deprecated]]`` +# ``cxx_attribute_deprecated`` ``_DEPRECATED_MSG`` ``[[deprecated]]`` +# ``cxx_thread_local`` ``_THREAD_LOCAL`` ``thread_local`` +# ============================= ================================ ===================== +# +# A use-case which arises with such deprecation macros is the deprecation +# of an entire library. In that case, all public API in the library may +# be decorated with the ``_DEPRECATED`` macro. This results in +# very noisy build output when building the library itself, so the macro +# may be may be defined to empty in that case when building the deprecated +# library: +# +# .. code-block:: cmake +# +# add_library(compat_support ${srcs}) +# target_compile_definitions(compat_support +# PRIVATE +# CompatSupport_DEPRECATED= +# ) + +#============================================================================= +# Copyright 2014 Stephen Kelly +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + + +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeCompilerIdDetection.cmake) + +function(_load_compiler_variables CompilerId lang) + include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-FeatureTests.cmake" OPTIONAL) + set(_cmake_oldestSupported_${CompilerId} ${_cmake_oldestSupported} PARENT_SCOPE) + foreach(feature ${ARGN}) + set(_cmake_feature_test_${CompilerId}_${feature} ${_cmake_feature_test_${feature}} PARENT_SCOPE) + endforeach() + include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-DetermineCompiler.cmake" OPTIONAL + RESULT_VARIABLE determinedCompiler) + if (NOT determinedCompiler) + include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-DetermineCompiler.cmake" OPTIONAL) + endif() + set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE) +endfunction() + +function(write_compiler_detection_header + file_keyword file_arg + prefix_keyword prefix_arg + ) + if (NOT "x${file_keyword}" STREQUAL "xFILE") + message(FATAL_ERROR "write_compiler_detection_header: FILE parameter missing.") + endif() + if (NOT "x${prefix_keyword}" STREQUAL "xPREFIX") + message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.") + endif() + set(options) + set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR) + set(multiValueArgs COMPILERS FEATURES) + cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT _WCD_COMPILERS) + message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one compiler.") + endif() + if (NOT _WCD_FEATURES) + message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one feature.") + endif() + + if(_WCD_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unparsed arguments: ${_WCD_UNPARSED_ARGUMENTS}") + endif() + + if (prefix_arg STREQUAL "") + message(FATAL_ERROR "A prefix must be specified") + endif() + string(MAKE_C_IDENTIFIER ${prefix_arg} cleaned_prefix) + if (NOT prefix_arg STREQUAL cleaned_prefix) + message(FATAL_ERROR "The prefix must be a valid C identifier.") + endif() + + if(NOT _WCD_VERSION) + set(_WCD_VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION}) + endif() + set(_min_version 3.1.0) # Version which introduced this function + if (_WCD_VERSION VERSION_LESS _min_version) + set(err "VERSION compatibility for write_compiler_detection_header is set to ${_WCD_VERSION}, which is too low.") + set(err "${err} It must be set to at least ${_min_version}. ") + set(err "${err} Either set the VERSION parameter to the write_compiler_detection_header function, or update") + set(err "${err} your minimum required CMake version with the cmake_minimum_required command.") + message(FATAL_ERROR "${err}") + endif() + + if(_WCD_OUTPUT_FILES_VAR) + if(NOT _WCD_OUTPUT_DIR) + message(FATAL_ERROR "If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.") + endif() + endif() + if(_WCD_OUTPUT_DIR) + if(NOT _WCD_OUTPUT_FILES_VAR) + message(FATAL_ERROR "If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.") + endif() + get_filename_component(main_file_dir ${file_arg} DIRECTORY) + if (NOT IS_ABSOLUTE ${main_file_dir}) + set(main_file_dir "${CMAKE_CURRENT_BINARY_DIR}/${main_file_dir}") + endif() + if (NOT IS_ABSOLUTE ${_WCD_OUTPUT_DIR}) + set(_WCD_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_WCD_OUTPUT_DIR}") + endif() + get_filename_component(out_file_dir ${_WCD_OUTPUT_DIR} ABSOLUTE) + string(FIND ${out_file_dir} ${main_file_dir} idx) + if (NOT idx EQUAL 0) + message(FATAL_ERROR "The compiler-specific output directory must be within the same directory as the main file.") + endif() + + if (main_file_dir STREQUAL out_file_dir) + unset(_WCD_OUTPUT_DIR) + else() + string(REPLACE "${main_file_dir}/" "" _WCD_OUTPUT_DIR "${out_file_dir}/") + endif() + endif() + + set(compilers + GNU + Clang + AppleClang + MSVC + SunPro + ) + + set(_hex_compilers ADSP Borland Embarcadero SunPro) + + foreach(_comp ${_WCD_COMPILERS}) + list(FIND compilers ${_comp} idx) + if (idx EQUAL -1) + message(FATAL_ERROR "Unsupported compiler ${_comp}.") + endif() + if (NOT _need_hex_conversion) + list(FIND _hex_compilers ${_comp} idx) + if (NOT idx EQUAL -1) + set(_need_hex_conversion TRUE) + endif() + endif() + endforeach() + + set(file_content " +// This is a generated file. Do not edit! + +#ifndef ${prefix_arg}_COMPILER_DETECTION_H +#define ${prefix_arg}_COMPILER_DETECTION_H +") + + if (_WCD_PROLOG) + set(file_content "${file_content}\n${_WCD_PROLOG}\n") + endif() + + if (_need_hex_conversion) + set(file_content "${file_content} +#define ${prefix_arg}_DEC(X) (X) +#define ${prefix_arg}_HEX(X) ( \\ + ((X)>>28 & 0xF) * 10000000 + \\ + ((X)>>24 & 0xF) * 1000000 + \\ + ((X)>>20 & 0xF) * 100000 + \\ + ((X)>>16 & 0xF) * 10000 + \\ + ((X)>>12 & 0xF) * 1000 + \\ + ((X)>>8 & 0xF) * 100 + \\ + ((X)>>4 & 0xF) * 10 + \\ + ((X) & 0xF) \\ + )\n") + endif() + + foreach(feature ${_WCD_FEATURES}) + if (feature MATCHES "^cxx_") + list(APPEND _langs CXX) + list(APPEND CXX_features ${feature}) + elseif (feature MATCHES "^c_") + list(APPEND _langs C) + list(APPEND C_features ${feature}) + else() + message(FATAL_ERROR "Unsupported feature ${feature}.") + endif() + endforeach() + list(REMOVE_DUPLICATES _langs) + + if(_WCD_OUTPUT_FILES_VAR) + get_filename_component(main_file_name ${file_arg} NAME) + set(compiler_file_content_ +"#ifndef ${prefix_arg}_COMPILER_DETECTION_H +# error This file may only be included from ${main_file_name} +#endif\n") + endif() + + foreach(_lang ${_langs}) + set(target_compilers) + foreach(compiler ${_WCD_COMPILERS}) + _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features}) + if(_cmake_oldestSupported_${compiler}) + list(APPEND target_compilers ${compiler}) + endif() + endforeach() + + get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES) + foreach(feature ${${_lang}_features}) + list(FIND known_features ${feature} idx) + if (idx EQUAL -1) + message(FATAL_ERROR "Unsupported feature ${feature}.") + endif() + endforeach() + + if(_lang STREQUAL CXX) + set(file_content "${file_content}\n#ifdef __cplusplus\n") + else() + set(file_content "${file_content}\n#ifndef __cplusplus\n") + endif() + + compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_ + ID_DEFINE + ) + + set(file_content "${file_content}${ID_CONTENT}\n") + + set(pp_if "if") + foreach(compiler ${target_compilers}) + set(file_content "${file_content}\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n") + + if(_WCD_OUTPUT_FILES_VAR) + set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h") + set(file_content "${file_content}\n# include \"${compile_file_name}\"\n") + endif() + + if(_WCD_OUTPUT_FILES_VAR) + set(compiler_file_content compiler_file_content_${compiler}_${_lang}) + else() + set(compiler_file_content file_content) + endif() + + set(${compiler_file_content} "${${compiler_file_content}} +# if !(${_cmake_oldestSupported_${compiler}}) +# error Unsupported compiler version +# endif\n") + + set(PREFIX ${prefix_arg}_) + if (_need_hex_conversion) + set(MACRO_DEC ${prefix_arg}_DEC) + set(MACRO_HEX ${prefix_arg}_HEX) + else() + set(MACRO_DEC) + set(MACRO_HEX) + endif() + string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY) + set(${compiler_file_content} "${${compiler_file_content}}${VERSION_BLOCK}\n") + set(PREFIX) + set(MACRO_DEC) + set(MACRO_HEX) + + set(pp_if "elif") + foreach(feature ${${_lang}_features}) + string(TOUPPER ${feature} feature_upper) + set(feature_PP "COMPILER_${feature_upper}") + set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n") + if (_cmake_feature_test_${compiler}_${feature} STREQUAL "1") + set(_define_item "\n# define ${prefix_arg}_${feature_PP} 1\n") + elseif (_cmake_feature_test_${compiler}_${feature}) + set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n") + set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n") + endif() + set(${compiler_file_content} "${${compiler_file_content}}${_define_item}") + endforeach() + endforeach() + if(pp_if STREQUAL "elif") + set(file_content "${file_content} +# else +# error Unsupported compiler +# endif\n") + endif() + foreach(feature ${${_lang}_features}) + string(TOUPPER ${feature} feature_upper) + set(feature_PP "COMPILER_${feature_upper}") + set(def_name ${prefix_arg}_${feature_PP}) + if (feature STREQUAL c_restrict) + set(def_value "${prefix_arg}_RESTRICT") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} restrict +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_constexpr) + set(def_value "${prefix_arg}_CONSTEXPR") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} constexpr +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_final) + set(def_value "${prefix_arg}_FINAL") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} final +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_override) + set(def_value "${prefix_arg}_OVERRIDE") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} override +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_static_assert) + set(def_value "${prefix_arg}_STATIC_ASSERT(X)") + set(def_value_msg "${prefix_arg}_STATIC_ASSERT_MSG(X, MSG)") + set(static_assert_struct "template struct ${prefix_arg}StaticAssert;\ntemplate<> struct ${prefix_arg}StaticAssert{};\n") + set(def_standard "# define ${def_value} static_assert(X, #X)\n# define ${def_value_msg} static_assert(X, MSG)") + set(def_alternative "${static_assert_struct}# define ${def_value} sizeof(${prefix_arg}StaticAssert)\n# define ${def_value_msg} sizeof(${prefix_arg}StaticAssert)") + set(file_content "${file_content}# if ${def_name}\n${def_standard}\n# else\n${def_alternative}\n# endif\n\n") + endif() + if (feature STREQUAL cxx_alignas) + set(def_value "${prefix_arg}_ALIGNAS(X)") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} alignas(X) +# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang +# define ${def_value} __attribute__ ((__aligned__(X))) +# elif ${prefix_arg}_COMPILER_IS_MSVC +# define ${def_value} __declspec(align(X)) +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_alignof) + set(def_value "${prefix_arg}_ALIGNOF(X)") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} alignof(X) +# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang +# define ${def_value} __alignof__(X) +# elif ${prefix_arg}_COMPILER_IS_MSVC +# define ${def_value} __alignof(X) +# endif +\n") + endif() + if (feature STREQUAL cxx_deleted_functions) + set(def_value "${prefix_arg}_DELETED_FUNCTION") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} = delete +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_extern_templates) + set(def_value "${prefix_arg}_EXTERN_TEMPLATE") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} extern +# else +# define ${def_value} +# endif +\n") + endif() + if (feature STREQUAL cxx_noexcept) + set(def_value "${prefix_arg}_NOEXCEPT") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} noexcept +# define ${def_value}_EXPR(X) noexcept(X) +# else +# define ${def_value} +# define ${def_value}_EXPR(X) +# endif +\n") + endif() + if (feature STREQUAL cxx_nullptr) + set(def_value "${prefix_arg}_NULLPTR") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} nullptr +# else +# define ${def_value} 0 +# endif +\n") + endif() + if (feature STREQUAL cxx_thread_local) + set(def_value "${prefix_arg}_THREAD_LOCAL") + set(file_content "${file_content} +# if ${def_name} +# define ${def_value} thread_local +# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang +# define ${def_value} __thread +# elif ${prefix_arg}_COMPILER_IS_MSVC +# define ${def_value} __declspec(thread) +# else +// ${def_value} not defined for this configuration. +# endif +\n") + endif() + if (feature STREQUAL cxx_attribute_deprecated) + set(def_name ${prefix_arg}_${feature_PP}) + set(def_value "${prefix_arg}_DEPRECATED") + set(file_content "${file_content} +# ifndef ${def_value} +# if ${def_name} +# define ${def_value} [[deprecated]] +# define ${def_value}_MSG(MSG) [[deprecated(MSG)]] +# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang +# define ${def_value} __attribute__((__deprecated__)) +# define ${def_value}_MSG(MSG) __attribute__((__deprecated__(MSG))) +# elif ${prefix_arg}_COMPILER_IS_MSVC +# define ${def_value} __declspec(deprecated) +# define ${def_value}_MSG(MSG) __declspec(deprecated(MSG)) +# else +# define ${def_value} +# define ${def_value}_MSG(MSG) +# endif +# endif +\n") + endif() + endforeach() + + set(file_content "${file_content}#endif\n") + + endforeach() + + if(_WCD_OUTPUT_FILES_VAR) + foreach(compiler ${_WCD_COMPILERS}) + foreach(_lang ${_langs}) + if(compiler_file_content_${compiler}_${_lang}) + set(CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_}") + set(CMAKE_CONFIGURABLE_FILE_CONTENT "${CMAKE_CONFIGURABLE_FILE_CONTENT}${compiler_file_content_${compiler}_${_lang}}") + + set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h") + set(full_path "${main_file_dir}/${compile_file_name}") + list(APPEND ${_WCD_OUTPUT_FILES_VAR} ${full_path}) + configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" + "${full_path}" + @ONLY + ) + endif() + endforeach() + endforeach() + set(${_WCD_OUTPUT_FILES_VAR} ${${_WCD_OUTPUT_FILES_VAR}} PARENT_SCOPE) + endif() + + if (_WCD_EPILOG) + set(file_content "${file_content}\n${_WCD_EPILOG}\n") + endif() + set(file_content "${file_content}\n#endif") + + set(CMAKE_CONFIGURABLE_FILE_CONTENT ${file_content}) + configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" + "${file_arg}" + @ONLY + ) +endfunction()