diff options
37 files changed, 1139 insertions, 417 deletions
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index d9b939f..fc4bfdc 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -125,6 +125,7 @@ They are normally called through the :command:`find_package` command. /module/FindDCMTK /module/FindDevIL /module/FindDoxygen + /module/FindEnvModules /module/FindEXPAT /module/FindFLEX /module/FindFLTK2 diff --git a/Help/module/FindEnvModules.rst b/Help/module/FindEnvModules.rst new file mode 100644 index 0000000..72c120f --- /dev/null +++ b/Help/module/FindEnvModules.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/FindEnvModules.cmake diff --git a/Help/release/dev/FindGLEW-updates.rst b/Help/release/dev/FindGLEW-updates.rst new file mode 100644 index 0000000..6487052 --- /dev/null +++ b/Help/release/dev/FindGLEW-updates.rst @@ -0,0 +1,5 @@ +FindGLEW-updates +---------------- + +* The :module:`FindGLEW` module now provides an interface more consistent + with what upstream GLEW provides in its own CMake package files. diff --git a/Help/release/dev/cuda-compiler-generator-expressions.rst b/Help/release/dev/cuda-compiler-generator-expressions.rst new file mode 100644 index 0000000..2610a39 --- /dev/null +++ b/Help/release/dev/cuda-compiler-generator-expressions.rst @@ -0,0 +1,5 @@ +cuda-compiler-generator-expressions +----------------------------------- + +* The ``$<CUDA_COMPILER_ID:...>`` and ``$<CUDA_COMPILER_VERSION:...>`` + :manual:`generator expressions <cmake-generator-expressions(7)>` were added. diff --git a/Help/release/dev/environment-modules.rst b/Help/release/dev/environment-modules.rst new file mode 100644 index 0000000..eace35d --- /dev/null +++ b/Help/release/dev/environment-modules.rst @@ -0,0 +1,5 @@ +environment-modules +------------------- + +* The :module:`FindEnvModules` module was added to use Lua- and TCL-based + environment modules in :ref:`CTest Scripts <CTest Script>`. diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake index e60ffe0..5b9ed34 100644 --- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake +++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake @@ -30,5 +30,6 @@ macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR) FAIL_REGEX "Incorrect command line option:" # Borland FAIL_REGEX "Warning: illegal option" # SunStudio 12 FAIL_REGEX "[Ww]arning: Invalid suboption" # Fujitsu + FAIL_REGEX "An invalid option .* appears on the command line" # Cray ) endmacro () diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 22e0523..4344bdb 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -251,6 +251,9 @@ External Project Definition The lack of such deterministic behavior makes the main project lose traceability and repeatability. + If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with + branch names and tags. A commit hash is not allowed. + ``GIT_REMOTE_NAME <name>`` The optional name of the remote. If this option is not specified, it defaults to ``origin``. @@ -1053,11 +1056,6 @@ define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED ) function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify) - if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10) - set(git_clone_shallow_options "--depth 1 --no-single-branch") - else() - set(git_clone_shallow_options "--depth 1") - endif() if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5) # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path. set(git_checkout_explicit-- "--") @@ -1067,12 +1065,30 @@ function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git # because that will not search for remote branch names, a common use case. set(git_checkout_explicit-- "") endif() - file(WRITE ${script_filename} -"if(\"${git_tag}\" STREQUAL \"\") - message(FATAL_ERROR \"Tag for git checkout should not be empty.\") -endif() + if("${git_tag}" STREQUAL "") + message(FATAL_ERROR "Tag for git checkout should not be empty.") + endif() -set(run 0) + set(git_clone_options) + if(git_shallow) + if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10) + list(APPEND git_clone_options "--depth 1 --no-single-branch") + else() + list(APPEND git_clone_options "--depth 1") + endif() + endif() + if(git_progress) + list(APPEND git_clone_options --progress) + endif() + foreach(config IN LISTS git_config) + list(APPEND git_clone_options --config ${config}) + endforeach() + if(NOT ${git_remote_name} STREQUAL "origin") + list(APPEND git_clone_options --origin \"${git_remote_name}\") + endif() + string (REPLACE ";" " " git_clone_options "${git_clone_options}") + file(WRITE ${script_filename} +"set(run 0) if(\"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\") set(run 1) @@ -1100,29 +1116,12 @@ if(NOT \"x${tls_verify}\" STREQUAL \"x\" AND NOT tls_verify) -c http.sslVerify=false) endif() -set(git_clone_options) - -set(git_shallow \"${git_shallow}\") -if(git_shallow) - list(APPEND git_clone_options ${git_clone_shallow_options}) -endif() - -set(git_progress \"${git_progress}\") -if(git_progress) - list(APPEND git_clone_options --progress) -endif() - -set(git_config \"${git_config}\") -foreach(config IN LISTS git_config) - list(APPEND git_clone_options --config \${config}) -endforeach() - # try the clone 3 times in case there is an odd git clone issue set(error_code 1) set(number_of_tries 0) while(error_code AND number_of_tries LESS 3) execute_process( - COMMAND \"${git_EXECUTABLE}\" \${git_options} clone \${git_clone_options} --origin \"${git_remote_name}\" \"${git_repository}\" \"${src_name}\" + COMMAND \"${git_EXECUTABLE}\" \${git_options} clone ${git_clone_options} \"${git_repository}\" \"${src_name}\" WORKING_DIRECTORY \"${work_dir}\" RESULT_VARIABLE error_code ) @@ -1146,15 +1145,6 @@ if(error_code) endif() execute_process( - COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule init ${git_submodules} - WORKING_DIRECTORY \"${work_dir}/${src_name}\" - RESULT_VARIABLE error_code - ) -if(error_code) - message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\") -endif() - -execute_process( COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule update --recursive --init ${git_submodules} WORKING_DIRECTORY \"${work_dir}/${src_name}\" RESULT_VARIABLE error_code @@ -2460,7 +2450,7 @@ function(_ep_add_download_command name) # set(repository ${git_repository}) set(module) - set(tag) + set(tag ${git_remote_name}) configure_file( "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in" "${stamp_dir}/${name}-gitinfo.txt" diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake index 0aa4f50..bfa449f 100644 --- a/Modules/FindBLAS.cmake +++ b/Modules/FindBLAS.cmake @@ -83,6 +83,13 @@ This module defines the following variables: set(BLA_VENDOR Intel10_64lp) find_package(BLAS) + +Hints +^^^^^ + +Set ``MKLROOT`` environment variable to a directory that contains an MKL +installation. + #]=======================================================================] include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake) @@ -394,6 +401,24 @@ if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All") endif () endif () + if (DEFINED ENV{MKLROOT}) + set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}") + endif () + if (_BLAS_MKLROOT_LIB_DIR) + if( SIZEOF_INTEGER EQUAL 8 ) + set( _BLAS_MKL_PATH_PREFIX "intel64" ) + else() + set( _BLAS_MKL_PATH_PREFIX "ia32" ) + endif() + if (WIN32) + string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_win") + elseif (APPLE) + string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_mac") + else () + string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_lin") + endif () + endif () + foreach (IT ${BLAS_SEARCH_LIBS}) string(REPLACE " " ";" SEARCH_LIBS ${IT}) if (NOT ${_LIBRARIES}) @@ -404,6 +429,7 @@ if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All") "" "${SEARCH_LIBS}" "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}" + "${_BLAS_MKLROOT_LIB_DIR}" ) endif () endforeach () diff --git a/Modules/FindEnvModules.cmake b/Modules/FindEnvModules.cmake new file mode 100644 index 0000000..5d3452d --- /dev/null +++ b/Modules/FindEnvModules.cmake @@ -0,0 +1,333 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindEnvModules +-------------- + +Locate an environment module implementation and make commands available to +CMake scripts to use them. This is compatible with both Lua-based Lmod +and TCL-based EnvironmentModules. + +This module is intended for the use case of setting up the compiler and library +environment within a :ref:`CTest Script <CTest Script>` (``ctest -S``). It can +also be used in a :ref:`CMake Script <Script Processing Mode>` (``cmake -P``). + +.. note:: + + The loaded environment will not survive past the end of the calling process. + Do not use this module in project code (``CMakeLists.txt`` files) to load + a compiler environment; it will not be available during the build. Instead + load the environment manually before running CMake or using the generated + build system. + +Example Usage +^^^^^^^^^^^^^ + +.. code-block:: cmake + + set(CTEST_BUILD_NAME "CrayLinux-CrayPE-Cray-dynamic") + set(CTEST_BUILD_CONFIGURATION Release) + set(CTEST_BUILD_FLAGS "-k -j8") + set(CTEST_CMAKE_GENERATOR "Unix Makefiles") + + ... + + find_package(EnvModules REQUIRED) + + env_module(purge) + env_module(load modules) + env_module(load craype) + env_module(load PrgEnv-cray) + env_module(load craype-knl) + env_module(load cray-mpich) + env_module(load cray-libsci) + + set(ENV{CRAYPE_LINK_TYPE} dynamic) + + ... + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +``EnvModules_FOUND`` + Found the a compatible environment modules framework + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variable will be set: + +``EnvModules_COMMAND`` + The low level module command to use. Currently supported are + implementations are the Lua based Lmod and TCL based EnvironmentModules. + +Environment Variables +^^^^^^^^^^^^^^^^^^^^^ + +``ENV{MODULESHOME}`` + Usually set by the module environment implementation, used as a hint to + locate the module command to execute. + +Provided Functions +^^^^^^^^^^^^^^^^^^ + +This defines the following cmake functions for interacting with environment +modules: + +.. command:: env_module + + Execute an aribitrary module command: + + .. code-block:: cmake + + env_module(cmd arg1 ... argN) + env_module( + COMMAND cmd arg1 ... argN + [OUTPUT_VARIABLE <out-var>] + [RESULT_VARIABLE <ret-var>] + ) + + The options are: + + ``cmd arg1 ... argN`` + The module sub-command and arguments to execute as if they were + passed directly to the module command in your shell environment. + + ``OUTPUT_VARIABLE <out-var>`` + The standard output from executing the module command. + + ``RESULT_VARIABLE <ret-var>`` + The return code from executing the module command. + +.. command:: env_module_swap + + Swap one module for another: + + .. code-block:: cmake + + env_module_swap(out_mod in_mod + [OUTPUT_VARIABLE <out-var>] + [RESULT_VARIABLE <ret-var>] + ) + + This is functionally equivalent to the ``module swap out_mod in_mod`` shell + command. The options are: + + ``OUTPUT_VARIABLE <out-var>`` + The standard output from executing the module command. + + ``RESULT_VARIABLE <ret-var>`` + The return code from executing the module command. + +.. command:: env_module_list + + Retrieve the list of currently loaded modules: + + .. code-block:: cmake + + env_module_list(<out-var>) + + This is functionally equivalent to the ``module list`` shell command. + The result is stored in ``<out-var>`` as a properly formatted CMake + :ref:`semicolon-separated list <CMake Language Lists>` variable. + +.. command:: env_module_avail + + Retrieve the list of available modules: + + .. code-block:: cmake + + env_module_avail([<mod-prefix>] <out-var>) + + This is functionally equivalent to the ``module avail <mod-prefix>`` shell + command. The result is stored in ``<out-var>`` as a properly formatted + CMake :ref:`semicolon-separated list <CMake Language Lists>` variable. + +#]=======================================================================] + +function(env_module) + if(NOT EnvModules_COMMAND) + message(FATAL_ERROR "Failed to process module command. EnvModules_COMMAND not found") + return() + endif() + + set(options) + set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE) + set(multiValueArgs COMMAND) + cmake_parse_arguments(MOD_ARGS + "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV} + ) + if(NOT MOD_ARGS_COMMAND) + # If no explicit command argument was given, then treat the calling syntax + # as: module(cmd args...) + set(exec_cmd ${ARGV}) + else() + set(exec_cmd ${MOD_ARGS_COMMAND}) + endif() + + if(MOD_ARGS_OUTPUT_VARIABLE) + set(err_var_args ERROR_VARIABLE err_var) + endif() + + execute_process( + COMMAND mktemp -t module.cmake.XXXXXXXXXXXX + OUTPUT_VARIABLE tempfile_name + ) + string(STRIP "${tempfile_name}" tempfile_name) + + # If the $MODULESHOME/init/cmake file exists then assume that the CMake + # "shell" functionality exits + if(EXISTS "$ENV{MODULESHOME}/init/cmake") + execute_process( + COMMAND ${EnvModules_COMMAND} cmake ${exec_cmd} + OUTPUT_FILE ${tempfile_name} + ${err_var_args} + RESULT_VARIABLE ret_var + ) + + else() # fallback to the sh shell and manually convert to CMake + execute_process( + COMMAND ${EnvModules_COMMAND} sh ${exec_cmd} + OUTPUT_VARIABLE out_var + ${err_var_args} + RESULT_VARIABLE ret_var + ) + endif() + + # If we executed successfully then process and cleanup the temp file + if(ret_var EQUAL 0) + # No CMake shell so we need to process the sh output into CMake code + if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake") + file(WRITE ${tempfile_name} "") + string(REPLACE "\n" ";" out_var "${out_var}") + foreach(sh_cmd IN LISTS out_var) + if(sh_cmd MATCHES "^ *unset *([^ ]*)") + set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})") + elseif(sh_cmd MATCHES "^ *export *([^ ]*)") + set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")") + elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)") + set(var_name "${CMAKE_MATCH_1}") + set(var_value "${CMAKE_MATCH_2}") + if(var_value MATCHES "^\"(.*[^\\])\"") + # If it's in quotes, take the value as is + set(var_value "${CMAKE_MATCH_1}") + else() + # Otherwise, strip trailing spaces + string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}") + endif() + string(REPLACE "\\ " " " var_value "${var_value}") + set(cmake_cmd "set(${var_name} \"${var_value}\")") + else() + continue() + endif() + file(APPEND ${tempfile_name} "${cmake_cmd}\n") + endforeach() + endif() + + # Process the change in environment variables + include(${tempfile_name}) + file(REMOVE ${tempfile_name}) + endif() + + # Push the output back out to the calling scope + if(MOD_ARGS_OUTPUT_VARIABLE) + set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE) + endif() + if(MOD_ARGS_RESULT_VARIABLE) + set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE) + endif() +endfunction(env_module) + +#------------------------------------------------------------------------------ +function(env_module_swap out_mod in_mod) + set(options) + set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE) + set(multiValueArgs) + + cmake_parse_arguments(MOD_ARGS + "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV} + ) + + env_module(COMMAND -t swap ${out_mod} ${in_mod} + OUTPUT_VARIABLE tmp_out + RETURN_VARIABLE tmp_ret + ) + + if(MOD_ARGS_OUTPUT_VARIABLE) + set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE) + endif() + if(MOD_ARGS_RESULT_VARIABLE) + set(${MOD_ARGS_RESULT_VARIABLE} ${tmp_ret} PARENT_SCOPE) + endif() +endfunction() + +#------------------------------------------------------------------------------ +function(env_module_list out_var) + cmake_policy(SET CMP0007 NEW) + env_module(COMMAND -t list OUTPUT_VARIABLE tmp_out) + + # Convert output into a CMake list + string(REPLACE "\n" ";" ${out_var} "${tmp_out}") + + # Remove title headers and empty entries + list(REMOVE_ITEM ${out_var} "No modules loaded") + if(${out_var}) + list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$") + endif() + list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$") + + set(${out_var} ${${out_var}} PARENT_SCOPE) +endfunction() + +#------------------------------------------------------------------------------ +function(env_module_avail) + cmake_policy(SET CMP0007 NEW) + + if(ARGC EQUAL 1) + set(mod_prefix) + set(out_var ${ARGV0}) + elseif(ARGC EQUAL 2) + set(mod_prefix ${ARGV0}) + set(out_var ${ARGV1}) + else() + message(FATAL_ERROR "Usage: env_module_avail([mod_prefix] out_var)") + endif() + env_module(COMMAND -t avail ${mod_prefix} OUTPUT_VARIABLE tmp_out) + + # Convert output into a CMake list + string(REPLACE "\n" ";" tmp_out "${tmp_out}") + + set(${out_var}) + foreach(MOD IN LISTS tmp_out) + # Remove directory entries and empty values + if(MOD MATCHES "^(.*:)?$") + continue() + endif() + + # Convert default modules + if(MOD MATCHES "^(.*)/$" ) # "foo/" + list(APPEND ${out_var} ${CMAKE_MATCH_1}) + elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)" + list(APPEND ${out_var} ${CMAKE_MATCH_2}) + list(APPEND ${out_var} ${CMAKE_MATCH_1}) + else() + list(APPEND ${out_var} ${MOD}) + endif() + endforeach() + + set(${out_var} ${${out_var}} PARENT_SCOPE) +endfunction() + +#------------------------------------------------------------------------------ +# Make sure we know where the underlying module command is +find_program(EnvModules_COMMAND + NAMES lmod modulecmd + HINTS ENV MODULESHOME + PATH_SUFFIXES libexec +) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND) diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake index ad8a810..34ee873 100644 --- a/Modules/FindGLEW.cmake +++ b/Modules/FindGLEW.cmake @@ -7,64 +7,300 @@ FindGLEW Find the OpenGL Extension Wrangler Library (GLEW) -IMPORTED Targets +Input Variables +^^^^^^^^^^^^^^^ + +The following variables may be set to influence this module’s behavior: + +``GLEW_USE_STATIC_LIBS`` + to find and create :prop_tgt:`IMPORTED` target for static linkage. + +``GLEW_VERBOSE`` + to output a detailed log of this module. + +Imported Targets ^^^^^^^^^^^^^^^^ -This module defines the :prop_tgt:`IMPORTED` target ``GLEW::GLEW``, -if GLEW has been found. +This module defines the following :ref:`Imported Targets <Imported Targets>`: + + +``GLEW::glew`` + The GLEW shared library. +``GLEW::glew_s`` + The GLEW static library, if ``GLEW_USE_STATIC_LIBS`` is set to ``TRUE``. +``GLEW::GLEW`` + Duplicates either ``GLEW::glew`` or ``GLEW::glew_s`` based on availability. Result Variables ^^^^^^^^^^^^^^^^ This module defines the following variables: -:: +``GLEW_INCLUDE_DIRS`` + include directories for GLEW +``GLEW_LIBRARIES`` + libraries to link against GLEW +``GLEW_SHARED_LIBRARIES`` + libraries to link against shared GLEW +``GLEW_STATIC_LIBRARIES`` + libraries to link against static GLEW +``GLEW_FOUND`` + true if GLEW has been found and can be used +``GLEW_VERSION`` + GLEW version +``GLEW_VERSION_MAJOR`` + GLEW major version +``GLEW_VERSION_MINOR`` + GLEW minor version +``GLEW_VERSION_MICRO`` + GLEW micro version - GLEW_INCLUDE_DIRS - include directories for GLEW - GLEW_LIBRARIES - libraries to link against GLEW - GLEW_FOUND - true if GLEW has been found and can be used #]=======================================================================] +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + +find_package(GLEW CONFIG QUIET) + +if(GLEW_FOUND) + find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG) + return() +endif() + +if(GLEW_VERBOSE) + message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.") +endif() + + +function(__glew_set_find_library_suffix shared_or_static) + if(UNIX AND "${shared_or_static}" MATCHES "SHARED") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE) + elseif(UNIX AND "${shared_or_static}" MATCHES "STATIC") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE) + elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE) + elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE) + elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE) + elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a" PARENT_SCOPE) + endif() + + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: CMAKE_FIND_LIBRARY_SUFFIXES for ${shared_or_static}: ${CMAKE_FIND_LIBRARY_SUFFIXES}") + endif() +endfunction() + + +if(GLEW_VERBOSE) + if(DEFINED GLEW_USE_STATIC_LIBS) + message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS: ${GLEW_USE_STATIC_LIBS}.") + else() + message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS is undefined. Treated as FALSE.") + endif() +endif() + find_path(GLEW_INCLUDE_DIR GL/glew.h) +mark_as_advanced(GLEW_INCLUDE_DIR) -if(NOT GLEW_LIBRARY) - find_library(GLEW_LIBRARY_RELEASE NAMES GLEW glew32 glew glew32s PATH_SUFFIXES lib64 libx32) - find_library(GLEW_LIBRARY_DEBUG NAMES GLEWd glew32d glewd PATH_SUFFIXES lib64) +set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR}) - include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) - select_library_configurations(GLEW) -endif () +if(GLEW_VERBOSE) + message(STATUS "FindGLEW: GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}") + message(STATUS "FindGLEW: GLEW_INCLUDE_DIRS: ${GLEW_INCLUDE_DIRS}") +endif() + +if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64" OR "${CMAKE_GENERATOR}" MATCHES "Win64") + set(_arch "x64") +else() + set(_arch "Win32") +endif() + + +__glew_set_find_library_suffix(SHARED) + +find_library(GLEW_SHARED_LIBRARY_RELEASE + NAMES GLEW glew glew32 + PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch} + PATHS ENV GLEW_ROOT) + +find_library(GLEW_SHARED_LIBRARY_DEBUG + NAMES GLEWd glewd glew32d + PATH_SUFFIXES lib lib64 + PATHS ENV GLEW_ROOT) + + +__glew_set_find_library_suffix(STATIC) + +find_library(GLEW_STATIC_LIBRARY_RELEASE + NAMES GLEW glew glew32s + PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch} + PATHS ENV GLEW_ROOT) + +find_library(GLEW_STATIC_LIBRARY_DEBUG + NAMES GLEWds glewds glew32ds + PATH_SUFFIXES lib lib64 + PATHS ENV GLEW_ROOT) + +include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) + +select_library_configurations(GLEW_SHARED) +select_library_configurations(GLEW_STATIC) + +if(NOT GLEW_USE_STATIC_LIBS) + set(GLEW_LIBRARIES ${GLEW_SHARED_LIBRARY}) +else() + set(GLEW_LIBRARIES ${GLEW_STATIC_LIBRARY}) +endif() + + +if(GLEW_VERBOSE) + message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_RELEASE: ${GLEW_SHARED_LIBRARY_RELEASE}") + message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_RELEASE: ${GLEW_STATIC_LIBRARY_RELEASE}") + message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_DEBUG: ${GLEW_SHARED_LIBRARY_DEBUG}") + message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_DEBUG: ${GLEW_STATIC_LIBRARY_DEBUG}") + message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY: ${GLEW_SHARED_LIBRARY}") + message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY: ${GLEW_STATIC_LIBRARY}") + message(STATUS "FindGLEW: GLEW_LIBRARIES: ${GLEW_LIBRARIES}") +endif() + + +# Read version from GL/glew.h file +if(EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h") + file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" _contents REGEX "^VERSION_.+ [0-9]+") + if(_contents) + string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MAJOR "${_contents}") + string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MINOR "${_contents}") + string(REGEX REPLACE ".*VERSION_MICRO[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MICRO "${_contents}") + set(GLEW_VERSION "${GLEW_VERSION_MAJOR}.${GLEW_VERSION_MINOR}.${GLEW_VERSION_MICRO}") + endif() +endif() + +if(GLEW_VERBOSE) + message(STATUS "FindGLEW: GLEW_VERSION_MAJOR: ${GLEW_VERSION_MAJOR}") + message(STATUS "FindGLEW: GLEW_VERSION_MINOR: ${GLEW_VERSION_MINOR}") + message(STATUS "FindGLEW: GLEW_VERSION_MICRO: ${GLEW_VERSION_MICRO}") + message(STATUS "FindGLEW: GLEW_VERSION: ${GLEW_VERSION}") +endif() -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args(GLEW - REQUIRED_VARS GLEW_INCLUDE_DIR GLEW_LIBRARY) + REQUIRED_VARS GLEW_INCLUDE_DIRS GLEW_LIBRARIES + VERSION_VAR GLEW_VERSION) -if(GLEW_FOUND) - set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR}) +if(NOT GLEW_FOUND) + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: could not found GLEW library.") + endif() + return() +endif() + + +if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS) + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: Creating GLEW::glew imported target.") + endif() + + add_library(GLEW::glew UNKNOWN IMPORTED) + + set_target_properties(GLEW::glew + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + + if(GLEW_SHARED_LIBRARY_RELEASE) + set_property(TARGET GLEW::glew + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + + set_target_properties(GLEW::glew + PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}") + endif() + + if(GLEW_SHARED_LIBRARY_DEBUG) + set_property(TARGET GLEW::glew + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + + set_target_properties(GLEW::glew + PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}") + endif() - if(NOT GLEW_LIBRARIES) - set(GLEW_LIBRARIES ${GLEW_LIBRARY}) +elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS) + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: Creating GLEW::glew_s imported target.") endif() - if (NOT TARGET GLEW::GLEW) - add_library(GLEW::GLEW UNKNOWN IMPORTED) - set_target_properties(GLEW::GLEW PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + add_library(GLEW::glew_s UNKNOWN IMPORTED) - if(GLEW_LIBRARY_RELEASE) - set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_LIBRARY_RELEASE}") + set_target_properties(GLEW::glew_s + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + + if(GLEW_STATIC_LIBRARY_RELEASE) + set_property(TARGET GLEW::glew_s + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + + set_target_properties(GLEW::glew_s + PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}") + endif() + + if(GLEW_STATIC_LIBRARY_DEBUG) + set_property(TARGET GLEW::glew_s + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + + set_target_properties(GLEW::glew_s + PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}") + endif() +endif() + +if(NOT TARGET GLEW::GLEW) + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: Creating GLEW::GLEW imported target.") + endif() + + add_library(GLEW::GLEW UNKNOWN IMPORTED) + + set_target_properties(GLEW::GLEW + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + + if(TARGET GLEW::glew) + if(GLEW_SHARED_LIBRARY_RELEASE) + set_property(TARGET GLEW::GLEW + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + + set_target_properties(GLEW::GLEW + PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}") + endif() + + if(GLEW_SHARED_LIBRARY_DEBUG) + set_property(TARGET GLEW::GLEW + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + + set_target_properties(GLEW::GLEW + PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}") endif() - if(GLEW_LIBRARY_DEBUG) - set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_LIBRARY_DEBUG}") + elseif(TARGET GLEW::glew_s) + if(GLEW_STATIC_LIBRARY_RELEASE) + set_property(TARGET GLEW::GLEW + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + + set_target_properties(GLEW::GLEW + PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}") endif() - if(NOT GLEW_LIBRARY_RELEASE AND NOT GLEW_LIBRARY_DEBUG) - set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_LOCATION "${GLEW_LIBRARY}") + if(GLEW_STATIC_LIBRARY_DEBUG AND GLEW_USE_STATIC_LIBS) + set_property(TARGET GLEW::GLEW + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + + set_target_properties(GLEW::GLEW + PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}") endif() + + elseif(GLEW_VERBOSE) + message(WARNING "FindGLEW: no `GLEW::glew` or `GLEW::glew_s` target was created. Something went wrong in FindGLEW target creation.") endif() endif() - -mark_as_advanced(GLEW_INCLUDE_DIR) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 696826f..596c7f5 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -236,8 +236,10 @@ set(SRCS cmFileLockResult.h cmFilePathChecksum.cxx cmFilePathChecksum.h - cmFileTimeComparison.cxx - cmFileTimeComparison.h + cmFileTime.cxx + cmFileTime.h + cmFileTimeCache.cxx + cmFileTimeCache.h cmFortranParserImpl.cxx cmFSPermissions.cxx cmFSPermissions.h @@ -796,7 +798,7 @@ foreach(check else() set(CMake_${check} 0) endif() - set_property(SOURCE cmFileTimeComparison.cxx APPEND PROPERTY + set_property(SOURCE cmFileTime.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}}) endforeach() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index c935ef6..5af288f 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 14) -set(CMake_VERSION_PATCH 20190318) +set(CMake_VERSION_PATCH 20190319) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 07bc7e7..8ea9a83 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -5,7 +5,7 @@ #include "cmAlgorithms.h" #include "cmCTest.h" #include "cmDuration.h" -#include "cmFileTimeComparison.h" +#include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" #include "cmMakefile.h" #include "cmProcessOutput.h" @@ -503,7 +503,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml) class cmCTestBuildHandler::FragmentCompare { public: - FragmentCompare(cmFileTimeComparison* ftc) + FragmentCompare(cmFileTimeCache* ftc) : FTC(ftc) { } @@ -513,14 +513,14 @@ public: // Order files by modification time. Use lexicographic order // among files with the same time. int result; - if (this->FTC->FileTimeCompare(l, r, &result) && result != 0) { + if (this->FTC->Compare(l, r, &result) && result != 0) { return result < 0; } return l < r; } private: - cmFileTimeComparison* FTC = nullptr; + cmFileTimeCache* FTC = nullptr; }; void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml) @@ -530,7 +530,7 @@ void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml) } // Sort XML fragments in chronological order. - cmFileTimeComparison ftc; + cmFileTimeCache ftc; FragmentCompare fragmentCompare(&ftc); typedef std::set<std::string, FragmentCompare> Fragments; Fragments fragments(fragmentCompare); diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index c128b02..efadaf1 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -2,7 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmDepends.h" -#include "cmFileTimeComparison.h" +#include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -177,8 +177,7 @@ bool cmDepends::CheckDependencies( if (dependerExists) { // The dependee and depender both exist. Compare file times. int result = 0; - if ((!this->FileComparison->FileTimeCompare(depender, dependee, - &result) || + if ((!this->FileTimeCache->Compare(depender, dependee, &result) || result < 0)) { // The depender is older than the dependee. regenerate = true; @@ -195,8 +194,8 @@ bool cmDepends::CheckDependencies( // The dependee exists, but the depender doesn't. Regenerate if the // internalDepends file is older than the dependee. int result = 0; - if ((!this->FileComparison->FileTimeCompare(internalDependsFileName, - dependee, &result) || + if ((!this->FileTimeCache->Compare(internalDependsFileName, dependee, + &result) || result < 0)) { // The depends-file is older than the dependee. regenerate = true; diff --git a/Source/cmDepends.h b/Source/cmDepends.h index 20c91ca..fc6571d 100644 --- a/Source/cmDepends.h +++ b/Source/cmDepends.h @@ -12,7 +12,7 @@ #include <string> #include <vector> -class cmFileTimeComparison; +class cmFileTimeCache; class cmLocalGenerator; /** \class cmDepends @@ -72,10 +72,7 @@ public: void Clear(const std::string& file); /** Set the file comparison object */ - void SetFileComparison(cmFileTimeComparison* fc) - { - this->FileComparison = fc; - } + void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; } protected: // Write dependencies for the target file to the given stream. @@ -101,7 +98,7 @@ protected: // Flag for verbose output. bool Verbose = false; - cmFileTimeComparison* FileComparison = nullptr; + cmFileTimeCache* FileTimeCache = nullptr; std::string Language; diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index a85f5ee..58b4ebb 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -6,6 +6,7 @@ #include <utility> #include "cmAlgorithms.h" +#include "cmFileTime.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" @@ -247,6 +248,8 @@ void cmDependsC::ReadCacheFile() cmIncludeLines* cacheEntry = nullptr; bool haveFileName = false; + cmFileTime cacheFileTime; + bool const cacheFileTimeGood = cacheFileTime.Load(this->CacheFileName); while (cmSystemTools::GetLineFromStream(fin, line)) { if (line.empty()) { cacheEntry = nullptr; @@ -256,11 +259,12 @@ void cmDependsC::ReadCacheFile() // the first line after an empty line is the name of the parsed file if (!haveFileName) { haveFileName = true; - int newer = 0; - bool res = - cmSystemTools::FileTimeCompare(this->CacheFileName, line, &newer); - if (res && newer == 1) // cache is newer than the parsed file + cmFileTime fileTime; + bool const res = cacheFileTimeGood && fileTime.Load(line); + bool const newer = res && cacheFileTime.Newer(fileTime); + + if (res && newer) // cache is newer than the parsed file { cacheEntry = new cmIncludeLines; this->FileCache[line] = cacheEntry; diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx index 560d893..8913e6d 100644 --- a/Source/cmFileCopier.cxx +++ b/Source/cmFileCopier.cxx @@ -532,7 +532,7 @@ bool cmFileCopier::InstallFile(const std::string& fromFile, bool copy = true; if (!this->Always) { // If both files exist with the same time do not copy. - if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) { + if (!this->FileTimes.DifferS(fromFile, toFile)) { copy = false; } } diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h index a11c371..003b8f6 100644 --- a/Source/cmFileCopier.h +++ b/Source/cmFileCopier.h @@ -5,7 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmFileTimeComparison.h" +#include "cmFileTimeCache.h" #include "cm_sys_stat.h" #include "cmsys/RegularExpression.hxx" @@ -28,7 +28,7 @@ protected: cmMakefile* Makefile; const char* Name; bool Always; - cmFileTimeComparison FileTimes; + cmFileTimeCache FileTimes; // Whether to install a file not matching any expression. bool MatchlessFiles; diff --git a/Source/cmFileTime.cxx b/Source/cmFileTime.cxx new file mode 100644 index 0000000..253457f --- /dev/null +++ b/Source/cmFileTime.cxx @@ -0,0 +1,49 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileTime.h" + +#include <string> +#include <time.h> + +// Use a platform-specific API to get file times efficiently. +#if !defined(_WIN32) || defined(__CYGWIN__) +# include "cm_sys_stat.h" +#else +# include "cmsys/Encoding.hxx" +# include <windows.h> +#endif + +bool cmFileTime::Load(std::string const& fileName) +{ +#if !defined(_WIN32) || defined(__CYGWIN__) + // POSIX version. Use the stat function. + struct stat fst; + if (::stat(fileName.c_str(), &fst) != 0) { + return false; + } +# if CMake_STAT_HAS_ST_MTIM + // Nanosecond resolution + this->NS = fst.st_mtim.tv_sec * NsPerS + fst.st_mtim.tv_nsec; +# elif CMake_STAT_HAS_ST_MTIMESPEC + // Nanosecond resolution + this->NS = fst.st_mtimespec.tv_sec * NsPerS + fst.st_mtimespec.tv_nsec; +# else + // Second resolution + this->NS = fst.st_mtime * NsPerS; +# endif +#else + // Windows version. Get the modification time from extended file attributes. + WIN32_FILE_ATTRIBUTE_DATA fdata; + if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fileName).c_str(), + GetFileExInfoStandard, &fdata)) { + return false; + } + + // Copy the file time to the output location. + this->NS = (static_cast<NSC>(fdata.ftLastWriteTime.dwHighDateTime) << 32) | + static_cast<NSC>(fdata.ftLastWriteTime.dwLowDateTime); + // The file time resolution is 100 ns. + this->NS *= 100; +#endif + return true; +} diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h new file mode 100644 index 0000000..4c8e556 --- /dev/null +++ b/Source/cmFileTime.h @@ -0,0 +1,130 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmFileTime_h +#define cmFileTime_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +/** \class cmFileTime + * \brief Abstract file modification time with support for comparison with + * other file modification times. + */ +class cmFileTime +{ +public: + typedef long long NSC; + static constexpr NSC NsPerS = 1000000000; + + cmFileTime() = default; + ~cmFileTime() = default; + + /** + * @brief Loads the file time of fileName from the file system + * @return true on success + */ + bool Load(std::string const& fileName); + + /** + * @brief Return true if this is older than ftm + */ + bool Older(cmFileTime const& ftm) const { return (this->NS - ftm.NS) < 0; } + + /** + * @brief Return true if this is newer than ftm + */ + bool Newer(cmFileTime const& ftm) const { return (ftm.NS - this->NS) < 0; } + + /** + * @brief Return true if this is the same as ftm + */ + bool Equal(cmFileTime const& ftm) const { return this->NS == ftm.NS; } + + /** + * @brief Return true if this is not the same as ftm + */ + bool Differ(cmFileTime const& ftm) const { return this->NS != ftm.NS; } + + /** + * @brief Compare file modification times. + * @return -1, 0, +1 for this older, same, or newer than ftm. + */ + int Compare(cmFileTime const& ftm) + { + NSC const diff = this->NS - ftm.NS; + if (diff == 0) { + return 0; + } + return (diff < 0) ? -1 : 1; + } + + // -- Comparison in second resolution + + /** + * @brief Return true if this is at least a second older than ftm + */ + bool OlderS(cmFileTime const& ftm) const + { + return (ftm.NS - this->NS) >= cmFileTime::NsPerS; + } + + /** + * @brief Return true if this is at least a second newer than ftm + */ + bool NewerS(cmFileTime const& ftm) const + { + return (this->NS - ftm.NS) >= cmFileTime::NsPerS; + } + + /** + * @brief Return true if this is within the same second as ftm + */ + bool EqualS(cmFileTime const& ftm) const + { + NSC diff = this->NS - ftm.NS; + if (diff < 0) { + diff = -diff; + } + return (diff < cmFileTime::NsPerS); + } + + /** + * @brief Return true if this is older or newer than ftm by at least a second + */ + bool DifferS(cmFileTime const& ftm) const + { + NSC diff = this->NS - ftm.NS; + if (diff < 0) { + diff = -diff; + } + return (diff >= cmFileTime::NsPerS); + } + + /** + * @brief Compare file modification times. + * @return -1: this at least a second older, 0: this within the same second + * as ftm, +1: this at least a second newer than ftm. + */ + int CompareS(cmFileTime const& ftm) const + { + NSC const diff = this->NS - ftm.NS; + if (diff <= -cmFileTime::NsPerS) { + return -1; + } + if (diff >= cmFileTime::NsPerS) { + return 1; + } + return 0; + } + + /** + * @brief The file modification time in nanoseconds + */ + NSC GetNS() const { return this->NS; } + +private: + NSC NS = 0; +}; + +#endif diff --git a/Source/cmFileTimeCache.cxx b/Source/cmFileTimeCache.cxx new file mode 100644 index 0000000..1fff6a9 --- /dev/null +++ b/Source/cmFileTimeCache.cxx @@ -0,0 +1,57 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileTimeCache.h" + +#include <string> +#include <unordered_map> +#include <utility> + +cmFileTimeCache::cmFileTimeCache() = default; + +cmFileTimeCache::~cmFileTimeCache() = default; + +bool cmFileTimeCache::Load(std::string const& fileName, cmFileTime& fileTime) +{ + // Use the stored time if available. + { + auto fit = this->FileTimes.find(fileName); + if (fit != this->FileTimes.end()) { + fileTime = fit->second; + return true; + } + } + // Read file time from OS + if (!fileTime.Load(fileName)) { + return false; + } + // Store file time in cache + this->FileTimes[fileName] = fileTime; + return true; +} + +bool cmFileTimeCache::Compare(std::string const& f1, std::string const& f2, + int* result) +{ + // Get the modification time for each file. + cmFileTime ft1, ft2; + if (this->Load(f1, ft1) && this->Load(f2, ft2)) { + // Compare the two modification times. + *result = ft1.Compare(ft2); + return true; + } + // No comparison available. Default to the same time. + *result = 0; + return false; +} + +bool cmFileTimeCache::DifferS(std::string const& f1, std::string const& f2) +{ + // Get the modification time for each file. + cmFileTime ft1, ft2; + if (this->Load(f1, ft1) && this->Load(f2, ft2)) { + // Compare the two modification times. + return ft1.DifferS(ft2); + } + // No comparison available. Default to different times. + return true; +} diff --git a/Source/cmFileTimeCache.h b/Source/cmFileTimeCache.h new file mode 100644 index 0000000..a47904c --- /dev/null +++ b/Source/cmFileTimeCache.h @@ -0,0 +1,51 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmFileTimeCache_h +#define cmFileTimeCache_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmFileTime.h" +#include <string> +#include <unordered_map> + +/** \class cmFileTimeCache + * \brief Caches file modification times in an internal map for fast lookups. + */ +class cmFileTimeCache +{ +public: + cmFileTimeCache(); + ~cmFileTimeCache(); + + cmFileTimeCache(const cmFileTimeCache&) = delete; + cmFileTimeCache& operator=(const cmFileTimeCache&) = delete; + + /** + * @brief Loads the file time from the cache or the file system. + * @return true on success + */ + bool Load(std::string const& fileName, cmFileTime& fileTime); + + /** + * @brief Compare file modification times. + * @return true for successful comparison and false for error. + * + * When true is returned, result has -1, 0, +1 for + * f1 older, same, or newer than f2. + */ + bool Compare(std::string const& f1, std::string const& f2, int* result); + + /** + * @brief Compare file modification times. + * @return true unless both files exist and have modification times less + * than 1 second apart. + */ + bool DifferS(std::string const& f1, std::string const& f2); + +private: + typedef std::unordered_map<std::string, cmFileTime> FileTimeMap; + FileTimeMap FileTimes; +}; + +#endif diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx deleted file mode 100644 index 8b3911e..0000000 --- a/Source/cmFileTimeComparison.cxx +++ /dev/null @@ -1,233 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmFileTimeComparison.h" - -#include <string> -#include <time.h> -#include <unordered_map> -#include <utility> - -// Use a platform-specific API to get file times efficiently. -#if !defined(_WIN32) || defined(__CYGWIN__) -# include "cm_sys_stat.h" -# define cmFileTimeComparison_Type struct stat -#else -# include "cmsys/Encoding.hxx" -# include <windows.h> -# define cmFileTimeComparison_Type FILETIME -#endif - -class cmFileTimeComparisonInternal -{ -public: - // Internal comparison method. - inline bool FileTimeCompare(const std::string& f1, const std::string& f2, - int* result); - - bool FileTimesDiffer(const std::string& f1, const std::string& f2); - -private: - typedef std::unordered_map<std::string, cmFileTimeComparison_Type> - FileStatsMap; - FileStatsMap Files; - - // Internal methods to lookup and compare modification times. - inline bool Stat(const std::string& fname, cmFileTimeComparison_Type* st); - inline int Compare(cmFileTimeComparison_Type* st1, - cmFileTimeComparison_Type* st2); - inline bool TimesDiffer(cmFileTimeComparison_Type* st1, - cmFileTimeComparison_Type* st2); -}; - -bool cmFileTimeComparisonInternal::Stat(const std::string& fname, - cmFileTimeComparison_Type* st) -{ - // Use the stored time if available. - cmFileTimeComparisonInternal::FileStatsMap::iterator fit = - this->Files.find(fname); - if (fit != this->Files.end()) { - *st = fit->second; - return true; - } - -#if !defined(_WIN32) || defined(__CYGWIN__) - // POSIX version. Use the stat function. - int res = ::stat(fname.c_str(), st); - if (res != 0) { - return false; - } -#else - // Windows version. Get the modification time from extended file - // attributes. - WIN32_FILE_ATTRIBUTE_DATA fdata; - if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fname).c_str(), - GetFileExInfoStandard, &fdata)) { - return false; - } - - // Copy the file time to the output location. - *st = fdata.ftLastWriteTime; -#endif - - // Store the time for future use. - this->Files[fname] = *st; - return true; -} - -cmFileTimeComparison::cmFileTimeComparison() -{ - this->Internals = new cmFileTimeComparisonInternal; -} - -cmFileTimeComparison::~cmFileTimeComparison() -{ - delete this->Internals; -} - -bool cmFileTimeComparison::FileTimeCompare(const std::string& f1, - const std::string& f2, int* result) -{ - return this->Internals->FileTimeCompare(f1, f2, result); -} - -bool cmFileTimeComparison::FileTimesDiffer(const std::string& f1, - const std::string& f2) -{ - return this->Internals->FileTimesDiffer(f1, f2); -} - -int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, - cmFileTimeComparison_Type* s2) -{ -#if !defined(_WIN32) || defined(__CYGWIN__) -# if CMake_STAT_HAS_ST_MTIM - // Compare using nanosecond resolution. - if (s1->st_mtim.tv_sec < s2->st_mtim.tv_sec) { - return -1; - } - if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) { - return 1; - } - if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) { - return -1; - } - if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) { - return 1; - } -# elif CMake_STAT_HAS_ST_MTIMESPEC - // Compare using nanosecond resolution. - if (s1->st_mtimespec.tv_sec < s2->st_mtimespec.tv_sec) { - return -1; - } - if (s1->st_mtimespec.tv_sec > s2->st_mtimespec.tv_sec) { - return 1; - } - if (s1->st_mtimespec.tv_nsec < s2->st_mtimespec.tv_nsec) { - return -1; - } - if (s1->st_mtimespec.tv_nsec > s2->st_mtimespec.tv_nsec) { - return 1; - } -# else - // Compare using 1 second resolution. - if (s1->st_mtime < s2->st_mtime) { - return -1; - } - if (s1->st_mtime > s2->st_mtime) { - return 1; - } -# endif - // Files have the same time. - return 0; -#else - // Compare using system-provided function. - return (int)CompareFileTime(s1, s2); -#endif -} - -bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1, - cmFileTimeComparison_Type* s2) -{ -#if !defined(_WIN32) || defined(__CYGWIN__) -# if CMake_STAT_HAS_ST_MTIM - // Times are integers in units of 1ns. - long long bil = 1000000000; - long long t1 = s1->st_mtim.tv_sec * bil + s1->st_mtim.tv_nsec; - long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec; - if (t1 < t2) { - return (t2 - t1) >= bil; - } - if (t2 < t1) { - return (t1 - t2) >= bil; - } - return false; -# elif CMake_STAT_HAS_ST_MTIMESPEC - // Times are integers in units of 1ns. - long long bil = 1000000000; - long long t1 = s1->st_mtimespec.tv_sec * bil + s1->st_mtimespec.tv_nsec; - long long t2 = s2->st_mtimespec.tv_sec * bil + s2->st_mtimespec.tv_nsec; - if (t1 < t2) { - return (t2 - t1) >= bil; - } - if (t2 < t1) { - return (t1 - t2) >= bil; - } - return false; -# else - // Times are integers in units of 1s. - if (s1->st_mtime < s2->st_mtime) { - return (s2->st_mtime - s1->st_mtime) >= 1; - } - if (s1->st_mtime > s2->st_mtime) { - return (s1->st_mtime - s2->st_mtime) >= 1; - } - return false; -# endif -#else - // Times are integers in units of 100ns. - LARGE_INTEGER t1; - LARGE_INTEGER t2; - t1.LowPart = s1->dwLowDateTime; - t1.HighPart = s1->dwHighDateTime; - t2.LowPart = s2->dwLowDateTime; - t2.HighPart = s2->dwHighDateTime; - if (t1.QuadPart < t2.QuadPart) { - return (t2.QuadPart - t1.QuadPart) >= static_cast<LONGLONG>(10000000); - } else if (t2.QuadPart < t1.QuadPart) { - return (t1.QuadPart - t2.QuadPart) >= static_cast<LONGLONG>(10000000); - } else { - return false; - } -#endif -} - -bool cmFileTimeComparisonInternal::FileTimeCompare(const std::string& f1, - const std::string& f2, - int* result) -{ - // Get the modification time for each file. - cmFileTimeComparison_Type s1; - cmFileTimeComparison_Type s2; - if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) { - // Compare the two modification times. - *result = this->Compare(&s1, &s2); - return true; - } - // No comparison available. Default to the same time. - *result = 0; - return false; -} - -bool cmFileTimeComparisonInternal::FileTimesDiffer(const std::string& f1, - const std::string& f2) -{ - // Get the modification time for each file. - cmFileTimeComparison_Type s1; - cmFileTimeComparison_Type s2; - if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) { - // Compare the two modification times. - return this->TimesDiffer(&s1, &s2); - } - // No comparison available. Default to different times. - return true; -} diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h deleted file mode 100644 index b4e4eb3..0000000 --- a/Source/cmFileTimeComparison.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmFileTimeComparison_h -#define cmFileTimeComparison_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <string> - -class cmFileTimeComparisonInternal; - -/** \class cmFileTimeComparison - * \brief Helper class for comparing file modification times. - * - * Compare file modification times or test if file modification times differ. - */ -class cmFileTimeComparison -{ -public: - cmFileTimeComparison(); - ~cmFileTimeComparison(); - - cmFileTimeComparison(const cmFileTimeComparison&) = delete; - cmFileTimeComparison& operator=(const cmFileTimeComparison&) = delete; - - /** - * Compare file modification times. - * Return true for successful comparison and false for error. - * When true is returned, result has -1, 0, +1 for - * f1 older, same, or newer than f2. - */ - bool FileTimeCompare(const std::string& f1, const std::string& f2, - int* result); - - /** - * Compare file modification times. Return true unless both files - * exist and have modification times less than 1 second apart. - */ - bool FileTimesDiffer(const std::string& f1, const std::string& f2); - -protected: - cmFileTimeComparisonInternal* Internals; -}; - -#endif diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index d1093be..f3d5a94 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -12,7 +12,7 @@ #include "cmAlgorithms.h" #include "cmCustomCommandGenerator.h" -#include "cmFileTimeComparison.h" +#include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -1273,12 +1273,11 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( // happen when a new source file is added and CMake regenerates the // project but no other sources were touched. bool needRescanDependInfo = false; - cmFileTimeComparison* ftc = - this->GlobalGenerator->GetCMakeInstance()->GetFileComparison(); + cmFileTimeCache* ftc = + this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache(); { int result; - if (!ftc->FileTimeCompare(internalDependFile, tgtInfo, &result) || - result < 0) { + if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) { if (verbose) { std::ostringstream msg; msg << "Dependee \"" << tgtInfo << "\" is newer than depender \"" @@ -1297,7 +1296,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( dirInfoFile += "/CMakeFiles"; dirInfoFile += "/CMakeDirectoryInformation.cmake"; int result; - if (!ftc->FileTimeCompare(internalDependFile, dirInfoFile, &result) || + if (!ftc->Compare(internalDependFile, dirInfoFile, &result) || result < 0) { if (verbose) { std::ostringstream msg; @@ -1318,7 +1317,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( if (!needRescanDirInfo) { cmDependsC checker; checker.SetVerbose(verbose); - checker.SetFileComparison(ftc); + checker.SetFileTimeCache(ftc); // cmDependsC::Check() fills the vector validDependencies() with the // dependencies for those files where they are still valid, i.e. neither // the files themselves nor any files they depend on have changed. @@ -1439,8 +1438,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( if (scanner) { scanner->SetLocalGenerator(this); - scanner->SetFileComparison( - this->GlobalGenerator->GetCMakeInstance()->GetFileComparison()); + scanner->SetFileTimeCache( + this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache()); scanner->SetLanguage(lang); scanner->SetTargetDirectory(targetDir); scanner->Write(ruleFileStream, internalRuleFileStream); diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c index 52af4a6..d41d097 100644 --- a/Source/cm_utf8.c +++ b/Source/cm_utf8.c @@ -71,6 +71,16 @@ const char* cm_utf8_decode_character(const char* first, const char* last, return 0; } + /* UTF-16 surrogate halves. */ + if (0xD800 <= uc && uc <= 0xDFFF) { + return 0; + } + + /* Invalid codepoints. */ + if (0x10FFFF < uc) { + return 0; + } + *pc = uc; return first; } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 08e284e..e1b775e 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -9,7 +9,7 @@ #include "cmDocumentationFormatter.h" #include "cmDuration.h" #include "cmExternalMakefileProjectGenerator.h" -#include "cmFileTimeComparison.h" +#include "cmFileTimeCache.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" @@ -138,7 +138,7 @@ cmake::cmake(Role role, cmState::Mode mode) this->DebugOutput = false; this->DebugTryCompile = false; this->ClearBuildSystem = false; - this->FileComparison = new cmFileTimeComparison; + this->FileTimeCache = new cmFileTimeCache; this->State = new cmState; this->State->SetMode(mode); @@ -222,7 +222,7 @@ cmake::~cmake() #ifdef CMAKE_BUILD_WITH_CMAKE delete this->VariableWatch; #endif - delete this->FileComparison; + delete this->FileTimeCache; } #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -2139,7 +2139,7 @@ int cmake::CheckBuildSystem() std::string dep_newest = *dep++; for (; dep != depends.end(); ++dep) { int result = 0; - if (this->FileComparison->FileTimeCompare(dep_newest, *dep, &result)) { + if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) { if (result < 0) { dep_newest = *dep; } @@ -2158,7 +2158,7 @@ int cmake::CheckBuildSystem() std::string out_oldest = *out++; for (; out != outputs.end(); ++out) { int result = 0; - if (this->FileComparison->FileTimeCompare(out_oldest, *out, &result)) { + if (this->FileTimeCache->Compare(out_oldest, *out, &result)) { if (result > 0) { out_oldest = *out; } @@ -2175,8 +2175,7 @@ int cmake::CheckBuildSystem() // If any output is older than any dependency then rerun. { int result = 0; - if (!this->FileComparison->FileTimeCompare(out_oldest, dep_newest, - &result) || + if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) || result < 0) { if (verbose) { std::ostringstream msg; @@ -2431,20 +2430,22 @@ static bool cmakeCheckStampFile(const std::string& stampName) } // Compare the stamp dependencies against the dependency file itself. - cmFileTimeComparison ftc; - std::string dep; - while (cmSystemTools::GetLineFromStream(fin, dep)) { - int result; - if (!dep.empty() && dep[0] != '#' && - (!ftc.FileTimeCompare(stampDepends, dep, &result) || result < 0)) { - // The stamp depends file is older than this dependency. The - // build system is really out of date. - std::cout << "CMake is re-running because " << stampName - << " is out-of-date.\n"; - std::cout << " the file '" << dep << "'\n"; - std::cout << " is newer than '" << stampDepends << "'\n"; - std::cout << " result='" << result << "'\n"; - return false; + { + cmFileTimeCache ftc; + std::string dep; + while (cmSystemTools::GetLineFromStream(fin, dep)) { + int result; + if (!dep.empty() && dep[0] != '#' && + (!ftc.Compare(stampDepends, dep, &result) || result < 0)) { + // The stamp depends file is older than this dependency. The + // build system is really out of date. + std::cout << "CMake is re-running because " << stampName + << " is out-of-date.\n"; + std::cout << " the file '" << dep << "'\n"; + std::cout << " is newer than '" << stampDepends << "'\n"; + std::cout << " result='" << result << "'\n"; + return false; + } } } diff --git a/Source/cmake.h b/Source/cmake.h index 1ffeabc..f8a2319 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -26,7 +26,7 @@ class cmExternalMakefileProjectGeneratorFactory; class cmFileAPI; -class cmFileTimeComparison; +class cmFileTimeCache; class cmGlobalGenerator; class cmGlobalGeneratorFactory; class cmMakefile; @@ -329,7 +329,7 @@ public: /** * Get the file comparison class */ - cmFileTimeComparison* GetFileComparison() { return this->FileComparison; } + cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; } // Do we want debug output during the cmake run. bool GetDebugOutput() { return this->DebugOutput; } @@ -509,7 +509,7 @@ private: std::unordered_set<std::string> HeaderFileExtensionsSet; bool ClearBuildSystem; bool DebugTryCompile; - cmFileTimeComparison* FileComparison; + cmFileTimeCache* FileTimeCache; std::string GraphVizFile; InstalledFilesMap InstalledFiles; diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx index c99c46d..7f52c82 100644 --- a/Tests/CMakeLib/testUTF8.cxx +++ b/Tests/CMakeLib/testUTF8.cxx @@ -21,17 +21,29 @@ struct test_utf8_entry }; static test_utf8_entry const good_entry[] = { - { 1, "\x20\x00\x00\x00", 0x0020 }, /* Space. */ - { 2, "\xC2\xA9\x00\x00", 0x00A9 }, /* Copyright. */ - { 3, "\xE2\x80\x98\x00", 0x2018 }, /* Open-single-quote. */ - { 3, "\xE2\x80\x99\x00", 0x2019 }, /* Close-single-quote. */ - { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629. */ + { 1, "\x20\x00\x00\x00", 0x0020 }, /* Space. */ + { 2, "\xC2\xA9\x00\x00", 0x00A9 }, /* Copyright. */ + { 3, "\xE2\x80\x98\x00", 0x2018 }, /* Open-single-quote. */ + { 3, "\xE2\x80\x99\x00", 0x2019 }, /* Close-single-quote. */ + { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629. */ + { 3, "\xED\x80\x80\x00", 0xD000 }, /* Valid 0xED prefixed codepoint. */ + { 4, "\xF4\x8F\xBF\xBF", 0x10FFFF }, /* Highest valid RFC codepoint. */ { 0, { 0, 0, 0, 0, 0 }, 0 } }; static test_utf8_char const bad_chars[] = { - "\x80\x00\x00\x00", "\xC0\x00\x00\x00", "\xE0\x00\x00\x00", - "\xE0\x80\x80\x00", "\xF0\x80\x80\x80", { 0, 0, 0, 0, 0 } + "\x80\x00\x00\x00", /* Leading continuation byte. */ + "\xC0\x80\x00\x00", /* Overlong encoding. */ + "\xC1\x80\x00\x00", /* Overlong encoding. */ + "\xC2\x00\x00\x00", /* Missing continuation byte. */ + "\xE0\x00\x00\x00", /* Missing continuation bytes. */ + "\xE0\x80\x80\x00", /* Overlong encoding. */ + "\xF0\x80\x80\x80", /* Overlong encoding. */ + "\xED\xA0\x80\x00", /* UTF-16 surrogate half. */ + "\xED\xBF\xBF\x00", /* UTF-16 surrogate half. */ + "\xF4\x90\x80\x80", /* Lowest out-of-range codepoint. */ + "\xF5\x80\x80\x80", /* Prefix forces out-of-range codepoints. */ + { 0, 0, 0, 0, 0 } }; static void report_good(bool passed, test_utf8_char const c) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 01f8226..d793adf 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1421,6 +1421,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindDoxygen) endif() + if(CMake_TEST_FindEnvModules) + add_subdirectory(FindEnvModules) + endif() + if(CMake_TEST_FindEXPAT) add_subdirectory(FindEXPAT) endif() @@ -1445,6 +1449,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindGit) endif() + if(CMake_TEST_FindGLEW) + add_subdirectory(FindGLEW) + endif() + if(CMake_TEST_FindGSL) add_subdirectory(FindGSL) endif() diff --git a/Tests/FindEnvModules/CMakeLists.txt b/Tests/FindEnvModules/CMakeLists.txt new file mode 100644 index 0000000..95b7d1d --- /dev/null +++ b/Tests/FindEnvModules/CMakeLists.txt @@ -0,0 +1,3 @@ +add_test(FindEnvModules.Test ${CMAKE_CMAKE_COMMAND} + -P ${CMAKE_CURRENT_LIST_DIR}/EnvModules.cmake +) diff --git a/Tests/FindEnvModules/EnvModules.cmake b/Tests/FindEnvModules/EnvModules.cmake new file mode 100644 index 0000000..0c81bf2 --- /dev/null +++ b/Tests/FindEnvModules/EnvModules.cmake @@ -0,0 +1,35 @@ +find_package(EnvModules REQUIRED) +message("module purge") +env_module(COMMAND purge RESULT_VARIABLE ret_var) +if(NOT ret_var EQUAL 0) + message(FATAL_ERROR "module(purge) returned ${ret_var}") +endif() + +message("module avail") +env_module_avail(avail_mods) +foreach(mod IN LISTS avail_mods) + message(" ${mod}") +endforeach() + +if(avail_mods) + list(GET avail_mods 0 mod0) + message("module load ${mod0}") + env_module(load ${mod0}) + + message("module list") + env_module_list(loaded_mods) + foreach(mod IN LISTS loaded_mods) + message(" ${mod}") + endforeach() + + list(LENGTH loaded_mods num_loaded_mods) + message("Number of modules loaded: ${num_loaded_mods}") + if(NOT num_loaded_mods EQUAL 1) + message(FATAL_ERROR "Exactly 1 module should be loaded. Found ${num_loaded_mods}") + endif() + + list(GET loaded_mods 0 mod0_actual) + if(NOT (mod0_actual MATCHES "^${mod0}")) + message(FATAL_ERROR "Loaded module does not match ${mod0}. Actual: ${mod0_actual}") + endif() +endif() diff --git a/Tests/FindGLEW/CMakeLists.txt b/Tests/FindGLEW/CMakeLists.txt new file mode 100644 index 0000000..ff42bce --- /dev/null +++ b/Tests/FindGLEW/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindGLEW.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindGLEW/Test" + "${CMake_BINARY_DIR}/Tests/FindGLEW/Test" + ${build_generator_args} + --build-project TestFindGLEW + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindGLEW/Test/CMakeLists.txt b/Tests/FindGLEW/Test/CMakeLists.txt new file mode 100644 index 0000000..954ee10 --- /dev/null +++ b/Tests/FindGLEW/Test/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.1) +project(TestFindGLEW LANGUAGES CXX) +include(CTest) + +find_package(GLEW REQUIRED) + +add_executable(test_glew_shared_tgt main.cpp) +target_link_libraries(test_glew_shared_tgt GLEW::GLEW) +add_test(NAME test_glew_shared_tgt COMMAND test_glew_shared_tgt) + +add_executable(test_glew_generic_tgt main.cpp) +target_link_libraries(test_glew_generic_tgt GLEW::glew) +add_test(NAME test_glew_generic_tgt COMMAND test_glew_generic_tgt) + +add_executable(test_glew_var main.cpp) +target_include_directories(test_glew_var PRIVATE ${GLEW_INCLUDE_DIRS}) +target_link_libraries(test_glew_var PRIVATE ${GLEW_LIBRARIES}) +add_test(NAME test_glew_var COMMAND test_glew_var) diff --git a/Tests/FindGLEW/Test/main.cpp b/Tests/FindGLEW/Test/main.cpp new file mode 100644 index 0000000..4a108ad --- /dev/null +++ b/Tests/FindGLEW/Test/main.cpp @@ -0,0 +1,8 @@ +#include <GL/glew.h> + +int main() +{ + GLenum init_return = glewInit(); + + return (init_return == GLEW_OK); +} diff --git a/Utilities/cmzstd/CMakeLists.txt b/Utilities/cmzstd/CMakeLists.txt index b1399bd..8ed04d8 100644 --- a/Utilities/cmzstd/CMakeLists.txt +++ b/Utilities/cmzstd/CMakeLists.txt @@ -41,4 +41,7 @@ add_library(cmzstd STATIC lib/dictBuilder/zdict.c ) +# BMI2 instructions are not supported in older environments. +set_property(TARGET cmzstd PROPERTY COMPILE_DEFINITIONS DYNAMIC_BMI2=0) + install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmzstd) @@ -304,7 +304,8 @@ CMAKE_CXX_SOURCES="\ cmFileCommand \ cmFileCopier \ cmFileInstaller \ - cmFileTimeComparison \ + cmFileTime \ + cmFileTimeCache \ cmFindBase \ cmFindCommon \ cmFindFileCommand \ |