1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5CMakeVerifyManifest
6-------------------
7
8
9
10CMakeVerifyManifest.cmake
11
12This script is used to verify that embedded manifests and side by side
13manifests for a project match.  To run this script, cd to a directory
14and run the script with cmake -P.  On the command line you can pass in
15versions that are OK even if not found in the .manifest files.  For
16example, cmake -Dallow_versions=8.0.50608.0
17-PCmakeVerifyManifest.cmake could be used to allow an embedded manifest
18of 8.0.50608.0 to be used in a project even if that version was not
19found in the .manifest file.
20#]=======================================================================]
21
22# This script first recursively globs *.manifest files from
23# the current directory.  Then globs *.exe and *.dll.  Each
24# .exe and .dll is scanned for embedded manifests and the versions
25# of CRT are compared to those found in the .manifest files
26# from the first glob.
27
28# crt_version:
29# function to extract the CRT version from a file
30# this can be passed a .exe, .dll, or a .manifest file
31# it will put the list of versions found into the variable
32# specified by list_var
33function(crt_version file list_var)
34  file(STRINGS "${file}" strings REGEX "Microsoft.VC...CRT" NEWLINE_CONSUME)
35  foreach(s ${strings})
36    set(has_match 1)
37    string(REGEX
38      REPLACE ".*<assembly.*\"Microsoft.VC...CRT\".*version=\"([^\"]*)\".*</assembly>.*$" "\\1"
39      version "${s}")
40    if(NOT "${version}" STREQUAL "")
41      list(APPEND version_list ${version})
42    else()
43      message(FATAL_ERROR "Parse error could not find version in [${s}]")
44    endif()
45  endforeach()
46  if(NOT DEFINED has_match)
47    message("Information: no embedded manifest in: ${file}")
48    return()
49  endif()
50  list(APPEND version_list ${${list_var}})
51  list(REMOVE_DUPLICATES version_list)
52  if(version_list)
53    set(${list_var} ${version_list} PARENT_SCOPE)
54  endif()
55endfunction()
56set(fatal_error FALSE)
57
58# check_version:
59#
60# test a file against the shipped manifest versions
61# for a directory
62function(check_version file manifest_versions)
63  set(manifest_versions ${manifest_versions} ${allow_versions})
64  # collect versions for a given file
65  crt_version(${file} file_versions)
66  # see if the versions
67  foreach(ver ${file_versions})
68    list(FIND manifest_versions "${ver}" found_version)
69    if("${found_version}" EQUAL -1)
70      message("ERROR: ${file} uses ${ver} not found in shipped manifests:[${manifest_versions}].")
71      set(fatal_error TRUE PARENT_SCOPE)
72    endif()
73  endforeach()
74  list(LENGTH file_versions len)
75  if(${len} GREATER 1)
76    message("WARNING: found more than one version of MICROSOFT.VC80.CRT referenced in ${file}: [${file_versions}]")
77  endif()
78endfunction()
79
80# collect up the versions of CRT that are shipped
81# in .manifest files
82set(manifest_version_list )
83file(GLOB_RECURSE manifest_files "*.manifest")
84foreach(f ${manifest_files})
85  crt_version("${f}" manifest_version_list)
86endforeach()
87list(LENGTH manifest_version_list LEN)
88if(LEN EQUAL 0)
89  message(FATAL_ERROR "No .manifest files found, no version check can be done.")
90endif()
91message("Versions found in ${manifest_files}: ${manifest_version_list}")
92if(DEFINED allow_versions)
93  message("Extra versions allowed: ${allow_versions}")
94endif()
95
96# now find all .exe and .dll files
97# and call check_version on each of them
98file(GLOB_RECURSE exe_files "*.exe")
99file(GLOB_RECURSE dll_files "*.dll")
100set(exe_files ${exe_files} ${dll_files})
101foreach(f ${exe_files})
102  check_version(${f} "${manifest_version_list}")
103endforeach()
104
105# report a fatal error if there were any so that cmake will return
106# a non zero value
107if(fatal_error)
108  message(FATAL_ERROR "This distribution embeds dll "
109    " versions that it does not ship, and may not work on other machines.")
110endif()
111