File: CMakeVerifyManifest.cmake

package info (click to toggle)
cmake 4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 152,348 kB
  • sloc: ansic: 403,894; cpp: 303,807; sh: 4,097; python: 3,582; yacc: 3,106; lex: 1,279; f90: 538; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 239; objc: 215; perl: 213; xml: 198; makefile: 108; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (142 lines) | stat: -rw-r--r-- 4,795 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
CMakeVerifyManifest
-------------------

This module is intended to be used in command-line mode using the
:ref:`cmake -P <Script Processing Mode>` to verify that embedded manifests
and side-by-side manifests for a project match.

Load this module in a CMake script with:

.. code-block:: cmake

  include(CMakeVerifyManifest)

This module first recursively globs ``*.manifest`` files from
the current source directory and creates a list of allowed versions.

Next, the script globs all ``*.exe`` and ``*.dll`` files.  Each
``.exe`` and ``.dll`` file is scanned for embedded manifests and
the versions of CRT are checked to be in the list of allowed
versions.

Input Variables
^^^^^^^^^^^^^^^

This module accepts the following variables:

``allow_versions``
  Additional versions can be passed by setting the ``allow_versions``
  variable from the invocation command.  This enables using additional
  embedded manifest versions in a project, even if that version was not
  found in a ``.manifest`` file.

Examples
^^^^^^^^

To use this module in the project, create a local command-line script (for
example, in the project's subdirectory ``cmake/scripts``) and include the
module:

.. code-block:: cmake
  :caption: ``cmake/scripts/verify-manifest.cmake``

  include(CMakeVerifyManifest)

Then run the local script in command-line and, for example, specify
additional embedded manifest of ``8.0.50608.0`` to be used in a project:

.. code-block:: shell

  cmake -Dallow_versions=8.0.50608.0 -Pcmake/scripts/verify-manifest.cmake
#]=======================================================================]

# crt_version:
# function to extract the CRT version from a file
# this can be passed a .exe, .dll, or a .manifest file
# it will put the list of versions found into the variable
# specified by list_var
function(crt_version file list_var)
  cmake_policy(PUSH)
  cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
  file(STRINGS "${file}" strings REGEX "Microsoft.VC...CRT" NEWLINE_CONSUME)
  cmake_policy(POP)
  foreach(s ${strings})
    set(has_match 1)
    string(REGEX
      REPLACE ".*<assembly.*\"Microsoft.VC...CRT\".*version=\"([^\"]*)\".*</assembly>.*$" "\\1"
      version "${s}")
    if(NOT "${version}" STREQUAL "")
      list(APPEND version_list ${version})
    else()
      message(FATAL_ERROR "Parse error could not find version in [${s}]")
    endif()
  endforeach()
  if(NOT DEFINED has_match)
    message("Information: no embedded manifest in: ${file}")
    return()
  endif()
  list(APPEND version_list ${${list_var}})
  list(REMOVE_DUPLICATES version_list)
  if(version_list)
    set(${list_var} ${version_list} PARENT_SCOPE)
  endif()
endfunction()
set(fatal_error FALSE)

# check_version:
#
# test a file against the shipped manifest versions
# for a directory
function(check_version file manifest_versions)
  set(manifest_versions ${manifest_versions} ${allow_versions})
  # collect versions for a given file
  crt_version(${file} file_versions)
  # see if the versions
  foreach(ver ${file_versions})
    list(FIND manifest_versions "${ver}" found_version)
    if("${found_version}" EQUAL -1)
      message("ERROR: ${file} uses ${ver} not found in shipped manifests:[${manifest_versions}].")
      set(fatal_error TRUE PARENT_SCOPE)
    endif()
  endforeach()
  list(LENGTH file_versions len)
  if(${len} GREATER 1)
    message("WARNING: found more than one version of MICROSOFT.VC80.CRT referenced in ${file}: [${file_versions}]")
  endif()
endfunction()

# collect up the versions of CRT that are shipped
# in .manifest files
set(manifest_version_list )
file(GLOB_RECURSE manifest_files "*.manifest")
foreach(f ${manifest_files})
  crt_version("${f}" manifest_version_list)
endforeach()
list(LENGTH manifest_version_list LEN)
if(LEN EQUAL 0)
  message(FATAL_ERROR "No .manifest files found, no version check can be done.")
endif()
message("Versions found in ${manifest_files}: ${manifest_version_list}")
if(DEFINED allow_versions)
  message("Extra versions allowed: ${allow_versions}")
endif()

# now find all .exe and .dll files
# and call check_version on each of them
file(GLOB_RECURSE exe_files "*.exe")
file(GLOB_RECURSE dll_files "*.dll")
set(exe_files ${exe_files} ${dll_files})
foreach(f ${exe_files})
  check_version(${f} "${manifest_version_list}")
endforeach()

# report a fatal error if there were any so that cmake will return
# a non zero value
if(fatal_error)
  message(FATAL_ERROR "This distribution embeds dll "
    " versions that it does not ship, and may not work on other machines.")
endif()